Linux で実行されている Python スクリプトで、Kernel32.dll から関数を呼び出そうとしています。Johannes Weiß が指摘したように、Linux で Python から Wine dll を呼び出す方法は? ctypes.cdll.LoadLibrary()を介してkernel32.dll.soライブラリをロードしていますが、正常にロードされます。kernel32 がロードされており、内部にGetLastError()関数が含まれていることも確認できます。ただし、関数を呼び出そうとするたびに、segfault が発生します。
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
テストを進めて、segfault なしで ctypes を介して呼び出すことができるいくつかの関数を見つけました。たとえば、Beep() および GetCurrentThread() 関数に名前を付けることができますが、他の多くの関数でも segfault が発生します。Python を使用せずに kernel32.dll.so ライブラリをテストする小さな C アプリケーションを作成しましたが、基本的に同じ結果が得られました。
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 ファイルの内部を調べて、どの関数とどの呼び出し規則が使用されているかを調べるために使用できるツールはありますか?