2017-02-14 12 views
1

저는 Pony Language의 FFI에서 Window의 CreateProcessA을 호출하려고했습니다.PonyLang Windows CreateProcess FFI

나는 C와 PonyLang 예제를 만들었습니다. C 예제는 훌륭하게 작동합니다 :

#include <windows.h> 
#include <stdio.h> 
#include <tchar.h> 

void wmain(void) { 
    STARTUPINFO info={0}; 
    PROCESS_INFORMATION processInfo={0}; 

    CreateProcessA("calc.exe", 0, 0, 0, 0, 0, 0, 0, &info, &processInfo); 

    if (status == 0) 
     printf("%d",GetLastError()); // never hits 

} 

calc.exe을 현재 디렉토리에 넣었습니다. 이것은 Windows에서 완벽하게 작동합니다.

use "lib:kernel32" 

primitive _ProcessAttributes 
primitive _ThreadAttributes 
primitive _Inherit 
primitive _Creation 
primitive _Environment 
primitive _CurrentDir 
primitive _StartupInfo 
primitive _ProcessInfo 

primitive _HandleIn 
primitive _HandleOut 
primitive _HandleErr 

primitive _Thread 
primitive _Process 

struct StartupInfo 
    var cb:I32 = 0 
    var lpReserved:Pointer[U8] tag= "".cstring() 
    var lpDesktop:Pointer[U8] tag= "".cstring() 
    var lpTitle:Pointer[U8] tag= "".cstring() 
    var dwX:I32 = 0 
    var dwY:I32 = 0 
    var dwXSize:I32=0 
    var dwYSize:I32=0 
    var dwXCountChars:I32=0 
    var dwYCountChars:I32=0 
    var dwFillAttribute:I32=0 
    var dwFlags:I32=0 
    var wShowWindow:I16=0 
    var cbReserved2:I16=0 
    var lpReserved2:Pointer[U8] tag="".cstring() 
    var hStdInput:Pointer[_HandleIn] = Pointer[_HandleIn] 
    var hStdOutput:Pointer[_HandleOut]= Pointer[_HandleOut] 
    var hStdError:Pointer[_HandleErr]= Pointer[_HandleErr] 

struct ProcessInfo 
    var hProcess:Pointer[_Process] = Pointer[_Process] 
    var hThread:Pointer[_Thread] = Pointer[_Thread] 
    var dwProcessId:I32 = 0 
    var dwThreadId:I32 = 0 


//var si:StartupInfo = StartupInfo 

actor Main 
    new create(env: Env) => 
    var si: StartupInfo = StartupInfo 
    var pi: ProcessInfo = ProcessInfo 
    var inherit:I8 = 0 
    var creation:I32 = 0 
    var one:I32 = 0 
    var two:I32 = 0 
    var three:I32 = 0 
    var four:I32 = 0 
    var z:I32 = 0 

    var p = @CreateProcessA[I8]("calc.exe", 
    z, 
    one, 
    two, 
    inherit, 
    creation, 
    three, 
    four, 
    addressof si, 
    addressof pi) 

    if p == 0 then 
     var err = @GetLastError[I32]() // hits this every time. 
     env.out.print("Last Error: " + err.string()) 
    end 

그래서 위의 코드 PonyLang에 대한 컴파일하지만 GetLastError 대부분의 시간 2. 때로는 998을 반환 GetLastError 수익률 123 다른 시간을 반환 는하지만, 내 PonyLang 구현은 0이 아닌 GetLastError을 반환에 계속? 오류 코드가 다른 경우가 있습니다. 이러한 코드는 모두 파일 액세스에 문제가 있음을 의미합니다.

Calc.exe은 현재 디렉토리 (예제와 동일한 디렉토리)에 있습니다.

또한 오류 코드가 다르지만 calc.exe는 C 버전에서는 실행되지만 PonyLang 버전에서는 실행되지 않습니다 (정상적으로 실행 됨). 이것은 내 PonyLang ffi 설정으로 뭔가가 떨어져 있다고 믿게합니다.

무엇이 잘못되었을 지 알고 계십니까?

+0

C 코드는 PonyLang 코드와 동일한 버그가 있으며 우연히 만 작동합니다. 오류가 발생했는지 여부를 확인하려면 CreateProcess의 반환 값을 확인해야합니다. * if * 오류가 발생한 경우에만 GetLastError()를 호출하여 오류 코드를 확인하는 것이 좋습니다. 오류가 발생하지 않은 경우 GetLastError()는 아무 것도 반환하지 않을 수도 있지만 0을 반환하지는 않습니다. –

+0

맞지만 C는 calc.exe를 표시하지만 PonyLang은 아무것도 표시하지 않습니다. 팁을 가져 주셔서 감사합니다. 반환 값을 확인하겠습니다. – efel

+0

'BOOL'이 8 비트 타입이라고 가정하고있는 것처럼 보입니다. 실제로 32 비트가되어 문제가 생길 수 있습니다. (또한 CreateProcess에 대한 몇 가지 인수는 포인터 유형이므로 64 비트 응용 프로그램을 빌드하는 경우 32 비트가 아닌 64 비트가 필요합니다. –

답변

3

문제는 addressof을 사용하는 것입니다. struct 개체를 만들 때 (예 : var si = StartupInfo으로 기본 유형은 구조에 대한 포인터입니다 (예 : 포니의 struct에는 값 의미가 없습니다). 그런 다음 CreateProcessAaddressof으로 호출하면 실제로 포인터를 함수에 전달합니다.

C 함수가 구조체에 대한 포인터를 예상하는 경우 FFI 호출을 수행 할 때 addressof없이 포니 개체를 전달하면됩니다.

+0

팁 주셔서 감사합니다. 하나; 메신저 123 오류가 지금은 이전 오류 (잘못된 파일 이름 등)와 비슷한 것을 의미합니다. MSDN은이 필드가 구조체 (자체 포인터가 아님)에 대한 주소임을 언급합니다. 포니가 콘크리트 구조체를 전달할 수 없다는 것을 언급하면; 난 그냥 쉬운 인터페이스와 내 자신의 DLL을 만들고 거기에 전화해야합니까? – efel

+0

예, 심층 C 레이어를 구현하는 것이 더 쉬울 것입니다. 조랑말 FFI는 여전히 매우 베어 본이지만 복잡한 API를 사용하는 것은 이상적이지 않습니다. –