You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
7.2 KiB
252 lines
7.2 KiB
|
|
/* Support for dynamic loading of extension modules */ |
|
|
|
#include "Python.h" |
|
|
|
#ifdef MS_XBOX |
|
#include <xtl.h> |
|
#else |
|
#include <windows.h> |
|
#endif |
|
#include <direct.h> |
|
#include <ctype.h> |
|
|
|
#include "importdl.h" |
|
|
|
const struct filedescr _PyImport_DynLoadFiletab[] = { |
|
#ifdef _DEBUG |
|
{"_d.pyd", "rb", C_EXTENSION}, |
|
{"_d.dll", "rb", C_EXTENSION}, |
|
#else |
|
{".pyd", "rb", C_EXTENSION}, |
|
{".dll", "rb", C_EXTENSION}, |
|
#endif |
|
{0, 0} |
|
}; |
|
|
|
|
|
/* Case insensitive string compare, to avoid any dependencies on particular |
|
C RTL implementations */ |
|
|
|
static int strcasecmp (char *string1, char *string2) |
|
{ |
|
int first, second; |
|
|
|
do { |
|
first = tolower(*string1); |
|
second = tolower(*string2); |
|
string1++; |
|
string2++; |
|
} while (first && first == second); |
|
|
|
return (first - second); |
|
} |
|
|
|
|
|
/* Function to return the name of the "python" DLL that the supplied module |
|
directly imports. Looks through the list of imported modules and |
|
returns the first entry that starts with "python" (case sensitive) and |
|
is followed by nothing but numbers until the separator (period). |
|
|
|
Returns a pointer to the import name, or NULL if no matching name was |
|
located. |
|
|
|
This function parses through the PE header for the module as loaded in |
|
memory by the system loader. The PE header is accessed as documented by |
|
Microsoft in the MSDN PE and COFF specification (2/99), and handles |
|
both PE32 and PE32+. It only worries about the direct import table and |
|
not the delay load import table since it's unlikely an extension is |
|
going to be delay loading Python (after all, it's already loaded). |
|
|
|
If any magic values are not found (e.g., the PE header or optional |
|
header magic), then this function simply returns NULL. */ |
|
|
|
#define DWORD_AT(mem) (*(DWORD *)(mem)) |
|
#define WORD_AT(mem) (*(WORD *)(mem)) |
|
|
|
static char *GetPythonImport (HINSTANCE hModule) |
|
{ |
|
unsigned char *dllbase, *import_data, *import_name; |
|
DWORD pe_offset, opt_offset; |
|
WORD opt_magic; |
|
int num_dict_off, import_off; |
|
|
|
/* Safety check input */ |
|
if (hModule == NULL) { |
|
return NULL; |
|
} |
|
|
|
/* Module instance is also the base load address. First portion of |
|
memory is the MS-DOS loader, which holds the offset to the PE |
|
header (from the load base) at 0x3C */ |
|
dllbase = (unsigned char *)hModule; |
|
pe_offset = DWORD_AT(dllbase + 0x3C); |
|
|
|
/* The PE signature must be "PE\0\0" */ |
|
if (memcmp(dllbase+pe_offset,"PE\0\0",4)) { |
|
return NULL; |
|
} |
|
|
|
/* Following the PE signature is the standard COFF header (20 |
|
bytes) and then the optional header. The optional header starts |
|
with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+ |
|
uses 64-bits for some fields). It might also be 0x107 for a ROM |
|
image, but we don't process that here. |
|
|
|
The optional header ends with a data dictionary that directly |
|
points to certain types of data, among them the import entries |
|
(in the second table entry). Based on the header type, we |
|
determine offsets for the data dictionary count and the entry |
|
within the dictionary pointing to the imports. */ |
|
|
|
opt_offset = pe_offset + 4 + 20; |
|
opt_magic = WORD_AT(dllbase+opt_offset); |
|
if (opt_magic == 0x10B) { |
|
/* PE32 */ |
|
num_dict_off = 92; |
|
import_off = 104; |
|
} else if (opt_magic == 0x20B) { |
|
/* PE32+ */ |
|
num_dict_off = 108; |
|
import_off = 120; |
|
} else { |
|
/* Unsupported */ |
|
return NULL; |
|
} |
|
|
|
/* Now if an import table exists, offset to it and walk the list of |
|
imports. The import table is an array (ending when an entry has |
|
empty values) of structures (20 bytes each), which contains (at |
|
offset 12) a relative address (to the module base) at which a |
|
string constant holding the import name is located. */ |
|
|
|
if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) { |
|
import_data = dllbase + DWORD_AT(dllbase + |
|
opt_offset + |
|
import_off); |
|
while (DWORD_AT(import_data)) { |
|
import_name = dllbase + DWORD_AT(import_data+12); |
|
if (strlen(import_name) >= 6 && |
|
!strncmp(import_name,"python",6)) { |
|
char *pch; |
|
|
|
/* Ensure python prefix is followed only |
|
by numbers to the end of the basename */ |
|
pch = import_name + 6; |
|
while (*pch && *pch != '.') { |
|
if (*pch >= '0' && *pch <= '9') { |
|
pch++; |
|
} else { |
|
pch = NULL; |
|
break; |
|
} |
|
} |
|
|
|
if (pch) { |
|
/* Found it - return the name */ |
|
return import_name; |
|
} |
|
} |
|
import_data += 20; |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
|
|
dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, |
|
const char *pathname, FILE *fp) |
|
{ |
|
#ifdef MS_XBOX |
|
return NULL; |
|
#else |
|
dl_funcptr p; |
|
char funcname[258], *import_python; |
|
|
|
PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname); |
|
|
|
{ |
|
HINSTANCE hDLL = NULL; |
|
char pathbuf[260]; |
|
LPTSTR dummy; |
|
/* We use LoadLibraryEx so Windows looks for dependent DLLs |
|
in directory of pathname first. However, Windows95 |
|
can sometimes not work correctly unless the absolute |
|
path is used. If GetFullPathName() fails, the LoadLibrary |
|
will certainly fail too, so use its error code */ |
|
if (GetFullPathName(pathname, |
|
sizeof(pathbuf), |
|
pathbuf, |
|
&dummy)) |
|
/* XXX This call doesn't exist in Windows CE */ |
|
hDLL = LoadLibraryEx(pathname, NULL, |
|
LOAD_WITH_ALTERED_SEARCH_PATH); |
|
if (hDLL==NULL){ |
|
char errBuf[256]; |
|
unsigned int errorCode; |
|
|
|
/* Get an error string from Win32 error code */ |
|
char theInfo[256]; /* Pointer to error text |
|
from system */ |
|
int theLength; /* Length of error text */ |
|
|
|
errorCode = GetLastError(); |
|
|
|
theLength = FormatMessage( |
|
FORMAT_MESSAGE_FROM_SYSTEM, /* flags */ |
|
NULL, /* message source */ |
|
errorCode, /* the message (error) ID */ |
|
0, /* default language environment */ |
|
(LPTSTR) theInfo, /* the buffer */ |
|
sizeof(theInfo), /* the buffer size */ |
|
NULL); /* no additional format args. */ |
|
|
|
/* Problem: could not get the error message. |
|
This should not happen if called correctly. */ |
|
if (theLength == 0) { |
|
PyOS_snprintf(errBuf, sizeof(errBuf), |
|
"DLL load failed with error code %d", |
|
errorCode); |
|
} else { |
|
size_t len; |
|
/* For some reason a \r\n |
|
is appended to the text */ |
|
if (theLength >= 2 && |
|
theInfo[theLength-2] == '\r' && |
|
theInfo[theLength-1] == '\n') { |
|
theLength -= 2; |
|
theInfo[theLength] = '\0'; |
|
} |
|
strcpy(errBuf, "DLL load failed: "); |
|
len = strlen(errBuf); |
|
strncpy(errBuf+len, theInfo, |
|
sizeof(errBuf)-len); |
|
errBuf[sizeof(errBuf)-1] = '\0'; |
|
} |
|
PyErr_SetString(PyExc_ImportError, errBuf); |
|
return NULL; |
|
} else { |
|
char buffer[256]; |
|
|
|
PyOS_snprintf(buffer, sizeof(buffer), "python%d%d.dll", |
|
PY_MAJOR_VERSION,PY_MINOR_VERSION); |
|
import_python = GetPythonImport(hDLL); |
|
|
|
if (import_python && |
|
strcasecmp(buffer,import_python)) { |
|
PyOS_snprintf(buffer, sizeof(buffer), |
|
"Module use of %.150s conflicts " |
|
"with this version of Python.", |
|
import_python); |
|
PyErr_SetString(PyExc_ImportError,buffer); |
|
FreeLibrary(hDLL); |
|
return NULL; |
|
} |
|
} |
|
p = GetProcAddress(hDLL, funcname); |
|
} |
|
|
|
return p; |
|
#endif |
|
}
|
|
|