PageRenderTime 124ms CodeModel.GetById 90ms app.highlight 14ms RepoModel.GetById 16ms app.codeStats 0ms

/Python/dynload_win.c

http://unladen-swallow.googlecode.com/
C | 274 lines | 170 code | 40 blank | 64 comment | 41 complexity | 43b5ff1e4f596d744b871de59cbf23ed MD5 | raw file
  1
  2/* Support for dynamic loading of extension modules */
  3
  4#include "Python.h"
  5
  6#ifdef HAVE_DIRECT_H
  7#include <direct.h>
  8#endif
  9#include <ctype.h>
 10
 11#include "importdl.h"
 12#include <windows.h>
 13
 14// "activation context" magic - see dl_nt.c...
 15extern ULONG_PTR _Py_ActivateActCtx();
 16void _Py_DeactivateActCtx(ULONG_PTR cookie);
 17
 18const struct filedescr _PyImport_DynLoadFiletab[] = {
 19#ifdef _DEBUG
 20	{"_d.pyd", "rb", C_EXTENSION},
 21#else
 22	{".pyd", "rb", C_EXTENSION},
 23#endif
 24	{0, 0}
 25};
 26
 27
 28/* Case insensitive string compare, to avoid any dependencies on particular
 29   C RTL implementations */
 30
 31static int strcasecmp (char *string1, char *string2)
 32{ 
 33	int first, second;
 34
 35	do {
 36		first  = tolower(*string1);
 37		second = tolower(*string2);
 38		string1++;
 39		string2++;
 40	} while (first && first == second);
 41
 42	return (first - second);
 43} 
 44
 45
 46/* Function to return the name of the "python" DLL that the supplied module
 47   directly imports.  Looks through the list of imported modules and
 48   returns the first entry that starts with "python" (case sensitive) and
 49   is followed by nothing but numbers until the separator (period).
 50
 51   Returns a pointer to the import name, or NULL if no matching name was
 52   located.
 53
 54   This function parses through the PE header for the module as loaded in
 55   memory by the system loader.  The PE header is accessed as documented by
 56   Microsoft in the MSDN PE and COFF specification (2/99), and handles
 57   both PE32 and PE32+.  It only worries about the direct import table and
 58   not the delay load import table since it's unlikely an extension is
 59   going to be delay loading Python (after all, it's already loaded).
 60
 61   If any magic values are not found (e.g., the PE header or optional
 62   header magic), then this function simply returns NULL. */
 63
 64#define DWORD_AT(mem) (*(DWORD *)(mem))
 65#define WORD_AT(mem)  (*(WORD *)(mem))
 66
 67static char *GetPythonImport (HINSTANCE hModule)
 68{
 69	unsigned char *dllbase, *import_data, *import_name;
 70	DWORD pe_offset, opt_offset;
 71	WORD opt_magic;
 72	int num_dict_off, import_off;
 73
 74	/* Safety check input */
 75	if (hModule == NULL) {
 76		return NULL;
 77	}
 78
 79	/* Module instance is also the base load address.  First portion of
 80	   memory is the MS-DOS loader, which holds the offset to the PE
 81	   header (from the load base) at 0x3C */
 82	dllbase = (unsigned char *)hModule;
 83	pe_offset = DWORD_AT(dllbase + 0x3C);
 84
 85	/* The PE signature must be "PE\0\0" */
 86	if (memcmp(dllbase+pe_offset,"PE\0\0",4)) {
 87		return NULL;
 88	}
 89
 90	/* Following the PE signature is the standard COFF header (20
 91	   bytes) and then the optional header.  The optional header starts
 92	   with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+
 93	   uses 64-bits for some fields).  It might also be 0x107 for a ROM
 94	   image, but we don't process that here.
 95
 96	   The optional header ends with a data dictionary that directly
 97	   points to certain types of data, among them the import entries
 98	   (in the second table entry). Based on the header type, we
 99	   determine offsets for the data dictionary count and the entry
100	   within the dictionary pointing to the imports. */
101
102	opt_offset = pe_offset + 4 + 20;
103	opt_magic = WORD_AT(dllbase+opt_offset);
104	if (opt_magic == 0x10B) {
105		/* PE32 */
106		num_dict_off = 92;
107		import_off   = 104;
108	} else if (opt_magic == 0x20B) {
109		/* PE32+ */
110		num_dict_off = 108;
111		import_off   = 120;
112	} else {
113		/* Unsupported */
114		return NULL;
115	}
116
117	/* Now if an import table exists, offset to it and walk the list of
118	   imports.  The import table is an array (ending when an entry has
119	   empty values) of structures (20 bytes each), which contains (at
120	   offset 12) a relative address (to the module base) at which a
121	   string constant holding the import name is located. */
122
123	if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) {
124		/* We have at least 2 tables - the import table is the second
125		   one.  But still it may be that the table size is zero */
126		if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD)))
127			return NULL;
128		import_data = dllbase + DWORD_AT(dllbase +
129						 opt_offset +
130						 import_off);
131		while (DWORD_AT(import_data)) {
132			import_name = dllbase + DWORD_AT(import_data+12);
133			if (strlen(import_name) >= 6 &&
134			    !strncmp(import_name,"python",6)) {
135				char *pch;
136
137				/* Ensure python prefix is followed only
138				   by numbers to the end of the basename */
139				pch = import_name + 6;
140#ifdef _DEBUG
141				while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') {
142#else
143				while (*pch && *pch != '.') {
144#endif
145					if (*pch >= '0' && *pch <= '9') {
146						pch++;
147					} else {
148						pch = NULL;
149						break;
150					}
151				}
152	    
153				if (pch) {
154					/* Found it - return the name */
155					return import_name;
156				}
157			}
158			import_data += 20;
159		}
160	}
161
162	return NULL;
163}
164
165
166dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
167				    const char *pathname, FILE *fp)
168{
169	dl_funcptr p;
170	char funcname[258], *import_python;
171
172	PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname);
173
174	{
175		HINSTANCE hDLL = NULL;
176		char pathbuf[260];
177		LPTSTR dummy;
178		unsigned int old_mode;
179		ULONG_PTR cookie = 0;
180		/* We use LoadLibraryEx so Windows looks for dependent DLLs 
181		    in directory of pathname first.  However, Windows95
182		    can sometimes not work correctly unless the absolute
183		    path is used.  If GetFullPathName() fails, the LoadLibrary
184		    will certainly fail too, so use its error code */
185
186		/* Don't display a message box when Python can't load a DLL */
187		old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
188
189		if (GetFullPathName(pathname,
190				    sizeof(pathbuf),
191				    pathbuf,
192				    &dummy)) {
193			ULONG_PTR cookie = _Py_ActivateActCtx();
194			/* XXX This call doesn't exist in Windows CE */
195			hDLL = LoadLibraryEx(pathname, NULL,
196					     LOAD_WITH_ALTERED_SEARCH_PATH);
197			_Py_DeactivateActCtx(cookie);
198		}
199
200		/* restore old error mode settings */
201		SetErrorMode(old_mode);
202
203		if (hDLL==NULL){
204			char errBuf[256];
205			unsigned int errorCode;
206
207			/* Get an error string from Win32 error code */
208			char theInfo[256]; /* Pointer to error text
209					      from system */
210			int theLength; /* Length of error text */
211
212			errorCode = GetLastError();
213
214			theLength = FormatMessage(
215				FORMAT_MESSAGE_FROM_SYSTEM |
216				FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */
217				NULL, /* message source */
218				errorCode, /* the message (error) ID */
219				0, /* default language environment */
220				(LPTSTR) theInfo, /* the buffer */
221				sizeof(theInfo), /* the buffer size */
222				NULL); /* no additional format args. */
223
224			/* Problem: could not get the error message.
225			   This should not happen if called correctly. */
226			if (theLength == 0) {
227				PyOS_snprintf(errBuf, sizeof(errBuf),
228				      "DLL load failed with error code %d",
229					      errorCode);
230			} else {
231				size_t len;
232				/* For some reason a \r\n
233				   is appended to the text */
234				if (theLength >= 2 &&
235				    theInfo[theLength-2] == '\r' &&
236				    theInfo[theLength-1] == '\n') {
237					theLength -= 2;
238					theInfo[theLength] = '\0';
239				}
240				strcpy(errBuf, "DLL load failed: ");
241				len = strlen(errBuf);
242				strncpy(errBuf+len, theInfo,
243					sizeof(errBuf)-len);
244				errBuf[sizeof(errBuf)-1] = '\0';
245			}
246			PyErr_SetString(PyExc_ImportError, errBuf);
247			return NULL;
248		} else {
249			char buffer[256];
250
251#ifdef _DEBUG
252			PyOS_snprintf(buffer, sizeof(buffer), "python%d%d_d.dll",
253#else
254			PyOS_snprintf(buffer, sizeof(buffer), "python%d%d.dll",
255#endif
256				      PY_MAJOR_VERSION,PY_MINOR_VERSION);
257			import_python = GetPythonImport(hDLL);
258
259			if (import_python &&
260			    strcasecmp(buffer,import_python)) {
261				PyOS_snprintf(buffer, sizeof(buffer),
262					      "Module use of %.150s conflicts "
263					      "with this version of Python.",
264					      import_python);
265				PyErr_SetString(PyExc_ImportError,buffer);
266				FreeLibrary(hDLL);
267				return NULL;
268			}
269		}
270		p = GetProcAddress(hDLL, funcname);
271	}
272
273	return p;
274}