gpt4 book ai didi

delphi - 第 3 方 dll 中未处理的 delphi 异常

转载 作者:IT王子 更新时间:2023-10-29 02:09:11 27 4
gpt4 key购买 nike

我有一个动态库,我需要从中调用我的 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

编辑:我相信我发现了导致异常的原因。似乎从我的代码调用时,此过程的第二个和第三个参数应该是指向字符串缓冲区的指针,而不是指向这些缓冲区上的指针的指针,如果我在过程的开头中断并手动修补它,代码运行并且正确终止。我仍然没有找到发生这种情况的原因,也没有找到解决方法。

编辑2:显然我之前对这个案例的评估是无效的。我能够阻止程序抛出异常,但我分析了程序集,结果发现这只是由于程序在抛出异常之前退出,而不是异常我得到了关于无效字符串的正常错误代码。

虽然我不太擅长理解反汇编代码,但看起来问题确实可能是由调用约定不匹配引起的。在过程代码的开头,当从工作程序调用时,EAX、EBX、ECX 和 EDX 寄存器为空,同时从我的代码调用时,只有 EAX 和 ECX 为空,EDX 保存一些东西,但 EBX 指向我的可执行文件中的 Calc 过程指针.稍后在 DLL 中有一部分检查 EBX 是否为空,如果不是则抛出异常。

编辑 3:好吧,这似乎也无关紧要,我知道信息太少,任何人都无法猜测发生了什么。因此,我将尝试准确跟踪此异常的来源,然后回到这个问题。

最佳答案

好的,所以我终于找到了答案。正如@kostix 所注意到的,go-ole 是必需的,因为 DLL 使用 COM 并且我必须先调用 CoInitializeEx。

但这只是其中的一部分,事实证明过程的字符串参数被声明为 UnicodeString,这需要我将一个转换函数放在一起以正确适应文档中描述的布局:http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Unicode_in_RAD_Studio#New_String_Type:_UnicodeString

一旦完成,一切都开始按预期工作。

关于delphi - 第 3 方 dll 中未处理的 delphi 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52253015/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com