2013-01-21 21 views
6

Próbuję wywołać jakąś funkcję z Kernel32.dll w moim skrypcie Pythona działającym pod Linuksem. Jak Johannes Weiß wskazał How to call Wine dll from python on Linux? ładuję bibliotekę kernel32.dll.so przez ctypes.cdll.LoadLibrary() i ładuje się dobrze. Widzę załadowany kernel32, a nawet ma wewnątrz funkcję GetLastError(). Jednak za każdym razem, gdy próbuję wywołać funkcję I'm gettings segfault.Segfault na wywołanie standardowego okna .dll z python ctypes z winem

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 

Najpierw myślałem o wywołaniu różnic w konwencjach, ale mimo wszystko wydaje się być w porządku. Kończę testowaniem prostej funkcji GetLastError bez żadnych parametrów, ale i tak nadal otrzymuję błąd Segmentacji.

moim systemie testowym jest Ubuntu 12.10, Python 2.7.3 i 1.4.1 wina (wszystko jest 32bit)

UPD

mogę kontynuować moje badania i znaleźć kilka funkcji, które mogę nazwać za pośrednictwem ctypes bez segfault. Na przykład mogę wymienić funkcje Beep() i GetCurrentThread(), wiele innych funkcji nadal daje mi segfault. Stworzyłem małą aplikację C do testowania biblioteki kernel32.dll.so bez pythona, ale mam zasadniczo takie same wyniki.

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; 
} 

Próbowałem użyć różnych konwencji wywoływania dla funkcji uśpienia(), ale nie miałem z tym szczęścia. Kiedy porównując deklaracje funkcji \ wdrożenie w źródłach wina są zasadniczo takie same

Deklaracje

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 

Jednak niektóre z nich działa, a niektóre nie. Jak mogę zrozumieć, te źródła są przeznaczone dla pliku kernel32.dll, a plik kernel32.dll.so jest rodzajem proxy, które ma zapewniać dostęp do kernel32.dll dla kodu linuxowego. Prawdopodobnie muszę znaleźć dokładne źródła pliku kernel32.dll.so i zapoznać się z deklaracjami.

Czy jest jakieś narzędzie, za pomocą którego można zajrzeć do pliku .so i dowiedzieć się, jakie funkcje i jakie konwencje są używane?

+0

Nie jestem zaznajomiony z Wine, ale uważam, że ten problem ma coś wspólnego z konwencjami wywołującymi, http://en.wikipedia.org/wiki/X86_calling_conventions, dla tych funkcji. Większość 'kernel32.dll' używa' stdcall'.Możesz spróbować wywołać niektóre funkcje z 'msvcrt.dll' lub' ws2_32.dll', większość jego funkcji używa 'cdecl', nie dostaniesz segfault. Zajrzyj tutaj, http://codepad.org/DzX33DYz. –

+0

@Sp. Dzięki, znalazłem kilka funkcji, które mogę wywołać z kernel32.dll.to moje własne. Jednak nie mogę znaleźć żadnej różnicy między nimi a funkcjami, których potrzebuję w moim kodzie. Czy mógłbyś zaproponować mi jakieś narzędzie, aby znaleźć konwencje wywoływania funkcji wewnątrz pliku .so? –

+0

Używam programu IDA pro, jest to bardzo przydatne w tej pracy. –

Odpowiedz

0

Najprostszym sposobem zbadania DLL jest użycie komendy nm, tj

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

Jak inni zwrócili uwagę, domyślny dla Windows konwencja wywoływania C DLL jest stdcall. Nie ma nic wspólnego z używaniem Pythona. Na platformie Windows jest dostępny ctypes.windll.

Jednak, Nie jestem nawet pewien, co próbujesz zrobić, jest w ogóle możliwe. Wine jest pełnoobszarowym emulatorem Windows i można bezpiecznie zgadnąć, że przynajmniej musisz go uruchomić z wine_init przed załadowaniem jakichkolwiek innych funkcji. Prawdopodobnie system Windows API ma pewien stan (ustawiony przy uruchamianiu systemu Windows).

Najprostszym sposobem kontynuacji jest prawdopodobnie zainstalowanie wersji Pythona dla Windows pod Wine i uruchomienie tam skryptu.