У меня есть динамическая библиотека, из которой мне нужно вызывать процедуру в моей программе Go, но я не могу понять, что это правильно. У меня есть другая программа, написанная на C #, которая использует эту DLL и в соответствии с dnSpy dllimport компилирует в:
[DllImport("Library.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern void Calc(double[] Input, [MarshalAs(UnmanagedType.VBByRefStr)] ref string Pattern, [MarshalAs(UnmanagedType.VBByRefStr)] ref string Database_path, double[] Output);
Поэтому, основываясь на этом, я попытался назвать это в своем коде так:
func main() {
lib := syscall.NewLazyDLL("Library.dll")
proc := lib.NewProc("Calc")
input := [28]float64{0.741, 0.585, 2, 12, 1, 1, 1, 101325, 2500, 3, 20, 17.73, 17.11, 45, 1, 0, 80, 60, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0}
output := [20]float64{}
tubePattern := marshalAnsi("P8-16G-E145/028")
basePath, _ := filepath.Abs(".")
databasePath := marshalAnsi(basePath)
a1 := uintptr(unsafe.Pointer(&input))
a2 := uintptr(unsafe.Pointer(tubePattern))
a3 := uintptr(unsafe.Pointer(databasePath))
a4 := uintptr(unsafe.Pointer(&output))
ret, _, _ := proc.Call(a1, a2, a3, a4)
log.Println(ret)
log.Println(output)
}
func marshalAnsi(input string) *[]byte {
var b bytes.Buffer
writer := transform.NewWriter(&b, charmap.Windows1252.NewEncoder())
writer.Write([]byte(input))
writer.Close()
output := b.Bytes()
return &output
}
Это приводит к необработанному исключению delphi:
Exception 0xeedfade 0x31392774 0x32db04e4 0x7677ddc2
PC=0x7677ddc2
syscall.Syscall6(0x314af7d0, 0x4, 0x10ee7eb8, 0x10ed21a0, 0x10ed21d0, 0x10ee7d78, 0x0, 0x0, 0x0, 0x0, ...)
C:/Go32/src/runtime/syscall_windows.go:184 +0xcf
syscall.(*Proc).Call(0x10ed21e0, 0x10ed85e0, 0x4, 0x4, 0x10, 0x49bee0, 0x533801, 0x10ed85e0)
C:/Go32/src/syscall/dll_windows.go:152 +0x32e
syscall.(*LazyProc).Call(0x10ecb9c0, 0x10ed85e0, 0x4, 0x4, 0x0, 0x0, 0x4c6d70, 0x5491a0)
C:/Go32/src/syscall/dll_windows.go:302 +0x48
main.main()
C:/Users/Krzysztof Kowalczyk/go/src/danpoltherm.pl/dllloader/main.go:32 +0x2c0
eax 0x19f3f0
ebx 0x31392774
ecx 0x7
edx 0x0
edi 0x10ee7d78
esi 0x31392774
ebp 0x19f448
esp 0x19f3f0
eip 0x7677ddc2
eflags 0x216
cs 0x23
fs 0x53
gs 0x2b
Я полагаю, что проблема может заключаться в том, как я передаю эти строки в процедуру, но я не вижу, чем мой код отличается от этого приложения на C #.
В библиотеке есть несколько других процедур, я могу без проблем вызвать DLL_Version
:
lib := syscall.NewLazyDLL("Library.dll")
verProc := lib.NewProc("DLL_Version")
var version float64
verProc.Call(uintptr(unsafe.Pointer(&version)))
log.Printf("DLL version: %f\n", version)
Выходы:
2018/09/10 09:13:11 DLL version: 1.250000
EDIT:
Я считаю, что я выяснил, что вызывает исключение. Кажется, что при вызове из моего кода 2-й и 3-й параметры для этой процедуры, которые должны быть указателями на строковые буферы, вместо этого являются указателями на указатели на эти буферы, если я нарушу начало процедуры и исправлю это вручную, код запустится и завершается правильно. Я до сих пор не нашел причину, почему это происходит, и как это исправить.
EDIT2:
По-видимому, моя предыдущая оценка этого дела была неверной. Мне удалось остановить выдачу исключения программой, но я проанализировал сборку и оказалось, что это произошло только из-за выхода программы до того, как было сгенерировано это исключение, и вместо исключения я получил нормальный код ошибки о недопустимой строке.
Хотя я не очень хорошо разбираюсь в дизассемблированном коде, похоже, что проблема действительно может быть вызвана несоответствием соглашения о вызовах. В начале кода процедуры при вызове из рабочей программы регистры EAX, EBX, ECX и EDX пусты, а при вызове из моего кода только EAX и ECX пусты, EDX содержит что-то, но EBX указывает на указатель процедуры Calc в моем исполняемом файле. , Позже в DLL есть часть, которая проверяет, является ли EBX пустым, и выдает исключение, если нет.
РЕДАКТИРОВАТЬ 3:
Ну, это, кажется, также не связано, я знаю, что слишком мало информации, чтобы кто-либо мог догадаться о том, что происходит. Поэтому я постараюсь отследить, откуда именно возникло это исключение, и вернусь к этому вопросу.