PonyLang Windows CreateProcess FFI
我一直在尝试从小马语言的FFI调用Window的PonyLang Windows CreateProcess FFI,windows,ffi,pony,ponylang,Windows,Ffi,Pony,Ponylang,我一直在尝试从小马语言的FFI调用Window的CreateProcessA 我创建了一个C和一个Ponelang示例。C示例非常有用: #include <windows.h> #include <stdio.h> #include <tchar.h> void wmain(void) { STARTUPINFO info={0}; PROCESS_INFORMATION processInfo={0}; CreateProces
CreateProcessA
我创建了一个C和一个Ponelang示例。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
}
因此,上面的代码为PonyLang编译,但大部分时间返回2。有时GetLastError
返回123。其他时候它返回998?
有时错误代码是不同的,这似乎很奇怪。这些代码都意味着文件访问有问题
Calc.exe
位于当前目录中(与c示例相同的目录)
此外,不仅错误代码不同,而且calc.exe在C版本中执行(运行正常),而在PonyLang版本中不执行。这让我相信我的蓬莱ffi设置出了问题
有人知道可能出了什么问题吗 问题在于您使用的
addressof
。当您创建一个struct
对象时,例如使用var si=StartupInfo
,底层类型是指向该结构的指针(例如,Pony中的struct
s没有值语义)。然后,当您使用addressof
调用CreateProcessA
时,实际上是在传递一个指向函数指针的指针
如果您的C函数需要一个指向结构的指针,那么在执行FFI调用时,您只需传递Pony对象而无需
addressof
。问题在于使用addressof
。当您创建一个struct
对象时,例如使用var si=StartupInfo
,底层类型是指向该结构的指针(例如,Pony中的struct
s没有值语义)。然后,当您使用addressof
调用CreateProcessA
时,实际上是在传递一个指向函数指针的指针
如果您的C函数需要指向结构的指针,则在执行FFI调用时,只需传递Pony对象,而无需
addressof
。您的C代码与PonyLang代码有相同的错误,并且只能在巧合的情况下工作。您必须检查CreateProcess的返回值以确定是否发生了错误。只有在发生错误时,调用GetLastError()来确定错误代码才有意义。如果没有发生错误,GetLastError()可能会返回任何内容,但不保证返回零。对,但是C显示calc.exe,而PonyLang则显示nothing。谢谢你的提示。我将检查返回值。看起来您假设BOOL
是一种8位类型,实际上是32位,这可能是造成问题的原因?(CreateProcess的两个参数也是指针类型的,所以如果您碰巧正在构建一个64位应用程序,它们将需要64位而不是32位。)FWIW,代码998明确表示某种参数错误,它与文件访问无关。(您确定=“”.cstring
会导致字段被初始化为空指针吗?),所以你可以看到你正在做的调用实际上看起来像Windows。你的C代码和你的Ponelang代码有相同的bug,只是巧合。您必须检查CreateProcess的返回值以确定是否发生了错误。只有在发生错误时,调用GetLastError()来确定错误代码才有意义。如果没有发生错误,GetLastError()可能会返回任何内容,但不保证返回零。对,但是C显示calc.exe,而PonyLang则显示nothing。谢谢你的提示。我将检查返回值。看起来您假设BOOL
是一种8位类型,实际上是32位,这可能是造成问题的原因?(CreateProcess的两个参数也是指针类型的,所以如果您碰巧正在构建一个64位应用程序,它们将需要64位而不是32位。)FWIW,代码998明确表示某种参数错误,它与文件访问无关。(您确定=“”.cstring
会导致字段被初始化为空指针吗?)也许您可以编写一个小型的C DLL,导出一个与CreateProcess具有相同签名的函数,然后调用它,这样您就可以看到您正在进行的调用实际上与Windows类似。感谢您提供的提示。然而我现在收到错误123,这意味着类似于以前的错误(无效文件名等)。MSDN提到此字段是结构的地址(本身不是指针)。如果你提到小马不能通过混凝土结构;我应该用一个简单的接口创建自己的dll并调用它吗?是的,实现一个shim C层可能会更容易。小马FFI仍然非常简单,不适合处理复杂的API。谢谢你的提示。然而我现在收到错误123,这意味着类似于以前的错误(无效文件名等)。MSDN提到此字段是结构的地址(本身不是指针)。如果你提到小马不能通过混凝土结构;我应该用一个简单的接口创建自己的dll并调用它吗?是的,实现一个shim C层可能会更容易。Pony FFI仍然非常简单,不适合处理复杂的API。
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