windows - 如何在 Golang 中将 void 指针传递给 Windows DLL (void**)

标签 windows go chakra chakracore

我正在尝试使用 Golang 在 Windows 上加载 ChakraCore.dll,但我无法弄清楚我需要将什么参数类型作为第三个参数传递。

我阅读 library code 的假设并松散地遵循 Embedding ChakraCore是第三个参数需要是空指针指针 (void**),因为头文件将 JsRuntimeHandle 定义为 typedef void *JsRuntimeHandle;

如果可能的话,我也希望避免使用 CGo。

控制台输出:

panic: JsCreateRuntime failed: An argument to a hosting API was null in a context where null is not allowed. (JsErrorNullArgument)

代码:

package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

var (
    chakraCore, _        = syscall.LoadLibrary("ChakraCore.dll")
    jsCreateRuntime, _ = syscall.GetProcAddress(chakraCore, "JsCreateRuntime")
)

const (
    JsNoError = 0
    JsErrorNullArgument = 0x10002
)

const (
    JsRuntimeAttributeNone = 0x00000000
)

func main() {
    const functionName = "JsCreateRuntime"
    var runtime uintptr
    ret, _, err := syscall.Syscall(
       uintptr(jsCreateRuntime),
       3,
       uintptr(JsRuntimeAttributeNone),
       uintptr(0),
       uintptr(unsafe.Pointer(runtime)),
    )
    if err != 0 {
        panic(fmt.Sprintf("%s failed: %v", functionName, err))
    }
    switch (ret) {
    case JsNoError:
        break
    case JsErrorNullArgument:
        panic(fmt.Sprintf("%s failed: An argument to a hosting API was null in a context where null is not allowed. (JsErrorNullArgument)", functionName))
    default:
        panic(fmt.Sprintf("%s failed: Unhandled error kind (%v).", functionName, ret))
    }
    panic(fmt.Sprintf("runtime: %v | ret: %v\n", runtime, uint(ret)))
    return
}

最佳答案

我可能在这里出错了,但是当我忽略 Windows 给我的错误并继续前进时,一切似乎都执行得很好。

例如,如果我运行这个:

package main

import (
    "errors"
    "fmt"
    "syscall"
    "unsafe"
)

var (
    chakraCore, _        = syscall.LoadLibrary("ChakraCore.dll")
    jsCreateRuntime, _ = syscall.GetProcAddress(chakraCore, "JsCreateRuntime")
    jsCreateContext, _ = syscall.GetProcAddress(chakraCore, "JsCreateContext")
    jsSetCurrentContext, _ = syscall.GetProcAddress(chakraCore, "JsSetCurrentContext")
    jsRunScript, _ = syscall.GetProcAddress(chakraCore, "JsRunScript")
    jsConvertValueToString, _ = syscall.GetProcAddress(chakraCore, "JsConvertValueToString")
    jsStringToPointer, _ = syscall.GetProcAddress(chakraCore, "JsStringToPointer")
)

const (
    JsNoError = 0
    JsErrorInvalidArgument = 0x10001
    JsErrorNullArgument = 0x10002

    JsErrorScriptCompile = 0x30002
)

const (
    JsRuntimeAttributeNone = 0x00000000
)

var jsExample = `
(()=>{
    return 'Hello world!';}
)()
`

func main() {
    var runtime unsafe.Pointer
    var context unsafe.Pointer
    var jsResult unsafe.Pointer
    var resultJSString unsafe.Pointer
    {
        const functionName = "JsCreateRuntime"
        ret, _, err := syscall.Syscall(
           uintptr(jsCreateRuntime),
           3,
           uintptr(JsRuntimeAttributeNone),
           uintptr(0),
           uintptr(unsafe.Pointer(&runtime)),
        )
        // NOTE: Skip this error as it seems to be a false positive
        //if err != 0 {
        //  panic(fmt.Sprintf("%s invalid DLL call: %v", functionName, err))
        //}
        if err := getJSError(ret); err != nil {
            panic(fmt.Sprintf("%s failed: %s", functionName, err))
        }
        if runtime == nil {
            panic("Runtime should not be 0. I think.")
        }
        fmt.Print(fmt.Sprintf("%s: runtime: %v | error code: %v | dll call error: %v\n", functionName, runtime, ret, err))
    }
    {
        const functionName = "JsCreateContext"
        ret, _, err := syscall.Syscall(
            uintptr(jsCreateContext),
            2,
            uintptr(runtime),
            uintptr(unsafe.Pointer(&context)),
            uintptr(0),
        )
        if err := getJSError(ret); err != nil {
            panic(fmt.Sprintf("%s failed: %s", functionName, err))
        }
        fmt.Print(fmt.Sprintf("%s: context: %v | error code: %v | dll call error: %v\n", functionName, context, ret, err))
    }
    {
        const functionName = "JsSetCurrentContext"
        ret, _, err := syscall.Syscall(
            uintptr(jsSetCurrentContext),
            1,
            uintptr(context),
            uintptr(0),
            uintptr(0),
        )
        if err := getJSError(ret); err != nil {
            panic(fmt.Sprintf("%s failed: %s", functionName, err))
        }
        fmt.Print(fmt.Sprintf("%s: error code: %v | dll call error: %v\n", functionName, ret, err))
    }
    {
        const functionName = "JsRunScript"
        context := 1
        str, err := syscall.UTF16PtrFromString(jsExample)
        if err != nil {
            panic(err)
        }
        url, err := syscall.UTF16PtrFromString("")
        if err != nil {
            panic(err)
        }
        ret, _, err := syscall.Syscall6(
            uintptr(jsRunScript),
            4,
            uintptr(unsafe.Pointer(str)),
            uintptr(context),
            uintptr(unsafe.Pointer(url)),
            uintptr(unsafe.Pointer(&jsResult)),
            uintptr(0),
            uintptr(0),
        )
        if err := getJSError(ret); err != nil {
            panic(fmt.Sprintf("%s failed: %s", functionName, err))
        }
        fmt.Print(fmt.Sprintf("%s: js result: %v | error code: %v | dll call error: %v\n", functionName, jsResult, ret, err))
    }
    {
        const functionName = "JsConvertValueToString"
        ret, _, err := syscall.Syscall(
            uintptr(jsConvertValueToString),
            2,
            uintptr(jsResult),
            uintptr(unsafe.Pointer(&resultJSString)),
            uintptr(0),
        )
        if err := getJSError(ret); err != nil {
            panic(fmt.Sprintf("%s failed: %s", functionName, err))
        }
        fmt.Print(fmt.Sprintf("%s: js convert val to string: %v | error code: %v | dll call error: %v\n", functionName, resultJSString, ret, err))
    }
    {
        const functionName = "JsStringToPointer"
        var utf16StringData *[0xffff]uint16
        var stringLen uintptr
        ret, _, err := syscall.Syscall(
            uintptr(jsStringToPointer),
            3,
            uintptr(resultJSString),
            uintptr(unsafe.Pointer(&utf16StringData)),
            uintptr(unsafe.Pointer(&stringLen)),
        )
        if err := getJSError(ret); err != nil {
            panic(fmt.Sprintf("%s failed: %s", functionName, err))
        }
        cStrData := syscall.UTF16ToString(utf16StringData[0 : stringLen])
        fmt.Print(fmt.Sprintf("%s: js string: %s (len: %v) | error code: %v | dll call error: %v\n", functionName, cStrData, stringLen, ret, err))
    }
    return
}

func getJSError(errorCode uintptr) error {
    switch (errorCode) {
    case JsNoError:
        return nil
    case JsErrorInvalidArgument:
        return errors.New("An argument to a hosting API was invalid. (JsErrorInvalidArgument)")
    case JsErrorNullArgument:
        return errors.New("An argument to a hosting API was null in a context where null is not allowed. (JsErrorNullArgument)")
    case JsErrorScriptCompile:
        return errors.New("JavaScript failed to compile. (JsErrorScriptCompile)")
    default:
       return fmt.Errorf("Unhandled error kind (%v).", errorCode)
    }
}

我在控制台中得到以下输出:

JsCreateRuntime: runtime: 0x3bd3310 | error code: 0 | dll call error: The parameter is incorrect.

JsCreateContext: context: 0x3ce2000 | error code: 0 | dll call error: The operation completed successfully.

JsSetCurrentContext: error code: 0 | dll call error: The operation completed successfully.

JsRunScript: js result: 0x3d00ac0 | error code: 0 | dll call error: The operation completed successfully.

JsConvertValueToString: js convert val to string: 0x3d00ac0 | error code: 0 | dll call error: The operation completed successfully.

JsStringToPointer: js string: Hello world! (len: 12) | error code: 0 | dll call error: The operation completed successfully.

关于windows - 如何在 Golang 中将 void 指针传递给 Windows DLL (void**),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56272558/

相关文章:

list - 如何在 Go 中获取映射键的排序列表?

javascript - IE 9's Javascript engine (code-named "Chakra 的 ProgId 或 CLSID 是什么”)

windows - 如何在 Komodo 7.1 中启用 mysql 支持?

c++ - 如何测量亚秒级持续时间?

windows - wmic cpu get LoadPercentage 总是返回空值

javascript - IE9 中的 JScript 版本是什么?

javascript - JXcore 可以在 Windows 7 上与 ChakraCore 一起使用吗?

windows - AF_UNIX 等效于 Windows

angularjs - Golang 一请求多响应

go - 如何查询具有部分键值的表