3

次の構成を作成しました。

  • A)2つのMFCダイアログを持つMFC拡張DLL。
  • B)DLLA関数を使用するMFC通常のdll。
  • C)DLL Bから関数を呼び出すwin32アプリケーション(非MFC)

DLL Aから関数を呼び出してダイアログを表示するDLLBから関数を呼び出すと、リソースが見つからないためにエラーが発生します。

私は正確な根本原因を見つけるために掘り下げました、そして主な理由はモジュールコンテキストがダイアログリソースを含むDLLAではなく呼び出し元のdllBに設定されているという事実であるようです。

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

私が見つけた回避策の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 に答える 4

4

拡張DLLのリソースを、EXEではなく通常のDLLのリソースチェーンに挿入する必要があります。次のように、拡張DLLで関数を作成し、通常のDLLのInitInstanceメソッドで呼び出します。

void initDLL()
{
  new CDynLinkLibrary(extensionDLL);
}
于 2012-11-14T19:28:26.437 に答える
1

あなたは「モジュールコンテキスト」と言いますが、実際には、終了テクニックは「モジュール状態」です。

AFAICSこれは、ここでは比較的標準的な(つまり、最も頻繁に発生する)MFCモジュールの状態に関連するユースケースです。つまり、コールバック/パブリックエクスポートされたAPIを介して内部実装領域に入力します。

AFX_MANAGE_STATEは、このユースケースに直接言及しています:「DLLにエクスポートされた関数がある場合」

この時点で、現在アクティブなモジュール状態は呼び出し側の1つであり、実装スコープ内で必要な状態ではありません。実装スコープは、異なるモジュール状態が必要であることを認識しているため(そして、どちらが正しいかを知るためのものです!)、モジュール状態に関連するルックアップ(正確にはリソースインスタンス)を実現するには、一時的に正しいモジュール状態に切り替える必要があります。ルックアップ)正しいインスタンススコープ内で実行されます。

また、これは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;
}
于 2017-09-20T11:23:53.507 に答える
0

あなたがすでに解決策を見つけたかどうかわからない、そうでない場合はあなたが使用してみることができます

AfxFindResourceHandle

DLLAの問題のあるリソースにアクセスする前。

于 2012-09-04T10:38:40.567 に答える
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
}
于 2015-04-18T17:20:52.823 に答える