Reputation: 63
I just am getting confused about passing the parameter to function in C++ over different projects.
I have two different solutions, of which one is a DLL project and another is Console project. Within the first project I have a piece of code as follows:
class __declspec(dllexport) FormatLog
{
public:
void __cdecl ParseFormat(LPCWSTR);
};
The rest of codes are not important herein, whereas in the second project I have the header file consisting of the following code:
class FormatImpl
{
public:
typedef void (__cdecl * FORMAT) (LPCWSTR);
HINSTANCE hModule;
FORMAT Format;
FormatImpl()
{
hModule = LoadLibrary(L"FormatLog.dll");
if (hModule != NULL)
{
Format = (FORMAT) GetProcAddress(hModule, "?ParseFormat@FormatLog@@XXXXXXXX@X");
}
}
~FormatImpl()
{
if (hModule != NULL)
{
FreeLibrary(hModule);
}
}
};
When I was calling this from the main function using the following code:
int main(int argc, char* argv[])
{
FormatImpl format;
format.Format(L"%t %m %i %l");
return 0;
}
the parameter became invalid in function void __cdecl ParseFormat(LPCWSTR format);
as <Bad Ptr>
while inspecting through the Visual Studio 2010.
My question is, if I use GetProcAddress
or LoadLibrary
to call a .dll file invoking any method, shouldn't I thereby be legitimate to pass any parameter apart from int, double, long or so on to the requested method?
Upvotes: 0
Views: 1036
Reputation: 148890
You have a major problem in your code: ParseFormat
is not a function taking a LPWSTR and returning void but an instance method of class FormatLog
. The difference is that for an instance method, you have a hidden this
parameter.
If you have control on first project, the simplest way IMHO is to just use a static method to get rid of the hidden parameter:
class __declspec(dllexport) FormatLog
{
public:
static void __cdecl ParseFormat(LPCWSTR);
};
If you have no control on first project, the correct type for FORMAT
would be a pointer to member. Unfortunately I could never find a way to convert the result of GetProcAddress
to a pointer to member. Hopefully, it is known that that you can simply get the address of the member function and call it directly, provided you add the hidden this
as first parameter. The code would become:
class FormatImpl
{
public:
typedef void (__cdecl *FORMAT) (FormatLog *l, LPCWSTR);
HINSTANCE hModule;
FORMAT Format;
FormatImpl()
{
hModule = LoadLibrary(L"FormatLog.dll");
if (hModule != NULL)
{
Format = (FORMAT) (void *) GetProcAddress(hModule,
"?ParseFormat@FormatLog@@QAAXPB_W@Z");
}
}
...
}
(after getting the mangled name in FormatLog.exp
) and you will use it like that:
int main(int argc, char* argv[])
{
FormatImpl format;
FormatLog l;
format.Format(&l, L"%t %m %i %l");
return 0;
}
Anyway, I generally think that the mangled names should be an implementation detail and I only export extern "C"
functions from a DLL if I later want to import them manually through GetProcAddress
.
So my advice would be to add in first project:
extern "C" {
__declspec(dllexport) void __cdecl doParseFormat(LPWSTR str) {
static FormatLog flog;
flog.ParseFormat(str);
}
}
Now you can simply write:
Format = (FORMAT) GetProcAddress(hModule, "doParseFormat");
which I personnaly find more clean, and you can use it easily.
Upvotes: 1