summaryrefslogtreecommitdiff
path: root/PC
diff options
context:
space:
mode:
authorMark Hammond <mhammond@skippinet.com.au>2009-01-27 23:12:23 +0000
committerMark Hammond <mhammond@skippinet.com.au>2009-01-27 23:12:23 +0000
commit352cd0a22297ab8407534c4750818372a39184ee (patch)
tree23f5f6498fb3b481e2f5922ea9474289247c03b2 /PC
parent35a5d4afa3a9f4fca0dbffd9992112dd3e0ded04 (diff)
downloadcpython-352cd0a22297ab8407534c4750818372a39184ee.tar.gz
On Windows, use the Python 'Activation Context' when loading extensions
to avoid problems loading the CRT from a private assembly. Via bug 4566.
Diffstat (limited to 'PC')
-rw-r--r--PC/dl_nt.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/PC/dl_nt.c b/PC/dl_nt.c
index e143c780ac..f8af8026f4 100644
--- a/PC/dl_nt.c
+++ b/PC/dl_nt.c
@@ -18,6 +18,63 @@ char dllVersionBuffer[16] = ""; // a private buffer
HMODULE PyWin_DLLhModule = NULL;
const char *PyWin_DLLVersionString = dllVersionBuffer;
+// Windows "Activation Context" work:
+// Our .pyd extension modules are generally built without a manifest (ie,
+// those included with Python and those built with a default distutils.
+// This requires we perform some "activation context" magic when loading our
+// extensions. In summary:
+// * As our DLL loads we save the context being used.
+// * Before loading our extensions we re-activate our saved context.
+// * After extension load is complete we restore the old context.
+// As an added complication, this magic only works on XP or later - we simply
+// use the existence (or not) of the relevant function pointers from kernel32.
+// See bug 4566 (http://python.org/sf/4566) for more details.
+
+typedef BOOL (WINAPI * PFN_GETCURRENTACTCTX)(HANDLE *);
+typedef BOOL (WINAPI * PFN_ACTIVATEACTCTX)(HANDLE, ULONG_PTR *);
+typedef BOOL (WINAPI * PFN_DEACTIVATEACTCTX)(DWORD, ULONG_PTR);
+typedef BOOL (WINAPI * PFN_ADDREFACTCTX)(HANDLE);
+typedef BOOL (WINAPI * PFN_RELEASEACTCTX)(HANDLE);
+
+// locals and function pointers for this activation context magic.
+static HANDLE PyWin_DLLhActivationContext = NULL; // one day it might be public
+static PFN_GETCURRENTACTCTX pfnGetCurrentActCtx = NULL;
+static PFN_ACTIVATEACTCTX pfnActivateActCtx = NULL;
+static PFN_DEACTIVATEACTCTX pfnDeactivateActCtx = NULL;
+static PFN_ADDREFACTCTX pfnAddRefActCtx = NULL;
+static PFN_RELEASEACTCTX pfnReleaseActCtx = NULL;
+
+void _LoadActCtxPointers()
+{
+ HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32)
+ pfnGetCurrentActCtx = (PFN_GETCURRENTACTCTX) GetProcAddress(hKernel32, "GetCurrentActCtx");
+ // If we can't load GetCurrentActCtx (ie, pre XP) , don't bother with the rest.
+ if (pfnGetCurrentActCtx) {
+ pfnActivateActCtx = (PFN_ACTIVATEACTCTX) GetProcAddress(hKernel32, "ActivateActCtx");
+ pfnDeactivateActCtx = (PFN_DEACTIVATEACTCTX) GetProcAddress(hKernel32, "DeactivateActCtx");
+ pfnAddRefActCtx = (PFN_ADDREFACTCTX) GetProcAddress(hKernel32, "AddRefActCtx");
+ pfnReleaseActCtx = (PFN_RELEASEACTCTX) GetProcAddress(hKernel32, "ReleaseActCtx");
+ }
+}
+
+ULONG_PTR _Py_ActivateActCtx()
+{
+ ULONG_PTR ret = 0;
+ if (PyWin_DLLhActivationContext && pfnActivateActCtx)
+ if (!(*pfnActivateActCtx)(PyWin_DLLhActivationContext, &ret)) {
+ OutputDebugString("Python failed to activate the activation context before loading a DLL\n");
+ ret = 0; // no promise the failing function didn't change it!
+ }
+ return ret;
+}
+
+void _Py_DeactivateActCtx(ULONG_PTR cookie)
+{
+ if (cookie && pfnDeactivateActCtx)
+ if (!(*pfnDeactivateActCtx)(0, cookie))
+ OutputDebugString("Python failed to de-activate the activation context\n");
+}
BOOL WINAPI DllMain (HANDLE hInst,
ULONG ul_reason_for_call,
@@ -29,9 +86,18 @@ BOOL WINAPI DllMain (HANDLE hInst,
PyWin_DLLhModule = hInst;
// 1000 is a magic number I picked out of the air. Could do with a #define, I spose...
LoadString(hInst, 1000, dllVersionBuffer, sizeof(dllVersionBuffer));
- //initall();
+
+ // and capture our activation context for use when loading extensions.
+ _LoadActCtxPointers();
+ if (pfnGetCurrentActCtx && pfnAddRefActCtx)
+ if ((*pfnGetCurrentActCtx)(&PyWin_DLLhActivationContext))
+ if (!(*pfnAddRefActCtx)(PyWin_DLLhActivationContext))
+ OutputDebugString("Python failed to load the default activation context\n");
break;
+
case DLL_PROCESS_DETACH:
+ if (pfnReleaseActCtx)
+ (*pfnReleaseActCtx)(PyWin_DLLhActivationContext);
break;
}
return TRUE;