srcanamdw/codescanner/pyinstaller/source/windows/dllmain.c
changeset 1 22878952f6e2
equal deleted inserted replaced
0:509e4801c378 1:22878952f6e2
       
     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 }