golang 交叉編譯C++ dll配置文件的實現(xiàn)
調(diào)用c++ 報%1 is not a valid Win32 application
開發(fā)環(huán)境:
win64位
C++ dll 為32位
首先遇到的坑就是環(huán)境的配置,調(diào)用了一個之前C++寫的dll,一直報錯:
%1 is not a valid Win32 application.
就懷疑是否是dll出了問題,使用C++調(diào)用,正常運行,排除dll的問題,然后懷疑是否是golang調(diào)用方法問題,這里簡要說一下golang調(diào)用dll的三種方法,使用了C語言編寫了一個最基本的dll,只包含helloword函數(shù)
void helloword(void) {
printf("Hello, World!\n");
}第一種,直接使用syscall庫調(diào)用,注意在用完后釋放
const HELLODLLPATH = `C:\gopath\src\helloword_dll\libhelloword.dll`
func Hello1() {
helloDll, e := syscall.LoadLibrary(HELLODLLPATH)
if e != nil {
panic(e)
}
helloword, e := syscall.GetProcAddress(helloDll, "helloword")
if e != nil {
panic(e)
}
_, _, er := syscall.Syscall(helloword, 0, 0, 0, 0)
if er != 0 {
panic(er)
}
e = syscall.FreeLibrary(helloDll)
if e != nil {
panic(e)
}
}第二種,使用syscall.NewLazyDLL()來調(diào)用,這種方式最為簡潔,后面主要使用這種方式
func Helloword2() {
helloDll := syscall.NewLazyDLL(HELLODLLPATH)
hello := helloDll.NewProc("helloword")
hello.Call()
}第三種,使用syscall.MustLoadDLL(),和第二種類似
func Helloword3() {
helloDll := syscall.MustLoadDLL(HELLODLLPATH)
hello := helloDll.MustFindProc("helloword")
_, _, _ = hello.Call()
}介紹完golang這三種調(diào)用dll的方式后,回到遇到的問題,采用這三種方式測試golang調(diào)用dll是否有問題,結(jié)果三種方式均成功調(diào)用,線索中斷,這個時候就只能懷疑最開始的dll和golang的是否匹配,通過查詢資料,發(fā)現(xiàn)之前的dll是32位,而golang的環(huán)境為amd64,此時通過goland設(shè)置編譯環(huán)境為386,并且把cgo打開
SET GOARCH=386 SET CGO_ENABLED=1
終于,成功調(diào)用!
第二個問題,就是調(diào)用dll的參數(shù)傳遞,這里用syscall.NewLazyDLL()來調(diào)用,目標(biāo)dll有一個識別圖像的方法,總共四個參數(shù),第一個是一個id,前面調(diào)用返回的,第二個是圖像數(shù)據(jù)指針,第三個圖像長度,第四個識別方式,返回是C語言字符串,具體調(diào)用如下
func IntPtr(n int) uintptr {
return uintptr(n)
}
func BytesPtr(s []byte) uintptr {
return uintptr(unsafe.Pointer(&s[0]))
}
func CnnDll2() {
cnnDll := syscall.NewLazyDLL(CNNDLLPATH)
//載入
CNN_init := cnnDll.NewProc("CNN_init")
bin := OpenBin()
id, _, _ := CNN_init.Call(BytesPtr(bin), IntPtr(len(bin)), 0, 0, IntPtr(2), IntPtr(5))
CNN_recognition := cnnDll.NewProc("CNN_recognition")
img := OpenImg()
//識別
ret, _, _ := CNN_recognition.Call(id, BytesPtr(img), IntPtr(len(img)), IntPtr(2))
var recode []byte
for i := 0; true; i++ {
tmp := *(*byte)(unsafe.Pointer(ret + uintptr(i)))
if tmp != 0 {
recode = append(recode, tmp)
} else {
break
}
}
fmt.Println("#ret", recode, string(recode))
}這里返回的字符串是C格式的,和golang的類型底層內(nèi)存模型不同,所以就是按照C的方式,移動指針,直到找到'\0',字符串結(jié)束,但是總覺得這種方式并非最好的方法,通過查詢資料,找到了自認(rèn)為比較科學(xué)的轉(zhuǎn)換方式,使用CGO的類型,如下
import "C" reStr := C.GoString((*C.char)(unsafe.Pointer(ret)))
C.GoString()的參數(shù)必須是 *C.char ,這里使用了cgo,正如前面所述,需開啟cgo環(huán)境
到此這篇關(guān)于golang 交叉編譯C++ dll配置文件的實現(xiàn)的文章就介紹到這了,更多相關(guān)golang 交叉編譯C++ dll配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang中多個線程和多個協(xié)程的使用區(qū)別小結(jié)
本文主要介紹了Golang中多個線程和多個協(xié)程的使用區(qū)別小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-06-06
go微服務(wù)PolarisMesh源碼解析服務(wù)端啟動流程
這篇文章主要為大家介紹了go微服務(wù)PolarisMesh源碼解析服務(wù)端啟動流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
golang語言如何將interface轉(zhuǎn)為int, string,slice,struct等類型
這篇文章主要介紹了golang語言如何將interface轉(zhuǎn)為int, string,slice,struct等類型,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12

