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