MFC扩展DLL资源加载问题

3
我已经建立了以下配置:
  • A) MFC扩展DLL,包含2个MFC对话框。
  • B) 使用DLL A函数的MFC常规dll。
  • C) 非MFC的win32应用程序调用来自DLL B的函数
当从DLL B中调用内部调用DLL A中的函数以显示对话框时,出现错误,原因是找不到资源。
我已经挖掘出确切的根本原因,主要原因似乎是模块上下文设置为调用DLL B而不是包含对话框资源的DLL A。
在DllMain中,初始化如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;
}

我找到的一个解决方法是存储从DLLMain接收到的hInstance参数:extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved),并且在调用函数时,在DLL A中保存当前句柄并设置新句柄为从DllMain接收到的句柄:

DLL A function1(............)
{
    HINSTANCE HinstanceOld = AfxGetResourceHandle(); 
    AfxSetResourceHandle(CErrohInstance); 
    .......
    //display dialog
    .....
    AfxSetResourceHandle(HinstanceOld);
}

通过使用这个解决方法,虽然仍会导致断言,但对话框已经显示出来了。

那么,应该采用何种正常的方式来解决这个问题呢?

4个回答

4

您需要将扩展 DLL 的资源插入到常规 DLL 的资源链中,而不是 EXE 中。只需在扩展 DLL 中创建一个函数,并在常规 DLL 的 InitInstance 方法中调用它,如下所示:

void initDLL()
{
  new CDynLinkLibrary(extensionDLL);
}

1
你说“模块上下文”,但实际上术语应该是“模块状态”。 据我所知,这是相对标准(即最常出现的)MFC模块状态相关用例,即:通过回调/公共导出API进入内部实现区域。 AFX_MANAGE_STATE 直接提到了这种用例:“如果您有一个DLL中的导出函数” 此时,当前活动的模块状态是调用方的模块状态,而不是实现范围内需要的模块状态。 由于实现范围“知道”它需要不同的模块状态(并且它“知道”哪个是正确的!),因此它需要临时切换到正确的模块状态,以实现在正确的实例范围内执行任何与模块状态相关的查找(精确地说:资源实例查找)。 而且,这不是通过 AfxSetModuleState() 手动完成的,而是通过 AFX_MANAGE_STATE 宏的适当生命周期机制(保证在可能存在的任何取消点(无论是返回、异常还是其他什么)上正确销毁)完成的。 换句话说,实现可能需要强烈类似于以下内容:
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;
}

0
我已经在我的DLLMain中添加了这些行,现在我可以使用其他由我的DLL调用的DLL中的资源,例如对话框。 这是代码:
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
}

0

不知道你是否已经找到了解决方案,如果没有,可以尝试使用

AfxFindResourceHandle

在访问Dll A中的有问题资源之前。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接