首页 文章

MFC扩展dll资源加载问题

提问于
浏览
3

我已经构建了以下配置:

  • A)具有2个MFC对话框的MFC扩展DLL .

  • B)使用DLL A函数的MFC常规dll .

  • C)win32应用程序(NON MFC)从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;
}

我找到的一个workarround是存储从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);
}

通过使用这个workarround它仍然会引发断言,但会显示对话框 .

解决这个问题的正常方法应该是什么?

4 回答

  • 0

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

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

    你说“模块上下文”但实际上终端技术是“模块状态” .

    AFAICS这是相对标准(即最常发生)的MFC模块状态相关用例,即:通过回调/公共导出API进入内部实现区域 .

    AFX_MANAGE_STATE直接提到这个用例:"If you have an exported function in a DLL"

    此时,当前活动的模块状态是主叫方之一,它不是实现范围内所需的那个 . 由于实现范围知道它需要一个不同的模块状态(并且知道哪个是正确的!),它需要临时切换到正确的状态,以实现任何与模块状态相关的查找(精确地:资源实例)查找)在正确的实例范围内完成 .

    这需要不是通过AfxSetModuleState()手动完成,而是通过正确的生命周期范围(保证适当的破坏,在任何可能存在的取消点,无论是返回或异常或其他)AFX_MANAGE_STATE宏的机制 .

    IOW,实现可能需要非常类似于:

    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

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

    AfxFindResourceHandle

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

  • 1

    我在我的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
    }
    

相关问题