6

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 ファイルの内部を調べて、どの関数とどの呼び出し規則が使用されているかを調べるために使用できるツールはありますか?

4

1 に答える 1

0

DLL を調べる最も簡単な方法は、次のnmコマンドを使用することです。

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

他の人が指摘したように、Windows C DLL のデフォルトの呼び出し規約はstdcall. Python の使用とは関係ありません。Windows プラットフォームでctypes.windllは、 を使用できます。

しかし、あなたがやろうとしていることがまったく可能かどうかさえわかりません。Wine は本格的な Windows エミュレーターであり、少なくともwine_init他の関数をロードする前に、Wine から起動する必要があると推測できます。Windows API にはおそらく何らかの状態があります (Windows の起動時に設定されます)。

続行する最も簡単な方法は、おそらく Wine の下に Windows バージョンの Python をインストールし、そこからスクリプトを実行することです。

于 2014-02-24T22:47:45.113 に答える