Home | History | Annotate | Download | only in PC
      1 /*
      2 
      3 Entry point for the Windows NT DLL.
      4 
      5 About the only reason for having this, is so initall() can automatically
      6 be called, removing that burden (and possible source of frustration if
      7 forgotten) from the programmer.
      8 
      9 */
     10 
     11 #include "Python.h"
     12 #include "windows.h"
     13 
     14 #ifdef Py_ENABLE_SHARED
     15 #ifdef MS_DLL_ID
     16 // The string is available at build, so fill the buffer immediately
     17 char dllVersionBuffer[16] = MS_DLL_ID;
     18 #else
     19 char dllVersionBuffer[16] = ""; // a private buffer
     20 #endif
     21 
     22 // Python Globals
     23 HMODULE PyWin_DLLhModule = NULL;
     24 const char *PyWin_DLLVersionString = dllVersionBuffer;
     25 
     26 #if HAVE_SXS
     27 // Windows "Activation Context" work.
     28 // Our .pyd extension modules are generally built without a manifest (ie,
     29 // those included with Python and those built with a default distutils.
     30 // This requires we perform some "activation context" magic when loading our
     31 // extensions.  In summary:
     32 // * As our DLL loads we save the context being used.
     33 // * Before loading our extensions we re-activate our saved context.
     34 // * After extension load is complete we restore the old context.
     35 // As an added complication, this magic only works on XP or later - we simply
     36 // use the existence (or not) of the relevant function pointers from kernel32.
     37 // See bug 4566 (http://python.org/sf/4566) for more details.
     38 // In Visual Studio 2010, side by side assemblies are no longer used by
     39 // default.
     40 
     41 typedef BOOL (WINAPI * PFN_GETCURRENTACTCTX)(HANDLE *);
     42 typedef BOOL (WINAPI * PFN_ACTIVATEACTCTX)(HANDLE, ULONG_PTR *);
     43 typedef BOOL (WINAPI * PFN_DEACTIVATEACTCTX)(DWORD, ULONG_PTR);
     44 typedef BOOL (WINAPI * PFN_ADDREFACTCTX)(HANDLE);
     45 typedef BOOL (WINAPI * PFN_RELEASEACTCTX)(HANDLE);
     46 
     47 // locals and function pointers for this activation context magic.
     48 static HANDLE PyWin_DLLhActivationContext = NULL; // one day it might be public
     49 static PFN_GETCURRENTACTCTX pfnGetCurrentActCtx = NULL;
     50 static PFN_ACTIVATEACTCTX pfnActivateActCtx = NULL;
     51 static PFN_DEACTIVATEACTCTX pfnDeactivateActCtx = NULL;
     52 static PFN_ADDREFACTCTX pfnAddRefActCtx = NULL;
     53 static PFN_RELEASEACTCTX pfnReleaseActCtx = NULL;
     54 
     55 void _LoadActCtxPointers()
     56 {
     57     HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll");
     58     if (hKernel32)
     59         pfnGetCurrentActCtx = (PFN_GETCURRENTACTCTX) GetProcAddress(hKernel32, "GetCurrentActCtx");
     60     // If we can't load GetCurrentActCtx (ie, pre XP) , don't bother with the rest.
     61     if (pfnGetCurrentActCtx) {
     62         pfnActivateActCtx = (PFN_ACTIVATEACTCTX) GetProcAddress(hKernel32, "ActivateActCtx");
     63         pfnDeactivateActCtx = (PFN_DEACTIVATEACTCTX) GetProcAddress(hKernel32, "DeactivateActCtx");
     64         pfnAddRefActCtx = (PFN_ADDREFACTCTX) GetProcAddress(hKernel32, "AddRefActCtx");
     65         pfnReleaseActCtx = (PFN_RELEASEACTCTX) GetProcAddress(hKernel32, "ReleaseActCtx");
     66     }
     67 }
     68 
     69 ULONG_PTR _Py_ActivateActCtx()
     70 {
     71     ULONG_PTR ret = 0;
     72     if (PyWin_DLLhActivationContext && pfnActivateActCtx)
     73         if (!(*pfnActivateActCtx)(PyWin_DLLhActivationContext, &ret)) {
     74             OutputDebugString("Python failed to activate the activation context before loading a DLL\n");
     75             ret = 0; // no promise the failing function didn't change it!
     76         }
     77     return ret;
     78 }
     79 
     80 void _Py_DeactivateActCtx(ULONG_PTR cookie)
     81 {
     82     if (cookie && pfnDeactivateActCtx)
     83         if (!(*pfnDeactivateActCtx)(0, cookie))
     84             OutputDebugString("Python failed to de-activate the activation context\n");
     85 }
     86 #endif /* HAVE_SXS */
     87 
     88 BOOL    WINAPI  DllMain (HANDLE hInst,
     89                                                 ULONG ul_reason_for_call,
     90                                                 LPVOID lpReserved)
     91 {
     92     switch (ul_reason_for_call)
     93     {
     94         case DLL_PROCESS_ATTACH:
     95             PyWin_DLLhModule = hInst;
     96 #ifndef MS_DLL_ID
     97             // If we have MS_DLL_ID, we don't need to load the string.
     98             // 1000 is a magic number I picked out of the air.  Could do with a #define, I spose...
     99             LoadString(hInst, 1000, dllVersionBuffer, sizeof(dllVersionBuffer));
    100 #endif
    101 
    102 #if HAVE_SXS
    103             // and capture our activation context for use when loading extensions.
    104             _LoadActCtxPointers();
    105             if (pfnGetCurrentActCtx && pfnAddRefActCtx)
    106                 if ((*pfnGetCurrentActCtx)(&PyWin_DLLhActivationContext))
    107                     if (!(*pfnAddRefActCtx)(PyWin_DLLhActivationContext))
    108                         OutputDebugString("Python failed to load the default activation context\n");
    109 #endif
    110             break;
    111 
    112         case DLL_PROCESS_DETACH:
    113 #if HAVE_SXS
    114             if (pfnReleaseActCtx)
    115                 (*pfnReleaseActCtx)(PyWin_DLLhActivationContext);
    116 #endif
    117             break;
    118     }
    119     return TRUE;
    120 }
    121 
    122 #endif /* Py_ENABLE_SHARED */
    123