• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 char dllVersionBuffer[16] = ""; // a private buffer
16 
17 // Python Globals
18 HMODULE PyWin_DLLhModule = NULL;
19 const char *PyWin_DLLVersionString = dllVersionBuffer;
20 
21 // Windows "Activation Context" work:
22 // Our .pyd extension modules are generally built without a manifest (ie,
23 // those included with Python and those built with a default distutils.
24 // This requires we perform some "activation context" magic when loading our
25 // extensions.  In summary:
26 // * As our DLL loads we save the context being used.
27 // * Before loading our extensions we re-activate our saved context.
28 // * After extension load is complete we restore the old context.
29 // As an added complication, this magic only works on XP or later - we simply
30 // use the existence (or not) of the relevant function pointers from kernel32.
31 // See bug 4566 (http://python.org/sf/4566) for more details.
32 
33 typedef BOOL (WINAPI * PFN_GETCURRENTACTCTX)(HANDLE *);
34 typedef BOOL (WINAPI * PFN_ACTIVATEACTCTX)(HANDLE, ULONG_PTR *);
35 typedef BOOL (WINAPI * PFN_DEACTIVATEACTCTX)(DWORD, ULONG_PTR);
36 typedef BOOL (WINAPI * PFN_ADDREFACTCTX)(HANDLE);
37 typedef BOOL (WINAPI * PFN_RELEASEACTCTX)(HANDLE);
38 
39 // locals and function pointers for this activation context magic.
40 static HANDLE PyWin_DLLhActivationContext = NULL; // one day it might be public
41 static PFN_GETCURRENTACTCTX pfnGetCurrentActCtx = NULL;
42 static PFN_ACTIVATEACTCTX pfnActivateActCtx = NULL;
43 static PFN_DEACTIVATEACTCTX pfnDeactivateActCtx = NULL;
44 static PFN_ADDREFACTCTX pfnAddRefActCtx = NULL;
45 static PFN_RELEASEACTCTX pfnReleaseActCtx = NULL;
46 
_LoadActCtxPointers()47 void _LoadActCtxPointers()
48 {
49     HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll");
50     if (hKernel32)
51         pfnGetCurrentActCtx = (PFN_GETCURRENTACTCTX) GetProcAddress(hKernel32, "GetCurrentActCtx");
52     // If we can't load GetCurrentActCtx (ie, pre XP) , don't bother with the rest.
53     if (pfnGetCurrentActCtx) {
54         pfnActivateActCtx = (PFN_ACTIVATEACTCTX) GetProcAddress(hKernel32, "ActivateActCtx");
55         pfnDeactivateActCtx = (PFN_DEACTIVATEACTCTX) GetProcAddress(hKernel32, "DeactivateActCtx");
56         pfnAddRefActCtx = (PFN_ADDREFACTCTX) GetProcAddress(hKernel32, "AddRefActCtx");
57         pfnReleaseActCtx = (PFN_RELEASEACTCTX) GetProcAddress(hKernel32, "ReleaseActCtx");
58     }
59 }
60 
_Py_ActivateActCtx()61 ULONG_PTR _Py_ActivateActCtx()
62 {
63     ULONG_PTR ret = 0;
64     if (PyWin_DLLhActivationContext && pfnActivateActCtx)
65         if (!(*pfnActivateActCtx)(PyWin_DLLhActivationContext, &ret)) {
66             OutputDebugString("Python failed to activate the activation context before loading a DLL\n");
67             ret = 0; // no promise the failing function didn't change it!
68         }
69     return ret;
70 }
71 
_Py_DeactivateActCtx(ULONG_PTR cookie)72 void _Py_DeactivateActCtx(ULONG_PTR cookie)
73 {
74     if (cookie && pfnDeactivateActCtx)
75         if (!(*pfnDeactivateActCtx)(0, cookie))
76             OutputDebugString("Python failed to de-activate the activation context\n");
77 }
78 
DllMain(HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved)79 BOOL    WINAPI  DllMain (HANDLE hInst,
80                                                 ULONG ul_reason_for_call,
81                                                 LPVOID lpReserved)
82 {
83     switch (ul_reason_for_call)
84     {
85         case DLL_PROCESS_ATTACH:
86             PyWin_DLLhModule = hInst;
87             // 1000 is a magic number I picked out of the air.  Could do with a #define, I spose...
88             LoadString(hInst, 1000, dllVersionBuffer, sizeof(dllVersionBuffer));
89 
90             // and capture our activation context for use when loading extensions.
91             _LoadActCtxPointers();
92             if (pfnGetCurrentActCtx && pfnAddRefActCtx)
93                 if ((*pfnGetCurrentActCtx)(&PyWin_DLLhActivationContext))
94                     if (!(*pfnAddRefActCtx)(PyWin_DLLhActivationContext))
95                         OutputDebugString("Python failed to load the default activation context\n");
96             break;
97 
98         case DLL_PROCESS_DETACH:
99             if (pfnReleaseActCtx)
100                 (*pfnReleaseActCtx)(PyWin_DLLhActivationContext);
101             break;
102     }
103     return TRUE;
104 }
105 
106 #endif /* Py_ENABLE_SHARED */
107