|
1 /* |
|
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. |
|
5 * |
|
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. |
|
10 * |
|
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.) |
|
18 * |
|
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. |
|
23 * |
|
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 |
|
27 */ |
|
28 #include "launch.h" |
|
29 #include <windows.h> |
|
30 #include <olectl.h> |
|
31 |
|
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; |
|
42 |
|
43 HINSTANCE gPythoncom = 0; |
|
44 char here[_MAX_PATH + 1]; |
|
45 int LoadPythonCom(void); |
|
46 void releasePythonCom(void); |
|
47 HINSTANCE gInstance; |
|
48 PyThreadState *thisthread = NULL; |
|
49 |
|
50 int launch(char const * archivePath, char const * archiveName) |
|
51 { |
|
52 PyObject *obHandle; |
|
53 int loadedNew = 0; |
|
54 char pathnm[_MAX_PATH]; |
|
55 |
|
56 VS("START"); |
|
57 strcpy(pathnm, archivePath); |
|
58 strcat(pathnm, archiveName); |
|
59 /* Set up paths */ |
|
60 if (setPaths(archivePath, archiveName)) |
|
61 return -1; |
|
62 VS("Got Paths"); |
|
63 /* Open the archive */ |
|
64 if (openArchive()) |
|
65 return -1; |
|
66 VS("Opened Archive"); |
|
67 /* Load Python DLL */ |
|
68 if (attachPython(&loadedNew)) |
|
69 return -1; |
|
70 |
|
71 if (loadedNew) { |
|
72 /* Start Python with silly command line */ |
|
73 PyEval_InitThreads(); |
|
74 if (startPython(1, (char**)&pathnm)) |
|
75 return -1; |
|
76 VS("Started new Python"); |
|
77 thisthread = PyThreadState_Swap(NULL); |
|
78 PyThreadState_Swap(thisthread); |
|
79 } |
|
80 else { |
|
81 VS("Attached to existing Python"); |
|
82 |
|
83 /* start a mew interp */ |
|
84 thisthread = PyThreadState_Swap(NULL); |
|
85 PyThreadState_Swap(thisthread); |
|
86 if (thisthread == NULL) { |
|
87 thisthread = Py_NewInterpreter(); |
|
88 VS("created thisthread"); |
|
89 } |
|
90 else |
|
91 VS("grabbed thisthread"); |
|
92 PyRun_SimpleString("import sys;sys.argv=[]"); |
|
93 } |
|
94 |
|
95 /* a signal to scripts */ |
|
96 PyRun_SimpleString("import sys;sys.frozen='dll'\n"); |
|
97 VS("set sys.frozen"); |
|
98 /* Create a 'frozendllhandle' as a counterpart to |
|
99 sys.dllhandle (which is the Pythonxx.dll handle) |
|
100 */ |
|
101 obHandle = Py_BuildValue("i", gInstance); |
|
102 PySys_SetObject("frozendllhandle", obHandle); |
|
103 Py_XDECREF(obHandle); |
|
104 /* Import modules from archive - this is to bootstrap */ |
|
105 if (importModules()) |
|
106 return -1; |
|
107 VS("Imported Modules"); |
|
108 /* Install zlibs - now import hooks are in place */ |
|
109 if (installZlibs()) |
|
110 return -1; |
|
111 VS("Installed Zlibs"); |
|
112 /* Run scripts */ |
|
113 if (runScripts()) |
|
114 return -1; |
|
115 VS("All scripts run"); |
|
116 if (PyErr_Occurred()) { |
|
117 // PyErr_Print(); |
|
118 //PyErr_Clear(); |
|
119 VS("Some error occurred"); |
|
120 } |
|
121 VS("PGL released"); |
|
122 // Abandon our thread state. |
|
123 PyEval_ReleaseThread(thisthread); |
|
124 VS("OK."); |
|
125 return 0; |
|
126 } |
|
127 void startUp() |
|
128 { |
|
129 char thisfile[_MAX_PATH + 1]; |
|
130 char *p; |
|
131 int len; |
|
132 |
|
133 if (!GetModuleFileNameA(gInstance, thisfile, _MAX_PATH)) { |
|
134 FATALERROR("System error - unable to load!"); |
|
135 return; |
|
136 } |
|
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); |
|
141 *++p = '\0'; |
|
142 len = p - here; |
|
143 //VS(here); |
|
144 //VS(&thisfile[len]); |
|
145 launch(here, &thisfile[len]); |
|
146 LoadPythonCom(); |
|
147 // Now Python is up and running (any scripts have run) |
|
148 } |
|
149 |
|
150 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) |
|
151 { |
|
152 char msg[40]; |
|
153 |
|
154 if ( dwReason == DLL_PROCESS_ATTACH) { |
|
155 sprintf(msg, "Attach from thread %x", GetCurrentThreadId()); |
|
156 VS(msg); |
|
157 gInstance = hInstance; |
|
158 } |
|
159 else if ( dwReason == DLL_PROCESS_DETACH ) { |
|
160 VS("Process Detach"); |
|
161 //if (gPythoncom) |
|
162 // releasePythonCom(); |
|
163 //finalizePython(); |
|
164 } |
|
165 |
|
166 return TRUE; |
|
167 } |
|
168 |
|
169 int LoadPythonCom() |
|
170 { |
|
171 char dllpath[_MAX_PATH+1]; |
|
172 VS("Loading Pythoncom"); |
|
173 // see if pythoncom is already loaded |
|
174 sprintf(dllpath, "pythoncom%02d.dll", getPyVersion()); |
|
175 gPythoncom = GetModuleHandle(dllpath); |
|
176 if (gPythoncom == NULL) { |
|
177 sprintf(dllpath, "%spythoncom%02d.dll", here, getPyVersion()); |
|
178 //VS(dllpath); |
|
179 gPythoncom = LoadLibraryEx( dllpath, // points to name of executable module |
|
180 NULL, // HANDLE hFile, // reserved, must be NULL |
|
181 LOAD_WITH_ALTERED_SEARCH_PATH // DWORD dwFlags // entry-point execution flag |
|
182 ); |
|
183 } |
|
184 if (!gPythoncom) { |
|
185 VS("Pythoncom failed to load"); |
|
186 return -1; |
|
187 } |
|
188 // debugging |
|
189 GetModuleFileNameA(gPythoncom, dllpath, _MAX_PATH); |
|
190 VS(dllpath); |
|
191 |
|
192 Pyc_DllCanUnloadNow = (__PROC__DllCanUnloadNow)GetProcAddress(gPythoncom, "DllCanUnloadNow"); |
|
193 Pyc_DllGetClassObject = (__PROC__DllGetClassObject)GetProcAddress(gPythoncom, "DllGetClassObject"); |
|
194 // DllRegisterServerEx etc are mainly used for "scripts", so that regsvr32.exe can be run on |
|
195 // a .py file, for example. They aren't really relevant here. |
|
196 Pyc_DllRegisterServerEx = (__PROC__DllRegisterServerEx)GetProcAddress(gPythoncom, "DllRegisterServerEx"); |
|
197 Pyc_DllUnregisterServerEx = (__PROC__DllUnregisterServerEx)GetProcAddress(gPythoncom, "DllUnregisterServerEx"); |
|
198 PyCom_CoUninitialize = (__PROC__PyCom_CoUninitialize)GetProcAddress(gPythoncom, "PyCom_CoUninitialize"); |
|
199 if (Pyc_DllGetClassObject == NULL) { |
|
200 VS("Couldn't get DllGetClassObject from pythoncom!"); |
|
201 return -1; |
|
202 } |
|
203 if (PyCom_CoUninitialize == NULL) { |
|
204 VS("Couldn't get PyCom_CoUninitialize from pythoncom!"); |
|
205 return -1; |
|
206 } |
|
207 return 0; |
|
208 } |
|
209 void releasePythonCom(void) |
|
210 { |
|
211 if (gPythoncom) { |
|
212 PyCom_CoUninitialize(); |
|
213 FreeLibrary(gPythoncom); |
|
214 gPythoncom = 0; |
|
215 } |
|
216 } |
|
217 //__declspec(dllexport) int __stdcall DllCanUnloadNow(void) |
|
218 //__declspec(dllexport) |
|
219 //STDAPI |
|
220 HRESULT __stdcall DllCanUnloadNow(void) |
|
221 { |
|
222 char msg[80]; |
|
223 HRESULT rc; |
|
224 |
|
225 sprintf(msg, "DllCanUnloadNow from thread %x", GetCurrentThreadId()); |
|
226 VS(msg); |
|
227 if (gPythoncom == 0) |
|
228 startUp(); |
|
229 rc = Pyc_DllCanUnloadNow(); |
|
230 sprintf(msg, "DllCanUnloadNow returns %x", rc); |
|
231 VS(msg); |
|
232 //if (rc == S_OK) |
|
233 // PyCom_CoUninitialize(); |
|
234 return rc; |
|
235 } |
|
236 |
|
237 //__declspec(dllexport) int __stdcall DllGetClassObject(void *rclsid, void *riid, void *ppv) |
|
238 HRESULT __stdcall DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) |
|
239 { |
|
240 char msg[80]; |
|
241 HRESULT rc; |
|
242 sprintf(msg, "DllGetClassObject from thread %x", GetCurrentThreadId()); |
|
243 VS(msg); |
|
244 if (gPythoncom == 0) |
|
245 startUp(); |
|
246 rc = Pyc_DllGetClassObject(rclsid, riid, ppv); |
|
247 sprintf(msg, "DllGetClassObject set %x and returned %x", *ppv, rc); |
|
248 VS(msg); |
|
249 return rc; |
|
250 } |
|
251 |
|
252 __declspec(dllexport) int DllRegisterServerEx(LPCSTR fileName) |
|
253 { |
|
254 char msg[40]; |
|
255 sprintf(msg, "DllRegisterServerEx from thread %x", GetCurrentThreadId()); |
|
256 VS(msg); |
|
257 if (gPythoncom == 0) |
|
258 startUp(); |
|
259 return Pyc_DllRegisterServerEx(fileName); |
|
260 } |
|
261 |
|
262 __declspec(dllexport) int DllUnregisterServerEx(LPCSTR fileName) |
|
263 { |
|
264 if (gPythoncom == 0) |
|
265 startUp(); |
|
266 return Pyc_DllUnregisterServerEx(fileName); |
|
267 } |
|
268 |
|
269 STDAPI DllRegisterServer() |
|
270 { |
|
271 int rc, pyrc; |
|
272 if (gPythoncom == 0) |
|
273 startUp(); |
|
274 PyEval_AcquireThread(thisthread); |
|
275 rc = callSimpleEntryPoint("DllRegisterServer", &pyrc); |
|
276 PyEval_ReleaseThread(thisthread); |
|
277 return rc==0 ? pyrc : SELFREG_E_CLASS; |
|
278 } |
|
279 |
|
280 STDAPI DllUnregisterServer() |
|
281 { |
|
282 int rc, pyrc; |
|
283 if (gPythoncom == 0) |
|
284 startUp(); |
|
285 PyEval_AcquireThread(thisthread); |
|
286 rc = callSimpleEntryPoint("DllUnregisterServer", &pyrc); |
|
287 PyEval_ReleaseThread(thisthread); |
|
288 return rc==0 ? pyrc : SELFREG_E_CLASS; |
|
289 } |