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. 快速增加controller节点

    # controller1节点部署成功后,再添加controller节点,复制配置文件并修改即可openstack pike 部署 目录汇总 http://www.cnblogs.com/elvi/p ...

  2. codeforces 630C - Lucky Numbers 递推思路

    630C - Lucky Numbers 题目大意: 给定数字位数,且这个数字只能由7和8组成,问有多少种组合的可能性 思路: 假设为1位,只有7和8:两位的时候,除了77,78,87,88之外还哇哦 ...

  3. PHP设置环境变量

    如果提示php命令不存在.说明未设置.设置方法如下 方法一:直接运行命令 [PHP] 纯文本查看 复制代码 ? 1 export PATH=$PATH:/usr/local/xxxx/php/bin ...

  4. Springmvc ModelAndView踩过的坑之HttpServletResponse response

    先抛出问题.以下两个方法声明有毛区别: @RequestMapping(value = "/rg") public void rg(@PathVariable Long pageI ...

  5. Jdk8的学习之lambda

    在JDK8中,引入了Lambda(读:了母达)表达式的概念,这是我最喜欢的特性,很多东西都变得简单了,一行代码可以搞定. 比如说排序 /** * 这是一个JDK8的lambda的排序应用 */ pub ...

  6. Redis入门篇

    一.Redis简介: Redis(http://redis.io)是一款开源的.高性能的键-值存储(key-value store),它是用ANSI C来编写.Redis的项目名是Remote Dic ...

  7. js获取地址栏URL上的参数

    获取地址栏上的URL参数现在最简单通用的方法应该就是下面这种了. function getUrlParam (name) { var reg = new RegExp('(^|&)' + na ...

  8. 》》QQ-注册

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. Testin云測试破7000万次:崩溃成90%手游应用质量难题

    Testin云測试破7000万次:崩溃成90%手游应用质量难题 2014/11/13 · Testin · 业界资讯 11月13日.全球最大的移动游戏.应用真机和用户云測试平台Testin云測宣布,已 ...

  10. Python 练习冊,每天一个小程序

    Python 练习冊,每天一个小程序 说明:     Github 原文地址: 点击打开链接 Python 练习冊.每天一个小程序.注:将 Python 换成其它语言,大多数题目也试用 不会出现诸如「 ...