DEADLOCK.MAK
 CC_OPTS = /MT /D_MT /O2 /c /YX
all: deadlockexe.exe
deadlockdll.lib: deadlockdll.dll
deadlockdll.dll: deadlockdll.obj
    link /DLL /IMPLIB:deadlockdll.lib /EXPORT:FunctionInADLL deadlockdll.obj
deadlockdll.obj: deadlockdll.h deadlockdll.cpp
    cl $(CC_OPTS) deadlockdll.cpp
deadlockexe.exe: deadlockdll.lib deadlockexe.obj
    link deadlockexe.obj deadlockdll.lib
deadlockexe.obj: deadlockdll.h deadlockexe.cpp
    cl $(CC_OPTS) $(DLLIMPORT) deadlockexe.cppDEADLOCKDLL.H
 __declspec(dllexport) int __stdcall FunctionInADLL(void);DEADLOCKDLL.CPP
 #include <windows.h>
#include <stdio.h>
#include <process.h>
#pragma hdrstop
#include "deadlockdll.h"
CRITICAL_SECTION MyCritSect;
void SecondThreadFunction(void * p);    // prototype the second thread function
// Called in the context of the main thread
__declspec(dllexport) int __stdcall FunctionInADLL(void)
{
    // Inform user of our startup status
    printf( "In primary thread\n" );
    // Initialize and enter a run of the mill critical section
    InitializeCriticalSection( &MyCritSect );
    EnterCriticalSection( &MyCritSect );
    // Start up a second thread, which will cause DllMain to be invoked in
    // the context of the new thread.
    printf( "Starting second thread\n" );
    _beginthread( SecondThreadFunction, 0, 0 );
    // Make the main thread sleep, thereby giving the second thread enough
    // time to execute through DllMain and deadlock
    printf( "Sleeping(1) in primary thread\n" );
    Sleep( 2000 );                                  
    printf("Done sleeping(1) in primary thread\n");
    // At this point, thread 1 owns MyCritSect, while thread 2 is blocked
    // inside DllMain, waiting for MyCritSect.  Unfortunately, thread
    // 2 holds the process critical section, which GetProcAddress neeeds.
    #if 1
    printf( "Before calling GetProcAddress in primary thread\n" );
    GetProcAddress( GetModuleHandle("KERNEL32.DLL"), "XYZ" );
    printf( "After calling GetProcAddress in primary thread\n" );
    #endif
    // If the process critical section didn't deadlock us, we'd release the
    // app critical section, and the 2nd thread would execute OK.
    LeaveCriticalSection( &MyCritSect );
    // Make the main thread sleep again, thereby ensuring that the second
    // thread has time to complete before the first thread exits
    printf( "Sleeping(2) in primary thread\n" );
    Sleep( 2000 );                              
    printf("Done sleeping(2) in primary thread\n");
    DeleteCriticalSection( &MyCritSect );       // Cleanup code
    printf( "Returning from primary thread\n" );
    return 0;
}
void SecondThreadFunction(void * p)
{
    printf("  In SecondThreadFunction\n" );
}
int WINAPI DllMain( HANDLE hInst, ULONG reason, LPVOID lpReserved )
{
    if ( reason == DLL_THREAD_ATTACH )
    {
        printf("  In DllMain of 2nd thread - Before EnterCriticalSection\n" );
        EnterCriticalSection( &MyCritSect );
        printf("  In DllMain of 2nd thread - After EnterCriticalSection\n" );
        LeaveCriticalSection( &MyCritSect );
        printf("  In DllMain of 2nd thread - After LeaveCriticalSection\n" );
    }
    return 1;
}DEADLOCKEXE.CPP
 #include "deadlockdll.h"
int main()
{
    return FunctionInADLL() + 2;  // kludge required to prevent
}                                 // compiler from optimizing a
                                  // call to jmp