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
_LoadActCtxPointers()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
_Py_ActivateActCtx()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
_Py_DeactivateActCtx(ULONG_PTR cookie)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
DllMain(HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved)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