我试图在 Linux 上运行的 Python 脚本中从 Kernel32.dll 调用一些函数。正如 Johannes Weiß 指出的如何在 Linux 上从 python 调用 Wine dll?我正在通过ctypes.cdll.LoadLibrary()加载kernel32.dll.so库,并且加载正常。我可以看到 kernel32 已加载,甚至内部还有GetLastError()函数。但是,每当我尝试调用该函数时,我都会遇到段错误。
import ctypes
kernel32 = ctypes.cdll.LoadLibrary('/usr/lib/i386-linux-gnu/wine/kernel32.dll.so')
print kernel32
# <CDLL '/usr/lib/i386-linux-gnu/wine/kernel32.dll.so', handle 8843c10 at b7412e8c>
print kernel32.GetLastError
# <_FuncPtr object at 0xb740b094>
gle = kernel32.GetLastError
# OK
gle_result = gle()
# fails with
# Segmentation fault (core dumped)
print gle_result
首先,我正在考虑调用约定差异,但毕竟它似乎没问题。我以测试没有任何参数的简单函数 GetLastError 函数结束,但无论如何我仍然遇到分段错误。
我的测试系统是 Ubuntu 12.10、Python 2.7.3 和 wine-1.4.1(都是 32 位的)
UPD
我继续我的测试并找到了几个可以通过 ctypes 调用而没有段错误的函数。例如我可以命名 Beep() 和 GetCurrentThread() 函数,许多其他函数仍然给我段错误。我创建了一个小型 C 应用程序来测试没有 python 的 kernel32.dll.so 库,但我得到了基本相同的结果。
int main(int argc, char **argv)
{
void *lib_handle;
#define LOAD_LIBRARY_AS_DATAFILE 0x00000002
long (*GetCurrentThread)(void);
long (*beep)(long,long);
void (*sleep)(long);
long (*LoadLibraryExA)(char*, long, long);
long x;
char *error;
lib_handle = dlopen("/usr/local/lib/wine/kernel32.dll.so", RTLD_LAZY);
if (!lib_handle)
{
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
// All the functions are loaded e.g. sleep != NULL
GetCurrentThread = dlsym(lib_handle, "GetCurrentThread");
beep = dlsym(lib_handle, "Beep");
LoadLibraryExA = dlsym(lib_handle, "LoadLibraryExA");
sleep = dlsym(lib_handle, "Sleep");
if ((error = dlerror()) != NULL)
{
fprintf(stderr, "%s\n", error);
exit(1);
}
// Works
x = (*GetCurrentThread)();
printf("Val x=%d\n",x);
// Works (no beeping, but no segfault too)
(*beep)(500,500);
// Segfault
(*sleep)(5000);
// Segfault
(*LoadLibraryExA)("/home/ubuntu/test.dll",0,LOAD_LIBRARY_AS_DATAFILE);
printf("The End\n");
dlclose(lib_handle);
return 0;
}
我试图对 Sleep() 函数使用不同的调用约定,但也没有运气。当我比较 Wine 源代码中的函数声明\实现时,它们本质上是相同的
声明
HANDLE WINAPI GetCurrentThread(void) // http://source.winehq.org/source/dlls/kernel32/thread.c#L573
BOOL WINAPI Beep( DWORD dwFreq, DWORD dwDur ) // http://source.winehq.org/source/dlls/kernel32/console.c#L354
HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) // http://source.winehq.org/source/dlls/kernel32/module.c#L928
VOID WINAPI DECLSPEC_HOTPATCH Sleep( DWORD timeout ) // http://source.winehq.org/source/dlls/kernel32/sync.c#L95
WINAPI is defined to be __stdcall
然而,其中一些有效,而另一些则无效。据我所知,这个来源是用于 kernel32.dll 文件,而 kernel32.dll.so 文件是某种代理,它应该为 linux 代码提供对 kernel32.dll 的访问。可能我需要找到 kernel32.dll.so 文件的确切来源并查看声明。
有什么工具可以用来查看 .so 文件并找出使用了哪些函数和调用约定?