golang 交叉編譯C++ dll配置文件的實(shí)現(xiàn)
調(diào)用c++ 報(bào)%1 is not a valid Win32 application
開發(fā)環(huán)境:
win64位
C++ dll 為32位
首先遇到的坑就是環(huán)境的配置,調(diào)用了一個(gè)之前C++寫的dll,一直報(bào)錯(cuò):
%1 is not a valid Win32 application.
就懷疑是否是dll出了問題,使用C++調(diào)用,正常運(yùn)行,排除dll的問題,然后懷疑是否是golang調(diào)用方法問題,這里簡(jiǎn)要說一下golang調(diào)用dll的三種方法,使用了C語言編寫了一個(gè)最基本的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)用,這種方式最為簡(jiǎn)潔,后面主要使用這種方式
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的方式后,回到遇到的問題,采用這三種方式測(cè)試golang調(diào)用dll是否有問題,結(jié)果三種方式均成功調(diào)用,線索中斷,這個(gè)時(shí)候就只能懷疑最開始的dll和golang的是否匹配,通過查詢資料,發(fā)現(xiàn)之前的dll是32位,而golang的環(huán)境為amd64,此時(shí)通過goland設(shè)置編譯環(huán)境為386,并且把cgo打開
SET GOARCH=386 SET CGO_ENABLED=1
終于,成功調(diào)用!
第二個(gè)問題,就是調(diào)用dll的參數(shù)傳遞,這里用syscall.NewLazyDLL()來調(diào)用,目標(biāo)dll有一個(gè)識(shí)別圖像的方法,總共四個(gè)參數(shù),第一個(gè)是一個(gè)id,前面調(diào)用返回的,第二個(gè)是圖像數(shù)據(jù)指針,第三個(gè)圖像長(zhǎng)度,第四個(gè)識(shí)別方式,返回是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()
//識(shí)別
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的方式,移動(dòng)指針,直到找到'\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配置文件的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang 交叉編譯C++ dll配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
提升Go語言開發(fā)效率的小技巧實(shí)例(GO語言語法糖)匯總
這篇文章主要介紹了提升Go語言開發(fā)效率的小技巧匯總,也就是Go語言的語法糖,掌握好這些可以提高我們的開發(fā)效率,需要的朋友可以參考下2022-11-11
Golang?HTTP服務(wù)超時(shí)控制實(shí)現(xiàn)原理分析
這篇文章主要介紹了Golang?HTTP服務(wù)超時(shí)控制實(shí)現(xiàn)原理,HTTP服務(wù)的超時(shí)控制是保障服務(wù)高可用性的重要措施之一,由于HTTP服務(wù)可能會(huì)遇到網(wǎng)絡(luò)延遲,資源瓶頸等問題,因此需要對(duì)請(qǐng)求進(jìn)行超時(shí)控制,以避免服務(wù)雪崩等問題,需要的朋友可以參考下2023-05-05
Golang?中的?strconv?包常用函數(shù)及用法詳解
strconv是Golang中一個(gè)非常常用的包,主要用于字符串和基本數(shù)據(jù)類型之間的相互轉(zhuǎn)換,這篇文章主要介紹了Golang中的strconv包,需要的朋友可以參考下2023-06-06
Go-RESTful實(shí)現(xiàn)下載功能思路詳解
這篇文章主要介紹了Go-RESTful實(shí)現(xiàn)下載功能,文件下載包括文件系統(tǒng)IO和網(wǎng)絡(luò)IO,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10
Go結(jié)合Gin導(dǎo)出Mysql數(shù)據(jù)到Excel表格
本文主要介紹了Go結(jié)合Gin導(dǎo)出Mysql數(shù)據(jù)到Excel表格,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08

