Reputation: 33
I have built the folowing configuration:
When calling functions from DLL B that inside call functions from DLL A to display a dialog an error occurs due to the fact that resource can not be found.
I have digged to find the exact root cause and themain reson seems to be the fact that the module context is set to the calling dll B rather than to the DLL A, which contains the dialog resource.
Inside DllMain the initialization is done as described in the MSDN:
static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
Hinstance = hInstance; //save instance for later reuse
// Extension DLL one-time initialization
if (AfxInitExtensionModule(extensionDLL,hInstance) == 0)
{
AfxMessageBox("Error on init AfxInitExtensionModule!");
return 0;
}
// Insert this DLL into the resource chain
new CDynLinkLibrary(extensionDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
Release();
}
return 1;
}
One workarround that i've found was to store the hInstance parameter received from DLLMain: extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) and inside DLL A when functions are called, I save current handle and set new handle the handle received from DllMain:
DLL A function1(............)
{
HINSTANCE HinstanceOld = AfxGetResourceHandle();
AfxSetResourceHandle(CErrohInstance);
.......
//display dialog
.....
AfxSetResourceHandle(HinstanceOld);
}
By using this workarround It still causses assertion but the dialogs are shown.
What should be the normal way of solving this problem?
Upvotes: 3
Views: 5531
Reputation: 335
You say "module context" but in fact the terminus technicus is "module state".
AFAICS this is the relatively standard (i.e., most frequently occurring) MFC module state related use case here, namely: entering via callbacks / public exported APIs into internal implementation area.
AFX_MANAGE_STATE directly mentions this use case: "If you have an exported function in a DLL"
At this point, the module state that is currently active is the one of the calling party, which is not the one which is needed within implementation scope. Since implementation scope knows that it needs a different module state (and it is the one to know which is the correct one!), it needs to temporarily switch to the correct one, to achieve having any module state related lookup (precisely: resource instance lookup) done within the correct instance scope.
And this needs to be done not manually via AfxSetModuleState(), but rather via the properly lifetime-scoped (guarantees proper destruction, at whichever cancellation points may exist, be it return or exception or whatever) mechanism of AFX_MANAGE_STATE macro.
IOW, implementation likely needs to strongly resemble something like:
BOOL MyPublicAPIOrCallback()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // ensure locally expected module state within this externally-invoked handling scope
some_handling_which_does_resource_lookup_or_whatever;
}
Upvotes: 1
Reputation: 11
I have add this lines in my DLLMain and now I don't have problems to use resources that are in other DLL's called by my DLL, like dialogs. This is the Code:
static AFX_EXTENSION_MODULE CODIAbantailDLLDLL = { NULL, NULL };
AplicacionBase theApp;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Quitar lo siguiente si se utiliza lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
// ******** VERY IMPORTANT ***********************
// IF you doesn't put this, when you call other DLL that has
// its owns resources (dialogs for instance), it crash
CoInitialize(NULL);
AfxWinInit(hInstance, NULL, ::GetCommandLine(), 0);
AfxEnableControlContainer();
//**************************************************
TRACE0("Inicializando CODIAbantailDLL.DLL\n");
// Inicialización única del archivo DLL de extensión
if (!AfxInitExtensionModule(CODIAbantailDLLDLL, hInstance))
return 0;
new CDynLinkLibrary(CODIAbantailDLLDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("Finalizando CODIAbantailDLL.DLL\n");
// Finalizar la biblioteca antes de llamar a los destructores
AfxTermExtensionModule(CODIAbantailDLLDLL);
}
return 1; // aceptar
}
Upvotes: 1
Reputation: 56
You have to insert the resources of the extension DLL into the resource chain of the regular DLL, not the EXE. Just create a function in the extension DLL and call it in the InitInstance method of the regular DLL, like this:
void initDLL()
{
new CDynLinkLibrary(extensionDLL);
}
Upvotes: 4
Reputation: 97
Dont know if you have already found the solution, if not You can try using
before accessing the problematic resource in Dll A.
Upvotes: 0