CGO 之 Dll调用
生成的dll库代码
// GoDll.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include <iostream> #include <cstdint> void __stdcall void_R0() { std::cout << __FUNCTION__ << std::endl; } void __stdcall void_R1(const char* name) { std::cout << __FUNCTION__ << " ----> " << name << std::endl; } void __stdcall void_R2(const char*name ,char **outName) { std::string _name = "HintSoft 新浩艺-"; _name += name; strcpy(*outName,_name.c_str()); } uint8_t __stdcall uint8_R1(char** outJson) { *outJson = new char[256]; memset(*outJson,0,256); strcpy(*outJson,"Hello -> 你被骗了,这里没有Json,只有中文"); return 1; } void __stdcall uint8_R1_free(char** outJson) { if(outJson == 0) return; if(*outJson == 0) return; delete [](*outJson); *outJson = nullptr; } typedef void (*CallBackFunType)(const char * in); void setCallBackFun(CallBackFunType func) { if(!func) { std::cout << __FUNCTION__ << " NULL ptr" << std::endl; } func("hello CallBackFuncType ---- setCallBackFun"); }
导出函数def,vs里新建一个*.def后缀名的文件,添加下面:
EXPORTS void_R0 @1 void_R1 @2 void_R2 @3 uint8_R1 @4 uint8_R1_free @5 setCallBackFun @6
go调用测试:
package main import ( "fmt" "syscall" "unsafe" ) /* #include <stdio.h> // 如果要调用C.free 一定要在些包含对应的头文件 #include <stdlib.h> // 以下两种方式任选其一 void CallBackFun( char* in); //void CallBackFun( char* in) //{ // printf("%s\r\n",in); //} */ import "C" // export 必须要 //export CallBackFun func CallBackFun(in *C.char) { fmt.Print(C.GoString(in)) } func main() { fmt.Println("---------------------------------------------------------------") handle, err := syscall.LoadDLL("GoDll.dll") if err != nil { fmt.Println(err.Error()) return } fmt.Println(handle.Handle) fmt.Println(handle.Name) void_R0, err := handle.FindProc("void_R0") if err != nil { fmt.Println("void_R0 不存在", err.Error()) return } void_R1, err := handle.FindProc("void_R1") if err != nil { fmt.Println("void_R1 不存在", err.Error()) return } void_R2, err := handle.FindProc("void_R2") if err != nil { fmt.Println("void_R2 不存在", err.Error()) return } uint8_R1, err := handle.FindProc("uint8_R1") if err != nil { fmt.Println("uint8_R1 不存在", err.Error()) return } uint8_R1_free, err := handle.FindProc("uint8_R1_free") if err != nil { fmt.Println("uint8_R1_free 不存在", err.Error()) return } setCallBackFun, err := handle.FindProc("setCallBackFun") if err != nil { fmt.Println("setCallBackFun 不存在", err.Error()) return } fmt.Println("--------------------------函数加载成功-------------------------") // ------------------------------------------------------------------------- fmt.Println("---- void_R0") fmt.Println(void_R0.Addr()) void_R0.Call() // ------------------------------------------------------------------------- fmt.Println("\r\n\r\n---- void_R1") fmt.Println(void_R1.Addr()) name := C.CString("li_jian_xing") void_R1.Call((uintptr)(unsafe.Pointer(name))) C.free(unsafe.Pointer(name)) // ------------------------------------------------------------------------- // 创建数组,传入char** 取出C函数中的数据 fmt.Println("\r\n\r\n---- void_R2") fmt.Println(void_R2.Addr()) arg := make([]C.char, 1024) name = C.CString("li_jian_xing") void_R2.Call((uintptr)(unsafe.Pointer(name)), (uintptr)(unsafe.Pointer((&arg)))) C.free(unsafe.Pointer(name)) fmt.Println(C.GoString(&arg[0])) // ------------------------------------------------------------------------- // 传入char** 取出C函数分配的内存,处理完再释放 fmt.Println("\r\n\r\n---- uint8_R1") fmt.Println(uint8_R1.Addr()) var argc *C.char uint8_R1.Call((uintptr)(unsafe.Pointer(&argc))) fmt.Println(C.GoString(argc)) uint8_R1_free.Call((uintptr)(unsafe.Pointer(&argc))) // ------------------------------------------------------------------------- // 向dll 函数设定回调 fmt.Println("\r\n\r\n---- setCallBackFun") fmt.Println(setCallBackFun.Addr()) setCallBackFun.Call((uintptr)(unsafe.Pointer(C.CallBackFun))) handle.Release() // 释放dll 句柄 }