php调用go生成的dll,golang调用c++的dll库文件

转战简书,来点干货,认真的码农必须讲清楚

最近使用golang调用c++的dll库文件,简单了解了一下,特作此笔记:

一、DLL 的编制与具体的编程语言及编译器无关

dll分com的dll和动态dll,

Com组件dll:不管是何种语言写的都可以调用,但com分很多种。比如php只能调用com的dll的特定的几种、不能直接调用动态dll,要使用第三方的dll文件dynwrap.dll或者编译PHP扩展来迂回调用

动态dll:只要遵循约定的 DLL 接口规范和调用方式,用各种语言编写的 DLL 都可以相互调用。譬如 Windows 提供的系统 DLL (其中包括了 Windows 的 API ),在任何开发环境中都能被调用,不在乎其是 Visual Basic 、 Visual C++ 还是 Delphi

二、动态dll文件里面需要被其他程序访问的函数必须导出,有2种方法(c++,其他语言不清楚)

先简单来个dll的源文件,就一个add函数,如下:

DllTestDef.h

#ifndef DLLTESTDEF_H

#define DLLTESTDEF_H

int add(int x, int y);

#endif

DllTestDef.cpp

#include "DllTestDef.h"

int add(int x, int y)

{

return x + y;

}

2.1、通过在.h头文件里面为函数添加 __declspec(dllexport),例如:

_declspec(dllexport) int add(int a, int b);

说明:此方式下,如果调用该dll的是一个c++程序(同一个编译器的版本)是没有问题的。但是如果是一个其它语言的程序(如C#、VB),则会出错

因为VC++编译器对于__declspec(dllexport)声明的函数会进行名称转换,如上面的函数会转换为Add@0,这样你在VB中必须这样声明:

Declare Function Add Lib "DLLTestDef.dll" Alias "Add@0" () As Long

@后面的数由于参数类型不同而可能不同。这显然不太方便。

为了解决这一问题,我们往往在函数前面再加一个extern "C",使用C方式的函数命名规则。所以为了大范围的使用我们基本申明都如下:

extern "C" _declspec(dllexport) int add(int a, int b);

DllTestDef.h改造如下:

#ifndef DLLTESTDEF_H

#define DLLTESTDEF_H

extern "C" __declspec(dllexport) int add(int x, int y);

#endif

DllTestDef.cpp同上面源文件

2.2、使用.def文件,为了简化2.1的那一长串代码,MS引入了def文件方便我们操作。

DllTestDef.h同源文件

DllTestDef.cpp同源文件

DllTestDef.def如下

LIBRARY DllTestDef

EXPORTS

add @ 1;导出其中的add函数,并指定add函数的序号为1

;sub @ 2

添加文件到项目属性里面的Linker/input里面

三、在golang里面使用动态dll,也有3种方法

注意的是golang由于数据类型和c++的不一致,在需要传参的时候需要把所有的参数都转换成

uintptr指针类型,而且转换的过程需要借助unsafe.Pointer指针

package main

import (

"fmt""syscall""unsafe")

func IntPtr(n int) uintptr {

return uintptr(n)

}

func StrPtr(s string) uintptr {

returnuintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))

}

//方法1:

func Lib_add(a, b int) {

lib := syscall.NewLazyDLL("lib.dll")

fmt.Println("dll:", lib.Name)

add := lib.NewProc("add")

fmt.Println("+++++++NewProc:", add,"+++++++")

ret, _, err := add.Call(IntPtr(a), IntPtr(b))

iferr != nil {

fmt.Println("lib.dll运算结果为:", ret)

}

}

//方法2:

func DllTestDef_add(a, b int) {

DllTestDef, _ := syscall.LoadLibrary("DllTestDef.dll")

fmt.Println("+++++++syscall.LoadLibrary:", DllTestDef,"+++++++")

defer syscall.FreeLibrary(DllTestDef)

add, err := syscall.GetProcAddress(DllTestDef,"add")

fmt.Println("GetProcAddress", add)

ret, _, err := syscall.Syscall(add,

2,

IntPtr(a),

IntPtr(b),

0)

iferr != nil {

fmt.Println("DllTestDef.dll运算结果为:", ret)

}

}

//方法3:

func DllTestDef_add2(a, b int) {

DllTestDef := syscall.MustLoadDLL("DllTestDef.dll")

add := DllTestDef.MustFindProc("add")

fmt.Println("+++++++MustFindProc:", add,"+++++++")

ret, _, err := add.Call(IntPtr(a), IntPtr(b))

iferr != nil {

fmt.Println("DllTestDef的运算结果为:", ret)

}

}

func main() {

Lib_add(4,5)

DllTestDef_add(4,5)

DllTestDef_add2(4,5)

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值