Как передать указатель недействительного указателя на Windows DLL в Голанге (void**)
Я пытаюсь поэкспериментировать с загрузкой 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
}
0 ответов
Возможно, я здесь что-то не так, но когда я просто игнорирую ошибку, которую выдает мне 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! (len: 12) | код ошибки: 0 | dll ошибка вызова: операция завершена успешно.