summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Hammond <mhammond@skippinet.com.au>2009-01-27 23:46:57 +0000
committerMark Hammond <mhammond@skippinet.com.au>2009-01-27 23:46:57 +0000
commit9844a1ffc3645a431ea9198e52214615e7752de7 (patch)
tree8e724435974089baad36e53369140da387193f69
parent4fcc4cf1857a7d0a37c39c5df9aed1744bc02cd5 (diff)
downloadcpython-git-9844a1ffc3645a431ea9198e52214615e7752de7.tar.gz
Merged revisions 69038 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r69038 | mark.hammond | 2009-01-28 10:12:23 +1100 (Wed, 28 Jan 2009) | 3 lines On Windows, use the Python 'Activation Context' when loading extensions to avoid problems loading the CRT from a private assembly. Via bug 4566. ........
-rw-r--r--PC/dl_nt.c68
-rw-r--r--Python/dynload_win.c10
2 files changed, 76 insertions, 2 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;
diff --git a/Python/dynload_win.c b/Python/dynload_win.c
index 2f46037ae9..61c5664da4 100644
--- a/Python/dynload_win.c
+++ b/Python/dynload_win.c
@@ -11,6 +11,10 @@
#include "importdl.h"
#include <windows.h>
+// "activation context" magic - see dl_nt.c...
+extern ULONG_PTR _Py_ActivateActCtx();
+void _Py_DeactivateActCtx(ULONG_PTR cookie);
+
const struct filedescr _PyImport_DynLoadFiletab[] = {
#ifdef _DEBUG
{"_d.pyd", "rb", C_EXTENSION},
@@ -172,6 +176,7 @@ dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
char pathbuf[260];
LPTSTR dummy;
unsigned int old_mode;
+ ULONG_PTR cookie = 0;
/* We use LoadLibraryEx so Windows looks for dependent DLLs
in directory of pathname first. However, Windows95
can sometimes not work correctly unless the absolute
@@ -184,10 +189,13 @@ dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
if (GetFullPathName(pathname,
sizeof(pathbuf),
pathbuf,
- &dummy))
+ &dummy)) {
+ ULONG_PTR cookie = _Py_ActivateActCtx();
/* XXX This call doesn't exist in Windows CE */
hDLL = LoadLibraryEx(pathname, NULL,
LOAD_WITH_ALTERED_SEARCH_PATH);
+ _Py_DeactivateActCtx(cookie);
+ }
/* restore old error mode settings */
SetErrorMode(old_mode);