简体   繁体   English

MFC扩展dll资源加载问题

[英]MFC extension dll resources loading problems

I have built the folowing configuration: 我已经构建了以下配置:

  • A) MFC Extension DLL having 2 MFC dialogs. A)具有2个MFC对话框的MFC扩展DLL。
  • B) MFC regular dll that uses DLL A functions. B)使用DLL A函数的MFC常规dll。
  • C) win32 application (NON MFC) calling for function from DLL B C)win32应用程序(NON MFC)从DLL B调用函数

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. 当从DLL B调用函数时,从DLL A调用函数内部以显示对话框时,由于无法找到资源这一事实而发生错误。

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. 我已经挖掘了找到确切的根本原因,并且主要的共鸣似乎是模块上下文被设置为调用dll B而不是包含对话框资源的DLL A.

Inside DllMain the initialization is done as described in the MSDN: 在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;
}

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: 我找到的一个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);
}

By using this workarround It still causses assertion but the dialogs are shown. 通过使用这个workarround它仍然会引发断言,但会显示对话框。

What should be the normal way of solving this problem? 解决这个问题的正常方法应该是什么?

You have to insert the resources of the extension DLL into the resource chain of the regular DLL, not the EXE. 您必须将扩展DLL的资源插入常规DLL的资源链,而不是EXE。 Just create a function in the extension DLL and call it in the InitInstance method of the regular DLL, like this: 只需在扩展DLL中创建一个函数,并在常规DLL的InitInstance方法中调用它,如下所示:

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

You say "module context" but in fact the terminus technicus is "module state". 你说“模块上下文”但实际上终端技术是“模块状态”。

AFAICS this is the relatively standard (ie, most frequently occurring) MFC module state related use case here, namely: entering via callbacks / public exported APIs into internal implementation area. AFAICS这是相对标准(即最常发生)的MFC模块状态相关用例,即:通过回调/公共导出API进入内部实现区域。

AFX_MANAGE_STATE directly mentions this use case: "If you have an exported function in a DLL" AFX_MANAGE_STATE直接提到了这个用例:“如果在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. 这需要不是通过AfxSetModuleState()手动完成,而是通过正确的生命周期范围(保证适当的破坏,在任何可能存在的取消点,无论是返回或异常或其他)AFX_MANAGE_STATE宏的机制。

IOW, implementation likely needs to strongly resemble something like: 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;
}

Dont know if you have already found the solution, if not You can try using 不知道你是否已经找到了解决方案,如果没有,你可以尝试使用

AfxFindResourceHandle AfxFindResourceHandle

before accessing the problematic resource in Dll A. 在访问Dll A中有问题的资源之前

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. 我在我的DLLMain中添加了这些行,现在我没有问题使用我的DLL调用的其他DLL中的资源,比如对话框。 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM