2
* Bootloader for a DLL COM server.
3
* Copyright (C) 2005, Giovanni Bajo
4
* Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version 2
9
* of the License, or (at your option) any later version.
11
* In addition to the permissions in the GNU General Public License, the
12
* authors give you unlimited permission to link or embed the compiled
13
* version of this file into combinations with other programs, and to
14
* distribute those combinations without any restriction coming from the
15
* use of this file. (The General Public License restrictions do apply in
16
* other respects; for example, they cover modification of the file, and
17
* distribution when not linked into a combine executable.)
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this program; if not, write to the Free Software
26
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
32
typedef int (__stdcall *__PROC__DllCanUnloadNow) (void);
33
__PROC__DllCanUnloadNow Pyc_DllCanUnloadNow = NULL;
34
typedef HRESULT (__stdcall *__PROC__DllGetClassObject) (REFCLSID, REFIID, LPVOID *);
35
__PROC__DllGetClassObject Pyc_DllGetClassObject = NULL;
36
typedef int (__cdecl *__PROC__DllRegisterServerEx) (const char *);
37
__PROC__DllRegisterServerEx Pyc_DllRegisterServerEx = NULL;
38
typedef int (__cdecl *__PROC__DllUnregisterServerEx) (const char *);
39
__PROC__DllUnregisterServerEx Pyc_DllUnregisterServerEx = NULL;
40
typedef void (__cdecl *__PROC__PyCom_CoUninitialize) (void);
41
__PROC__PyCom_CoUninitialize PyCom_CoUninitialize = NULL;
43
HINSTANCE gPythoncom = 0;
44
char here[_MAX_PATH + 1];
45
int LoadPythonCom(void);
46
void releasePythonCom(void);
48
PyThreadState *thisthread = NULL;
50
int launch(char const * archivePath, char const * archiveName)
54
char pathnm[_MAX_PATH];
57
strcpy(pathnm, archivePath);
58
strcat(pathnm, archiveName);
60
if (setPaths(archivePath, archiveName))
63
/* Open the archive */
68
if (attachPython(&loadedNew))
72
/* Start Python with silly command line */
73
PI_PyEval_InitThreads();
74
if (startPython(1, (char**)&pathnm))
76
VS("Started new Python");
77
thisthread = PI_PyThreadState_Swap(NULL);
78
PI_PyThreadState_Swap(thisthread);
81
VS("Attached to existing Python");
83
/* start a mew interp */
84
thisthread = PI_PyThreadState_Swap(NULL);
85
PI_PyThreadState_Swap(thisthread);
86
if (thisthread == NULL) {
87
thisthread = PI_Py_NewInterpreter();
88
VS("created thisthread");
91
VS("grabbed thisthread");
92
PI_PyRun_SimpleString("import sys;sys.argv=[]");
95
/* a signal to scripts */
96
PI_PyRun_SimpleString("import sys;sys.frozen='dll'\n");
98
/* Create a 'frozendllhandle' as a counterpart to
99
sys.dllhandle (which is the Pythonxx.dll handle)
101
obHandle = PI_Py_BuildValue("i", gInstance);
102
PI_PySys_SetObject("frozendllhandle", obHandle);
103
Py_XDECREF(obHandle);
104
/* Import modules from archive - this is to bootstrap */
107
VS("Imported Modules");
108
/* Install zlibs - now import hooks are in place */
111
VS("Installed Zlibs");
115
VS("All scripts run");
116
if (PI_PyErr_Occurred()) {
119
VS("Some error occurred");
122
// Abandon our thread state.
123
PI_PyEval_ReleaseThread(thisthread);
129
char thisfile[_MAX_PATH + 1];
133
if (!GetModuleFileNameA(gInstance, thisfile, _MAX_PATH)) {
134
FATALERROR("System error - unable to load!");
137
// fill in here (directory of thisfile)
138
//GetModuleFileName returns an absolute path
139
strcpy(here, thisfile);
140
for (p=here+strlen(here); *p != '\\' && p >= here+2; --p);
144
//VS(&thisfile[len]);
145
launch(here, &thisfile[len]);
147
// Now Python is up and running (any scripts have run)
150
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
152
if ( dwReason == DLL_PROCESS_ATTACH) {
153
VS("Attach from thread %x", GetCurrentThreadId());
154
gInstance = hInstance;
156
else if ( dwReason == DLL_PROCESS_DETACH ) {
157
VS("Process Detach");
159
// releasePythonCom();
168
char dllpath[_MAX_PATH+1];
169
VS("Loading Pythoncom");
170
// see if pythoncom is already loaded
171
sprintf(dllpath, "pythoncom%02d.dll", getPyVersion());
172
gPythoncom = GetModuleHandleA(dllpath);
173
if (gPythoncom == NULL) {
174
sprintf(dllpath, "%spythoncom%02d.dll", here, getPyVersion());
176
gPythoncom = LoadLibraryExA( dllpath, // points to name of executable module
177
NULL, // HANDLE hFile, // reserved, must be NULL
178
LOAD_WITH_ALTERED_SEARCH_PATH // DWORD dwFlags // entry-point execution flag
182
VS("Pythoncom failed to load");
186
GetModuleFileNameA(gPythoncom, dllpath, _MAX_PATH);
189
Pyc_DllCanUnloadNow = (__PROC__DllCanUnloadNow)GetProcAddress(gPythoncom, "DllCanUnloadNow");
190
Pyc_DllGetClassObject = (__PROC__DllGetClassObject)GetProcAddress(gPythoncom, "DllGetClassObject");
191
// DllRegisterServerEx etc are mainly used for "scripts", so that regsvr32.exe can be run on
192
// a .py file, for example. They aren't really relevant here.
193
Pyc_DllRegisterServerEx = (__PROC__DllRegisterServerEx)GetProcAddress(gPythoncom, "DllRegisterServerEx");
194
Pyc_DllUnregisterServerEx = (__PROC__DllUnregisterServerEx)GetProcAddress(gPythoncom, "DllUnregisterServerEx");
195
PyCom_CoUninitialize = (__PROC__PyCom_CoUninitialize)GetProcAddress(gPythoncom, "PyCom_CoUninitialize");
196
if (Pyc_DllGetClassObject == NULL) {
197
VS("Couldn't get DllGetClassObject from pythoncom!");
200
if (PyCom_CoUninitialize == NULL) {
201
VS("Couldn't get PyCom_CoUninitialize from pythoncom!");
206
void releasePythonCom(void)
209
PyCom_CoUninitialize();
210
FreeLibrary(gPythoncom);
214
//__declspec(dllexport) int __stdcall DllCanUnloadNow(void)
215
//__declspec(dllexport)
217
HRESULT __stdcall DllCanUnloadNow(void)
221
VS("DllCanUnloadNow from thread %x", GetCurrentThreadId());
224
rc = Pyc_DllCanUnloadNow();
225
VS("DllCanUnloadNow returns %x", rc);
227
// PyCom_CoUninitialize();
231
//__declspec(dllexport) int __stdcall DllGetClassObject(void *rclsid, void *riid, void *ppv)
232
HRESULT __stdcall DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
236
VS("DllGetClassObject from thread %x", GetCurrentThreadId());
239
rc = Pyc_DllGetClassObject(rclsid, riid, ppv);
240
VS("DllGetClassObject set %x and returned %x", *ppv, rc);
245
__declspec(dllexport) int DllRegisterServerEx(LPCSTR fileName)
247
VS("DllRegisterServerEx from thread %x", GetCurrentThreadId());
250
return Pyc_DllRegisterServerEx(fileName);
253
__declspec(dllexport) int DllUnregisterServerEx(LPCSTR fileName)
257
return Pyc_DllUnregisterServerEx(fileName);
260
STDAPI DllRegisterServer()
265
PI_PyEval_AcquireThread(thisthread);
266
rc = callSimpleEntryPoint("DllRegisterServer", &pyrc);
267
PI_PyEval_ReleaseThread(thisthread);
268
return rc==0 ? pyrc : SELFREG_E_CLASS;
271
STDAPI DllUnregisterServer()
276
PI_PyEval_AcquireThread(thisthread);
277
rc = callSimpleEntryPoint("DllUnregisterServer", &pyrc);
278
PI_PyEval_ReleaseThread(thisthread);
279
return rc==0 ? pyrc : SELFREG_E_CLASS;