Как передать указатель недействительного указателя на Windows DLL в Голанге (void **) - PullRequest
0 голосов
/ 23 мая 2019

Я пытаюсь поэкспериментировать с загрузкой ChakraCore.dll в Windows с помощью Golang, но у меня возникают проблемы с определением, какой тип параметра мне нужно передать в качестве третьего параметра.

Мое предположениеиз чтения библиотечного кода и свободного следования Embedded ChakraCore заключается в том, что третьим параметром должен быть указатель на пустой указатель (void **), поскольку заголовочные файлы определяют JsRuntimeHandle как typedef void *JsRuntimeHandle;

Я также надеюсь избежать CGo, если это возможно.

Вывод на консоль:

паника: сбой JsCreateRuntime: аргумент дляAPI хостинга был нулевым в контексте, где ноль не разрешен.(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
}

1 Ответ

0 голосов
/ 02 июня 2019

Возможно, я что-то здесь не так понял, но когда я просто игнорирую ошибку, которую мне выдает 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: время выполнения: 0x3bd3310 | код ошибки: 0 | Ошибка вызова DLL: Неверный параметр.

JsCreateContext: context: 0x3ce2000 | код ошибки: 0 | Ошибка вызова DLL: операция успешно завершена.

JsSetCurrentContext: код ошибки: 0 | Ошибка вызова DLL: операция успешно завершено.

JsRunScript: js результат: 0x3d00ac0 | ошибка код: 0 | Ошибка вызова DLL: операция успешно завершена.

JsConvertValueToString: js преобразует val в строку: 0x3d00ac0 | ошибка код: 0 | Ошибка вызова DLL: операция успешно завершена.

JsStringToPointer: js string: Hello world! (лен: 12) | код ошибки: 0 | Ошибка вызова DLL: операция успешно завершена.

...