信息: 在写完全文之后,我遇到了some other SO post,又尝试了一次,它才起作用。但是,由于对我来说解决方案(甚至是问题)一点都不明显(并且编写此问题的工作量很大),因此我决定仍然将此文本与解决方案一起发布。希望这对some developer coming across this post in the future有帮助。
由于我对SO还很陌生,所以我真的不知道这是否值得赞赏,所以随时让我知道将其删除。
TLDR:
我正在尝试调用DLL,该DLL需要一个字符串参数并返回一个字符串。我尝试了几种无济于事的解决方案和方法。最后-偶然-我发现问题出在传递字符串的方式上。
我的解决方法是:
imagePath := "*30 C:\\absolute\\path\\to\\test.png"
bytePath := []byte(imagePath + "\x00") // Make string null-terminated (required by C)
dll := syscall.NewLazyDLL("ImageSearchDLL.dll")
imageSearch := dll.NewProc("ImageSearch")
r1, _, _ := imageSearch.Call(
0,
0,
1920,
1080,
uintptr(unsafe.Pointer(&bytePath[0]))) // Make sure to pass index 0
// DLL returned char*, parse that to a GoString
var s string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
hdr.Data = uintptr(unsafe.Pointer(r1))
hdr.Len = 32 // Adjust length as needed!
fmt.Println(s)
char*
和C.CString
可能以某种方式将C.GoString
解析为字符串并反向,我无法在足够短的时间内完成该工作,所以我决定保持这种方式。
还应该检查字符串的长度(由\ x00终止)。
我还很陌生,但是想在下一个桌面自动化项目中使用它。为此,我正在尝试查找显示器中存在的图像。 由于找不到任何能够执行此操作的go库,因此我决定尝试使用几年前Autoit经验中已知的DLL:DLL Download Source Code
但是,经过数小时的尝试找到解决方案(包括the wiki)之后,我无法正常工作。
库/函数本身具有以下签名:
char* WINAPI ImageSearch(int aLeft, int aTop, int aRight, int aBottom, char *aImageFile)
由于我对C一点都不熟悉,因此我尝试了提出的其他两种解决方案:
path := "*30 C:\\absolute\\path\\to\\test.png"
dll := syscall.NewLazyDLL("ImageSearchDLL.dll")
imageSearch := dll.NewProc("ImageSearch")
r1, r2, r3 := imageSearch.Call(0, 0, 1920, 1080, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(imagePath))))
fmt.Println(r1, r2, r3)
和:
path := "*30 C:\\absolute\\path\\to\\test.png"
dll2, _ := syscall.LoadLibrary("ImageSearchDLL.dll")
imageSearch2, _ := syscall.GetProcAddress(dll2, "ImageSearch")
r1, r2, r3 = syscall.Syscall6(imageSearch2,
5,
uintptr(0),
uintptr(0),
uintptr(1920),
uintptr(1920),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(imagePath))),
0)
fmt.Println(r1, r2, r3)
请注意,路径变量是根据this solution using C#设置的。
两者的输出如下:
6442522512 0 Der Vorgang wurde erfolgreich beendet.
含义:“该过程已成功完成”。
由于DLL应该返回一个char*
,所以我打开了documentation of unsafe并找到了Pointer>(6)。使用猜测的字符串长度,我想出了这个尝试:
imagePath := "*30 C:\\absolute\\path\\to\\test.png"
dll := syscall.NewLazyDLL("ImageSearchDLL.dll")
imageSearch := dll.NewProc("ImageSearch")
r1, r2, r3 := imageSearch.Call(0, 0, 1920, 1080, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(imagePath))))
fmt.Println(r1, r2, r3)
var s string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
hdr.Data = uintptr(unsafe.Pointer(r1))
hdr.Len = 64
fmt.Println(s)
这至少可以打印出某种字符串:
6442522512 0 Der Vorgang wurde erfolgreich beendet.
0 0 0 0 0 1|%d|%d|%d|%d 0 c:\pic.bmp
据我了解,该问题可能是由3种可能的问题引起的:
char*
的解析不起作用由于我必须了解如何处理2和3,因此我至少想确保不是1。因此,我在Autoit中进行了快速测试,返回了预期的结果:
#include "array.au3"
$res = DllCall("ImageSearchDLL.dll", "str", "ImageSearch", "int", 0, "int", 0, "int", 1920, "int", 1080, "str", "*30 C:\\absolute\\path\\to\\test.png")
_ArrayDisplay($res)
输出:
Row|Col 0
[0]|1|505|1051|21|20
[1]|0
[2]|0
[3]|1920
[4]|1080
[5]|*30 C:\\absolute\\path\\to\\test.png
这使我充满信心,至少可以正确使用dll。但是,这也导致我真的对其他尝试一无所知。看看cgo时,我并没有真正了解要如何实现自己想要实现的目标,尤其是在没有C知识的情况下。
您对我的进一步方法有什么建议吗?还有什么可以尝试的?