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 (三)的更多相关文章

  1. calling c++ from golang with swig--windows dll(一)

    calling c++ from golang with swig--windows dll 之前项目组开发的项目核心代码全部使用C++语言,新项目可能会引入golang,花了一天多时间研究了wind ...

  2. calling c++ from golang with swig--windows dll (四)

    calling c++ from golang with swig--windows dll 四 前面讲述了windows环境下golang如何通过swig调用C++ dll.由于编译c++代码使用了 ...

  3. calling c++ from golang with swig--windows dll 二

    Name mangling && Name demangling 在讲述golang如何利用swig调用windows dll之前,需要了解一个概念:Name Mangling (或者 ...

  4. golang调用c++的dll库文件

    最近使用golang调用c++的dll库文件,简单了解了一下,特作此笔记:一.DLL 的编制与具体的编程语言及编译器无关 dll分com的dll和动态dll,Com组件dll:不管是何种语言写的都可以 ...

  5. Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术

    catalogue 1. 引言2. 使用注册表注入DLL3. 使用Windows挂钩来注入DLL4. 使用远程线程来注入DLL5. 使用木马DLL来注入DLL6. 把DLL作为调试器来注入7. 使用c ...

  6. go 调用windows dll 的方法

    go 调用windows dll 的方法 ,代码如下: package main import ( "fmt" "syscall" "time&quo ...

  7. C#实现动态调用Windows DLL

    调用方法: object obj = WinDllInvoke("Kernel32.dll", "Beep", , }, typeof(void)); 函数代码 ...

  8. windows phone 三种数据共享的方式(8)

    原文:windows phone 三种数据共享的方式(8) 本节实现的内容是数据共享,实现的效果描述:首先是建立两个页面,当页面MainPage通过事件导航到页面SecondPage是,我们需要将Ma ...

  9. 转载:Windows下三分钟搭建Shadowoscks服务器端

    Windows下三分钟搭建Shadowoscks服务器端 之前在V2EX上有人问为啥没人做个在Windows上一键运行Shadowsocks服务器端的程序,我只想说……这是因为没人关注我的libQtS ...

随机推荐

  1. HBase表预分区与压缩

    1.建立HBase预分区表.sql语句如下: create 'buyer_calllogs_info_ts', 'record', {SPLITS_FILE => 'hbase_calllogs ...

  2. php的定界符<<<eof的问题

    在php的编程过程中难免会遇到输出大段的html和javascript脚本的情况,可都放在具体的地方的时候,路由不好处理,而且比较浪费时间 如果按照传统的输出方法,按照字符串输出的话,需要大量的转义字 ...

  3. Numpy入门 - 行列式转置

    本章实例讲解如何将一个数组对象进行转置,我们可以使用.T将行列数据颠倒过来,看下面的代码: import numpy as np arr = np.array([[1, 2, 3], [4, 5, 6 ...

  4. Teredo Tunnel Adapter: Error Code 10

    Teredo Tunneling 该设备无法启动 错误代码 ErrCode:10 解决方法 前文: Win7 系统,打算开启IPV6,本地连接的网络 ip6 驱动是异常的,先重新安装了网卡驱动. 过程 ...

  5. github与git之间怎么建立连接

    git是一款强大的分布式版本控制系统,到底是什么意思呢?其实我也不知道,以后知道了再补上吧.下面咱们来讲一下github怎么与你电脑上的git建立起连接关系. 一.你要有一个github账号. 去百度 ...

  6. php 将pdf转成图片且将图片拼接

    说明: 1.pdf转图片通过安装php扩展imagick实现. 2.由于windows扩展安装的一系列问题,建议在linux环境开发,windows大伙可以尝试安装. 3.为Centos 安装Imag ...

  7. Netty4 学习笔记之二:客户端与服务端心跳 demo

    前言 在上一篇Netty demo 中,了解了Netty中的客户端和服务端之间的通信.这篇则介绍Netty中的心跳. 之前在Mina 中心跳的使用是通过继承 KeepAliveMessageFacto ...

  8. Android Weekly Notes Issue #287

    Android Weekly Issue #287 December 10th, 2017 Android Weekly Issue #287 圣诞节快要来了,小编也偷懒了,本期内容包括如何通过AS添 ...

  9. 好好写代码吧,没事别瞎B去创业!

    知乎上看到这个问题 正好最近想写篇关于此的文章,于是就回答了一波. 也贴到这里来,回答如下 : 本问题简直为我量身定制,做为一个正在创业中的苦逼少年,说说我是如何从鼓吹怂恿身边人创业转换成反对创业的. ...

  10. reverse函数实现指定页面跳转

    需求: 在views中返回的url需要返回到具体的某一篇文章的评论列表 return redirect(reverse('cms_comment_manage',args=(number,))) dj ...