【问题标题】:MFC extension dll resources loading problemsMFC扩展dll资源加载问题
【发布时间】:2012-07-16 01:49:07
【问题描述】:

我已经构建了以下配置:

  • 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;
}

我发现的一个解决方法是存储从 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,它仍然会引起断言,但会显示对话框。

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

【问题讨论】:

    标签: c++ dll mfc dialog afx


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      你说的是“模块上下文”,但实际上技术的终点是“模块状态”。

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

      AFX_MANAGE_STATE直接提到了这个用例:“如果你有一个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;
      }
      

      【讨论】:

        【解决方案3】:

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

        AfxFindResourceHandle

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

        【讨论】:

          【解决方案4】:

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

          【讨论】:

            猜你喜欢
            • 2010-12-13
            • 2012-05-07
            • 1970-01-01
            • 2010-10-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-23
            • 1970-01-01
            相关资源
            最近更新 更多