Segfault调用标准windows .dll从python ctypes与wine

And*_*nko 6 python linux ctypes wine segmentation-fault

我正试图在我在Linux上运行的Python脚本中调用Kernel32.dll中的某些函数.正如JohannesWeiß所指出的如何在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
Run Code Online (Sandbox Code Playgroud)

首先,我在考虑调用约定差异,但毕竟它似乎没问题.我结束了测试简单函数GetLastError函数没有任何参数,但我仍然得到Segmentation故障.

我的测试系统是Ubuntu 12.10,Python 2.7.3和wine-1.4.1(一切都是32位)

UPD

我继续我的测试,并找到几个我可以通过ctypes调用而没有segfault的函数.例如,我可以命名Beep()和GetCurrentThread()函数,许多其他函数仍然给我segfault.我创建了一个小的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;
}
Run Code Online (Sandbox Code Playgroud)

我试图为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 
Run Code Online (Sandbox Code Playgroud)

然而,其中一些有效,有些则无效.据我所知,这些来源是针对kernel32.dll文件和kernel32.dll.so文件是某种代理,它应该为linux代码提供对kernel32.dll的访问.可能我需要找到kernel32.dll.so文件的确切来源并查看声明.

是否有任何工具可以用来查看.so文件,找出哪些函数和使用的调用约定?

Kru*_*lur 0

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

\n\n
$ nm kernel32.dll.so |\xc2\xa0grep GetLastError\n7b86aae0 T _GetLastError\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

但是,我什至不确定您正在尝试做的事情是否可能。Wine 是一个成熟的 Windows 模拟器,可以肯定地猜测,至少您必须使用以下命令启动它:wine_init在加载任何其他功能之前启动它。Windows API 可能有某种状态(Windows 启动时设置)。

\n\n

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

\n