3

この場合、動的にロードされたDLLは、ファイル/フォルダーのプロパティページに新しいプロパティシート(新しいタブ)を追加するために、Windowsエクスプローラーによってロードされます。

この簡単な例は、StrmExt.dll(ダウンロードソース)です。この例(Microsoftが提供するソース)では、DLLはスレッドローカルストレージ(TLS)を使用しないため、複数のプロパティページを同時にロードするときに大きな問題が発生します。

ソースを確認すると、DLLには1つのスレッドベース変数(ファイルのファイルパス)が必要でした...

static TCHAR g_szFile[MAX_PATH];

この1行のコードを次のように変更します。

_declspec (thread) TCHAR g_szFile[MAX_PATH];

... DLLが複数のスレッドをサポートできるようにしたため、プロパティシートの複数のインスタンスをサポートできるようになりました。ただし、この変更はWindows Vista以降でのみサポートされることを私は知っていました(Windows 7でのテストは非常に肯定的です)。たとえば、XPは、動的にロードされたライブラリではこれをサポートしません...そしてアプリケーションをクラッシュさせることが知られています。(最後の段落を参照)。

XPで実行するために、この宣言を使用できませんでした。DLLエントリポイントを次の場所から拡張する必要があると思いました。

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        _Module.Init(ObjectMap, hInstance, &LIBID_STRMEXTLib);
        DisableThreadLibraryCalls(hInstance);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
        _Module.Term();
    return TRUE;    // ok
}

...このようなものに...以前にここで見たように

struct ThreadData {
    static TCHAR g_szFile[MAX_PATH];
};
...
DWORD g_dwThreadIndex;

extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, 
                      DWORD dwReason, LPVOID /*pReserved*/)
{
    ThreadData* pData;   
    switch (dwReason) {
        case DLL_PROCESS_ATTACH:

            g_dwThreadIndex = ::TlsAlloc();
            if (g_dwThreadIndex == TLS_OUT_OF_INDEXES)
                return FALSE;

           // execute the DLL_THREAD_ATTACH code

        case DLL_THREAD_ATTACH:

            // allocate memory for this thread
            pData = (ThreadData*) ::LocalAlloc(LPTR, sizeof(ThreadData));
            if (pData == 0)
                return FALSE;

            ::TlsSetValue(g_dwThreadIndex, (LPVOID) pData);
            break;

        case DLL_THREAD_DETACH:

            // release memory for this thread
            pData = (ThreadData*) ::TlsGetValue(g_dwThreadIndex);
            if (pData != 0)
                ::LocalFree((HLOCAL) pData);
            break;

        case DLL_PROCESS_DETACH:

            // release memory for this thread
            pData = (ThreadData*) ::TlsGetValue(g_dwThreadIndex);
            if (pData != 0)
                ::LocalFree((HLOCAL) pData);
            // release the TLS index
            ::TlsFree(g_dwThreadIndex);
            break;
    } 
    return TRUE;
}

これは、1つまたは2つのスレッドを作成するかどうかに関係なく、DLLの最初のロード中に正常に機能します。DLLが解放された後、ライブラリの次のロード時にExplorerがクラッシュします。

私は何を誤解していますか?元の開発者がDLLプロセスの接続通知時にスレッド通知を意図的に無効にしていることに気付きました。なんで?

DisableThreadLibraryCalls(hInstance);
4

1 に答える 1

1

この場合、問題は完全に回避するのが最善です。はい、おそらくプロセスよりも多くのスレッドがあります。はい、各プロパティシートは1つのスレッドにのみ関連付けられますが、その逆は保証されません。2つのプロパティシートが1つのスレッドを共有する場合があります。これは、OS次第です。(そして、そのような文書化されていない決定はバージョン間で異なります)。

代わりに、のlParamメンバーを使用してPROPSHEETPAGEください。64ビットシステムでも、ポインタを保持するのに十分な大きさです。それをあなた自身のクラスに向けてください。ライフタイム管理は、試行していたDLLのアタッチ/デタッチよりもはるかに簡単です。WindowsはPropSheetPageProc適切なタイミングであなたに電話をかけます。

于 2012-03-09T09:16:49.413 に答える