使用wine从python ctypes调用标准windows .dll时出现分段错误



我试图在Linux上运行的Python脚本中从Kernel32.dll调用一些函数。正如Johannes Weiß指出的,如何在Linux上从python调用Wine dll ?我正在加载kernel32.dll。通过ctypes.cdll.LoadLibrary()加载。我可以看到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位)

乌利希期刊指南

我继续我的测试,并找到几个函数,我可以通过ctypes调用没有段错误。例如,我可以命名Beep()和GetCurrentThread()函数,许多其他函数仍然给我段错误。我创建了一个小C应用程序来测试kernel32.dll。没有python的库但我得到了基本相同的结果

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, "%sn", 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, "%sn", error);
      exit(1);
   }
   // Works
   x = (*GetCurrentThread)();   
   printf("Val x=%dn",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 Endn");
   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。所以file是一种代理,它应该为Linux代码提供对kernel32.dll的访问。可能我需要找到kernel32.dll的确切来源。因此,整理并查看一下声明。

有什么工具我可以用它来看看里面。so文件,找出什么函数和调用约定使用?

检查DLL最简单的方法是使用nm命令,即

$ nm kernel32.dll.so | grep GetLastError
7b86aae0 T _GetLastError

正如其他人指出的那样,Windows C dll的默认调用约定是stdcall。它与使用Python无关。在Windows平台上,ctypes.windll可用

然而,我甚至不确定你想做什么是在所有可能的。Wine是一个成熟的Windows模拟器,可以放心地猜测,至少在加载任何其他功能之前,您必须先使用wine_init启动它。Windows API可能有一些状态(在Windows启动时设置)。

最简单的方法可能是在Wine下安装Windows版本的Python并从那里运行脚本。

最新更新