1/*
2
3Entry point for the Windows NT DLL.
4
5About the only reason for having this, is so initall() can automatically
6be called, removing that burden (and possible source of frustration if
7forgotten) 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
17char dllVersionBuffer[16] = MS_DLL_ID;
18#else
19char dllVersionBuffer[16] = ""; // a private buffer
20#endif
21
22// Python Globals
23HMODULE PyWin_DLLhModule = NULL;
24const 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
41typedef BOOL (WINAPI * PFN_GETCURRENTACTCTX)(HANDLE *);
42typedef BOOL (WINAPI * PFN_ACTIVATEACTCTX)(HANDLE, ULONG_PTR *);
43typedef BOOL (WINAPI * PFN_DEACTIVATEACTCTX)(DWORD, ULONG_PTR);
44typedef BOOL (WINAPI * PFN_ADDREFACTCTX)(HANDLE);
45typedef BOOL (WINAPI * PFN_RELEASEACTCTX)(HANDLE);
46
47// locals and function pointers for this activation context magic.
48static HANDLE PyWin_DLLhActivationContext = NULL; // one day it might be public
49static PFN_GETCURRENTACTCTX pfnGetCurrentActCtx = NULL;
50static PFN_ACTIVATEACTCTX pfnActivateActCtx = NULL;
51static PFN_DEACTIVATEACTCTX pfnDeactivateActCtx = NULL;
52static PFN_ADDREFACTCTX pfnAddRefActCtx = NULL;
53static PFN_RELEASEACTCTX pfnReleaseActCtx = NULL;
54
55void _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
69ULONG_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
80void _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
88BOOL    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