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 ...
随机推荐
- [flask实践] 解决qq邮箱/mysql的相关配置问题
笔者经过flask web(Miguel著,封面是一条狗)一书的学习,打算实现一个旅游类网站,在此过程中发现,相对于书中的flasky博客程序,需要作出一些改变: 1. 注册邮箱:国内要使用126,q ...
- sqlserver的四种分页方式
第一种:ROW_NUMBER() OVER()方式 select * from ( select *, ROW_NUMBER() OVER(Order by ArtistId ) AS RowId f ...
- Django的分页器(paginator)
先导入模块: from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 分页器paginator 下面的所有方法 ...
- dingo/API 最新版 V2.0 之安装讲解
我发现关于dingo/API V2.0的资料少之又少,应该也是发布时间不久的原因.下面,我就来给大家讲解(翻译)下官方的英文文档,如果有说的不对的地方,请指正.先附上,官网wiki地址https:// ...
- 组合模式(Composite)
组合模式(Composite) 组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便,看看关系图: 直接来看代码: [java] view plaincopypublic class Tr ...
- 微信JS-SDK选择相册或拍照并上传PHP实现
理解:微信上传接口是拍照,或者选择本地照片,上传到微信的服务器,获取到一个id,通过token与这个id获取到图片,保存到服务器即可. 效果 通过微信js接口,调用底层程序. 需要引入js文件,并进行 ...
- thinkphp整合系列之极验滑动验证码
对于建站的筒子们来说:垃圾广告真是让人深恶痛绝:为了清净:搞个难以识别的验证码吧:又被用户各种吐槽:直到后来出现了极验这个滑动的验证码:这真是一个体验好安全高的方案:官网:http://www.gee ...
- CentOS6 图形界面(gnome)安装,使用vnc进行远程连接
CentOS6相对于CentOS5的安装有了不少的进步,有不少默认的选项可以选择,如: Desktop :基本的桌面系统,包括常用的桌面软件,如文档查看工具. Minimal Desktop :基本的 ...
- 数据库文件*.sdf文件定时备份,但是大小的增量在不断增长的问题排查
在某项目上,使用SQL Server数据库,现场反馈每天定时备份数据库文件,每天的数据量是400多个申请单的量.之前每天增长量是50M,但是后来两天增长量是80M,每天的数据量差不多. 到底从什么地方 ...
- NOIP2017提高组初赛解析
首发于订阅号 嗨编程,这是一个以嗨为目标的编程订阅号(仅仅是目标而已),扫码可关注,不定期更. 解析中引用了一张关于排序的总结课件图片,来源网络,如果侵权,请联系本人删除(没钱付版权费)