Home > database >  Do I have to call TlsAlloc() in DLL_PROCESS_ATTACH?
Do I have to call TlsAlloc() in DLL_PROCESS_ATTACH?

Time:05-28

Do I have to call TlsAlloc() in DLL_PROCESS_ATTACH once genrally since the DLL hasn't any addional calls with DLL_THREAD_ATTACH for the thread doing the LoadLibrary() ?
Or to make it even more complicated: Do I get a DLL_THREAD_ATTACH notification in addition to the DLL_PROCESS_ATTACH notification if I create a thread directly from DLL_PROCESS_ATTACH ?

EDIT: I've wrote a little test application that loads a library that spawns a thread:

#include <Windows.h>
#include <iostream>

using namespace std;

int main()
{
    HMODULE hmLib = LoadLibraryA( "theDll.dll" );
    HANDLE &hDllThread = *(HANDLE *)GetProcAddress( hmLib, "hDllThread" );
    WaitForSingleObject( hDllThread, INFINITE );
    cout << "thead terminated " << endl;
    cout << "thread id: " << GetCurrentThreadId() << endl << endl;
}

Here's the DLL:

#include <Windows.h>
#include <iostream>

using namespace std;

extern "C"
__declspec(dllexport)
HANDLE hDllThread = NULL;

void printThreadId()
{
    cout << "thread id: " << GetCurrentThreadId() << endl;
};

BOOL APIENTRY DllMain( HMODULE hModule, DWORD dwReason, LPVOID lpReserved )
{
    switch( dwReason )
    {
    case DLL_PROCESS_ATTACH:
        {
            printThreadId();
            cout << "process attach" << endl << endl;
            ::hDllThread = CreateThread( nullptr, 0,
                []( LPVOID ) -> DWORD
                {
                    cout << "created thread id: " << GetCurrentThreadId() << endl;
                    cout << endl;
                    return 0;
                }, nullptr, 0, nullptr );
            // don't do that here
            // WaitForSingleObject( ::hDllThread, INFINITE );
            break;
        }
    case DLL_THREAD_ATTACH:
        printThreadId();
        cout << "thread attach" << endl << endl;
        // don't do that here
        // WaitForSingleObject( ::hDllThread, INFINITE );
        break;
    case DLL_THREAD_DETACH:
        printThreadId();
        cout << "thread detach" << endl << endl;
        break;
    case DLL_PROCESS_DETACH:
        printThreadId();
        cout << "process detach" << endl << endl;
        break;
    }
    return TRUE;
}

static struct S
{
    S()
    {
        printThreadId();
        cout << "statics are initialized, but not thread locals" << endl << endl;
    }
} s;

On my computer this prints:

thread id: 14692
statics are initialized, but not thread locals

thread id: 14692
process attach

thread id: 9396
thread attach

created thread id: 9396

thread id: 9396
thread detach

thead terminated
thread id: 14692

thread id: 14692
process detach

"thread attach" is printed before "created thread" in the context of the new thread. If I wait for the thread to terminate in DLL_PROCESS_ATTACH or DLL_THREAD_ATTACH I wait forever. So the entry point is called after both calls. Is this documented ?

CodePudding user response:

1.Do I have to call TlsAlloc() in DLL_PROCESS_ATTACH once genrally since the DLL hasn't any addional calls with DLL_THREAD_ATTACH for the thread doing the LoadLibrary() ?

Call TlsAlloc() won't do anything for your current question.

Each time the process creates a new thread, the entry-point function is called with the DLL_THREAD_ATTACH value.


2.So the entry point is called after both calls. Is this documented ?

Raymond Chen has explained thread creation and running process in his blog.

When you call CreateThread, a kernel thread object is created and scheduled. Once the thread gets a chance to run, the kernel calls all the DllMain functions with the DLL_THREAD_ATTACH code. Once that’s done, the thread’s entry point is called.

In MSDN, You can refer to this official document.

DLL_THREAD_ATTACH, Note that a DLL's entry-point function is called with this value only by threads created after the DLL is loaded by the process.

CodePudding user response:

Sorry, everything I told based on outdated informaton. Before Vista dynamially loaded DLLs with thread locals weren't reliable.
Everything is fine with thread_local / __declspec(thread) in DLLs for years.

  • Related