2017-02-14 75 views
1

我一直在嘗試從Pony Language的FFI調用Window的CreateProcessAPonyLang Windows創建進程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上完美無瑕。 然而,我PonyLang實現不斷返回非零GetLastError

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.有時GetLastError回報123將返回998其他時間? 有時候,錯誤代碼有些不同,這似乎很奇怪。這些代碼都意味着文件訪問存在一些問題?

Calc.exe位於當前目錄(與c示例相同的目錄)。

不僅錯誤代碼不同,而且calc.exe在C版本中執行(運行正常),但不在PonyLang版本中執行。這讓我相信我的PonyLang ffi設置有些問題。

有誰知道什麼可能是錯的?

+0

您的C代碼與您的PonyLang代碼具有相同的錯誤,並且只能巧合使用。您必須檢查CreateProcess的返回值以確定是否發生錯誤。只有*如果發生錯誤,調用GetLastError()來確定錯誤代碼是很有意義的。如果沒有發生錯誤,GetLastError()可能會返回任何內容,但不保證返回零。 –

+0

對,但C顯示calc.exe而PonyLang,什麼也沒有。謝謝你的提示。我會檢查返回值。 – efel

+0

它看起來像你假設'BOOL'是一個8位類型,它實際上是32位,也許這是造成麻煩? (也有一些CreateProcess的參數是指針類型的,所以如果你碰巧正在構建一個64位應用程序,它們將需要64位而不是32位。) –

回答

3

問題出在您使用addressof。當您創建一個struct對象時,例如與var si = StartupInfo一樣,基礎類型是指向該結構的指針(即在小馬中沒有價值語義)。然後當你調用CreateProcessAaddressof時,你實際上將一個指針傳遞給函數的指針。

如果你的C函數需要一個指向結構體的指針,那麼你可以在執行FFI調用時簡單地傳遞沒有addressof的Pony對象。

+0

謝謝你的提示。然而;即時獲取錯誤123現在意味着類似於以前的錯誤(無效的文件名稱等)。 MSDN提到這個字段是一個結構的地址(本身不是一個指針)。如果你提到小馬不能通過具體結構,我應該用一個簡單的界面創建我自己的dll並打電話給那裏? – efel

+0

是的,實現一個墊片C層可能會更容易。 Pony FFI仍然非常簡陋,不適合使用複雜的API。 –