Skip to content

Commit 5dad751

Browse files
author
mark.hammond
committed
On Windows, use the Python 'Activation Context' when loading extensions
to avoid problems loading the CRT from a private assembly. Via bug 4566. git-svn-id: http://svn.python.org/projects/python/trunk@69038 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent bcc2813 commit 5dad751

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

PC/dl_nt.c

+67-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,63 @@ char dllVersionBuffer[16] = ""; // a private buffer
1818
HMODULE PyWin_DLLhModule = NULL;
1919
const 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

2279
BOOL 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;

Python/dynload_win.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include "importdl.h"
1212
#include <windows.h>
1313

14+
// "activation context" magic - see dl_nt.c...
15+
extern ULONG_PTR _Py_ActivateActCtx();
16+
void _Py_DeactivateActCtx(ULONG_PTR cookie);
17+
1418
const struct filedescr _PyImport_DynLoadFiletab[] = {
1519
#ifdef _DEBUG
1620
{"_d.pyd", "rb", C_EXTENSION},
@@ -172,6 +176,7 @@ dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
172176
char pathbuf[260];
173177
LPTSTR dummy;
174178
unsigned int old_mode;
179+
ULONG_PTR cookie = 0;
175180
/* We use LoadLibraryEx so Windows looks for dependent DLLs
176181
in directory of pathname first. However, Windows95
177182
can sometimes not work correctly unless the absolute
@@ -184,10 +189,13 @@ dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
184189
if (GetFullPathName(pathname,
185190
sizeof(pathbuf),
186191
pathbuf,
187-
&dummy))
192+
&dummy)) {
193+
ULONG_PTR cookie = _Py_ActivateActCtx();
188194
/* XXX This call doesn't exist in Windows CE */
189195
hDLL = LoadLibraryEx(pathname, NULL,
190196
LOAD_WITH_ALTERED_SEARCH_PATH);
197+
_Py_DeactivateActCtx(cookie);
198+
}
191199

192200
/* restore old error mode settings */
193201
SetErrorMode(old_mode);

0 commit comments

Comments
 (0)