@@ -18,6 +18,63 @@ char dllVersionBuffer[16] = ""; // a private buffer
1818HMODULE PyWin_DLLhModule = NULL ;
1919const char * PyWin_DLLVersionString = dllVersionBuffer ;
2020
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+
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+
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+
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+ }
2178
2279BOOL WINAPI DllMain (HANDLE hInst ,
2380 ULONG ul_reason_for_call ,
@@ -29,9 +86,18 @@ BOOL WINAPI DllMain (HANDLE hInst,
2986 PyWin_DLLhModule = hInst ;
3087 // 1000 is a magic number I picked out of the air. Could do with a #define, I spose...
3188 LoadString (hInst , 1000 , dllVersionBuffer , sizeof (dllVersionBuffer ));
32- //initall();
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" );
3396 break ;
97+
3498 case DLL_PROCESS_DETACH :
99+ if (pfnReleaseActCtx )
100+ (* pfnReleaseActCtx )(PyWin_DLLhActivationContext );
35101 break ;
36102 }
37103 return TRUE;
0 commit comments