Please, have a look at the previous (bad) implementation and the review here.
After reading the suggested article at HowTo: Export C++ classes from a DLL, I have decided to use a plain C function approach. However, I want to use C++ code inside the DLL later. Anyway, the exported one will be a plain C function with the const char *
argument.
In my earlier attempt, I tried to pass reference to the vector<string>
argument, which is not possible or at least safe. The vector of strings was the result of parsing the line from a text file. Now, I am passing the line itself, and the parsing is done inside the DLL. The code of the caller and the type of the called function look like this:
typedef __declspec(dllimport) int (__cdecl *CONVERTPROC)(const char *);
int call_convert_from_dll(const std::string & dllname, const char * line)
{
HINSTANCE hinstLib;
CONVERTPROC convert;
BOOL fRunTimeLinkSuccess = FALSE;
// Get a handle to the DLL module.
hinstLib = LoadLibrary(dllname.c_str());
// If the handle is valid, try to get the function address.
if (hinstLib != nullptr)
{
convert = (CONVERTPROC)GetProcAddress(hinstLib, "convert");
// If the function address is valid, call the function.
if (convert != nullptr)
{
fRunTimeLinkSuccess = TRUE;
(convert)(line);
}
else {
DWORD err = GetLastError();
if (err == ERROR_PROC_NOT_FOUND)
cerr << "procedure convert() was not found" << endl;
else
cerr << "runtime link failed: " << err << endl;
}
// Free the DLL module.
FreeLibrary(hinstLib);
}
// If unable to call the DLL function, use an alternative.
if (!fRunTimeLinkSuccess) {
cerr << "Failed when using '" << dllname << "' library." << endl;
return 1;
}
return 0;
}
The name of the called function (from the DLL) is passed as a string. Because of that, the extern "C"
must be used to avoid identifier mangling.
The mentioned article also says that no exception should cross the boundary of the DLL module (if it is not the special case when both parts are written in C++ and compiled by the same version of the compiler). Because of that, the try/catch
wraps the body of the called function. Any exception is transformed to the error code equal to 1:
extern "C" { // we need to export the C interface
__declspec(dllexport) int __cdecl convert(const char * line)
{
int err = 0;
try {
cout << "my.dll: '" << line << "'" << endl;
vector<string> vs;
StringTok(vs, line, " \t\n");
err = xmain(vs);
}
catch (...) {
return 1;
}
return err;
}
} // extern "C"
Can you see any other flaw in the code?