calling c++ from golang with swig--windows dll (三)
calling c++ from golang with swig--windows dll 三
使用动态链接库(DLL)主要有两种方式:一种通过链接导入库,在代码中直接调用DLL中的函数;另一种借助LoadLibrary/LoadLibraryEx,GetProcessAddress函数在代码中间接调用DLL中的函数。这两种使用方式对应两种动态链接,分别称为: load-time dynamic link (加载时动态链接)和run-time dynamic link (运行时动态链接)。
DLL工程编译后产生*.dll文件和同名的.lib文件, .lib文件是导入库,使用加载时链接的应用工程可以在代码中显式调用DLL中的函数,而且必须要用导入库*.lib链接。当系统启动一个使用加载时动态链接的程序时,它将利用链接器放置在文件中的信息来定位进程使用的DLL(可执行程序导入的)中的名称(DLL导出函数)。然后系统搜索DLL文件。如果系统无法找到所需的DLL,则会终止该进程,并向用户显示一个报告错误的对话框。否则,系统将DLL映射到进程的虚拟地址空间,并增加DLL引用计数。系统调用入口点函数(end-point function)。如果入口点函数没有返回TRUE,系统将终止进程并报告错误。最后,系统使用导入的DLL函数起始地址来修改函数地址表。(参阅msdn:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684184(v=vs.85).aspx)
使用运行时动态链接,当应用程序调用LoadLibrary或LoadLibraryEx函数时,系统将尝试找到DLL。如果搜索成功,系统将DLL模块映射到进程的虚拟地址空间,并将引用计数递增。然后系统在调用LoadLibrary或LoadLibraryEx的线程上下文中调用入口点函数。成功后LoadLibray或LoadLibraryEx返回一个指向DLL的句柄。进程可以在GetProcAddress、FreeLibrary函数调用中使用这个句柄来标识DLL。进程调用GetProcessAddress获取一个DLL导出函数的地址。当DLL模块不再需要时,进程可以调用FreeLibrary或FreeLibraryExAndExitThread。这些函数将减少模块引用计数并从进程的虚拟地址空间中取消映射的DLL代码。(参阅msdn:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682596(v=vs.85).aspx)
可以用上述两种动态链接在Golang中使用C++ DLL。Go标准库”syscall”提供了syscall.LoadLibrary,syscall.GetProcAddress,syscall.Syscall系列函数,可以轻松实现运行时动态链接,可参阅godoc查看syscall包的用法。
当DLL导出了C++类或者导出了大量函数,使用运行时动态链接很难实现或很繁琐,这种情况下应该使用加载时动态链接。下面主要讲如何用swig实现golang调用C++ DLL。(环境 windows 7 64位操作系统,安装64位 tdm-gcc,代码编译采用x64)
用VS 2010向导创建一个简单的动态链接库Simple.dll
主要代码如下:
Simple.h文件
#ifdef SIMPLE_EXPORTS
#define SIMPLE_API __declspec(dllexport)
#else
#define SIMPLE_API __declspec(dllimport)
#endif
// This class is exported from the Simple.dll
class SIMPLE_API CSimple {
public:
CSimple(void);
// TODO: add your methods here.
void SayHello();
};
extern SIMPLE_API int nSimple;
SIMPLE_API int fnSimple(void);
Simple.cpp文件:
// Simple.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "Simple.h"
#include <iostream>
using namespace std;
// This is an example of an exported variable
/*SIMPLE_API*/ int nSimple=0;
// This is an example of an exported function.
/*SIMPLE_API*/ int fnSimple(void)
{
return 42;
}
// This is the constructor of a class that has been exported.
// see Simple.h for the class definition
CSimple::CSimple()
{
return;
}
void CSimple::SayHello()
{
cout<<"Hello World"<<endl;
}
这个简单的DLL导出了一个变量,一个函数和一个类,类中包含一个构造函数和一个SayHello方法。用Dependency Walker查看Simple.dll文件:
Simple.dll导出了5个函数(变量),前面介绍过C++ Name mangling,可以用undname.exe查看undecorated name,多出来的那个函数是CSimple类的拷贝赋值操作符=。
接下来创建一个简单的go程序来调用Simple.dll,工程目录是D:\GoSimple,在该目录下创建simple文件夹,将Simple.dll和Simple.h文件拷贝到D:\GoSimple\simple中,再创建swig程序的输入文件simple.i

在命令行中切换到 D:\GoSimple\simple,执行 swig -c++ -go -cgo -intgosize 64 simple.i

成功后生成两个文件 simple_wrap.cxx 和 simple.go
打开simple.go,增加链接项
#cgo CFLAGS: -I .
#cgo LDFLAGS:-L . -lSimple

在D:\GoSimple中创建一个简单的main.go文件调用DLL

go build编译,可以看到出现一堆错误:

全部是链接错误,找不到定义。最开始实现go调用c++ dll时,费了较多的时间来解决这个编译错误,后来才明白go使用了gcc编译器,gcc的name mangling与微软visual c++编译器的name mangling不同,需要将DLL文件中增加一份按照g++ name mangling的函数名称。
根据DLL导出函数、dependency walker、go build的错误提示,前面讲过的C++ name mangling相关的内容,可以整理出如下关系:
|
函数名 |
Visual C++ decorated name |
g++ mangled name |
|
nSimple |
?nSimple@@3HA |
nSimple |
|
fnSimple |
?fnSimple@@YAHXZ |
_Z8fnSimplev |
|
CSimple::SayHello |
?SayHello@CSimple@@QEAAXXZ |
_ZN7CSimple8SayHelloEv |
|
CSimple::CSimple |
??0CSimple@@QEAA@XZ |
_ZN7CSimpleC1Ev |
我们需要利用.def文件为DLL文件的导出项部分增加一份g++使用的符号。为Simple DLL工程增加Simple.def,

重新编译后,再次用dependency walker来查看Simple.dll

增加def文件的作用是为函数入口点增加一个别名,例如?fnSimple@@YAHXZ 和_Z8fnSimplev对应的入口点同为0x0000102D,?fnSimple@@YAHXZ是visual c++ mangled name,_Z8fnSimplev是gcc mangled name。golang使用gcc编译c++代码,为DLL增加导出项后,就可以解决函数未定义的链接错误了。
更新D:\GoSimple\simple目录的Simple.dll,同时也在D:\GoSimple中拷贝一份Simple.dll
重新go build,编译成功。
运行

注意:1.go build前,需要在D:\GoSimple中也拷贝一份Simple.dll,否则会出现错误:

2.不能将Simple.lib拷贝到go程序目录中,否则会出现错误:

calling c++ from golang with swig--windows dll (三)的更多相关文章
- calling c++ from golang with swig--windows dll(一)
calling c++ from golang with swig--windows dll 之前项目组开发的项目核心代码全部使用C++语言,新项目可能会引入golang,花了一天多时间研究了wind ...
- calling c++ from golang with swig--windows dll (四)
calling c++ from golang with swig--windows dll 四 前面讲述了windows环境下golang如何通过swig调用C++ dll.由于编译c++代码使用了 ...
- calling c++ from golang with swig--windows dll 二
Name mangling && Name demangling 在讲述golang如何利用swig调用windows dll之前,需要了解一个概念:Name Mangling (或者 ...
- golang调用c++的dll库文件
最近使用golang调用c++的dll库文件,简单了解了一下,特作此笔记:一.DLL 的编制与具体的编程语言及编译器无关 dll分com的dll和动态dll,Com组件dll:不管是何种语言写的都可以 ...
- Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术
catalogue 1. 引言2. 使用注册表注入DLL3. 使用Windows挂钩来注入DLL4. 使用远程线程来注入DLL5. 使用木马DLL来注入DLL6. 把DLL作为调试器来注入7. 使用c ...
- go 调用windows dll 的方法
go 调用windows dll 的方法 ,代码如下: package main import ( "fmt" "syscall" "time&quo ...
- C#实现动态调用Windows DLL
调用方法: object obj = WinDllInvoke("Kernel32.dll", "Beep", , }, typeof(void)); 函数代码 ...
- windows phone 三种数据共享的方式(8)
原文:windows phone 三种数据共享的方式(8) 本节实现的内容是数据共享,实现的效果描述:首先是建立两个页面,当页面MainPage通过事件导航到页面SecondPage是,我们需要将Ma ...
- 转载:Windows下三分钟搭建Shadowoscks服务器端
Windows下三分钟搭建Shadowoscks服务器端 之前在V2EX上有人问为啥没人做个在Windows上一键运行Shadowsocks服务器端的程序,我只想说……这是因为没人关注我的libQtS ...
随机推荐
- ionic3中NavController类push setRoot相关问题解决
今天在测试app的时候发现,登录页跳转到首页后,会加载两次数据.百思不得其解,查看了所有代码也没能发现问题.最终抱着尝试的态度,动了如下代码: if (suc) { //this.navCtrl.pu ...
- NB-IoT物联网,来了
日前,深圳移动联合华为公司在深圳市福田.前海及盐田区域部署NB-IoT/LTE融合站点130余个,完成NB-IoT系统关键技术验证和组网技术验证,已初步形成NB-IoT试商用条件.深圳移动后续将在深圳 ...
- Android 异步消息处理机制前篇(二):深入理解Message消息池
版权声明:本文出自汪磊的博客,转载请务必注明出处. 上一篇中共同探讨了ThreadLocal,这篇我们一起看下常提到的Message消息池到底是怎么回事,废话少说吧,进入正题. 对于稍有经验的开发人员 ...
- sklearn 中 make_blobs模块使用
sklearn.datasets.make_blobs(n_samples=100, n_features=2, centers=3, cluster_std=1.0, center_box=(-10 ...
- 网页设计——6.html其他标签
今天学习html的其他标签: 一.列表 1.无序列表ul 基本结构: <ul type="属性值"> <li>列表内容</li> </u ...
- BigDecimal工具类处理精度计算
/** * Created by My_coder on 2017-07-27. * 加减乘除计算工具类 */ public class BigDecimalUtil { private BigDec ...
- poj 2905 双向队列(待补充)
Parallel Computer Simulator Description Programs executed concurrently on a uniprocessor system ap ...
- 开发H5基本知识摘要
一:开发平台 我在公司开发app主要是在apicloud平台上https://www.apicloud.com/,需要开发的同学可以点击进入这个平台了解: 二:开发工具 既然是在apicloud平台上 ...
- The literal of int xxxxx is out of range
有时候我们定义了long型的变量,当我们给该变量赋值过长的整数时,系统依旧会提示长度超过范围,解决的方法例如以下: long timeShow = 1437565243495L; 我们须要在整形变量的 ...
- 阿里云部署Docker(6)----解决删除<none>镜像问题
转载请注明来源,本博客原创作者为:http://blog.csdn.net/minimicall?viewmode=contents 在Docker使用中,常常会碰到删除镜像不成功.反而让镜像变成了& ...