zoukankan      html  css  js  c++  java
  • 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++,其他语言不清楚)
    源文件如下:
    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 {
        return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))
    }
    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))
        if err != nil {
            fmt.Println("lib.dll运算结果为:", ret)
        }
    
    }
    
    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)
        if err != nil {
            fmt.Println("DllTestDef.dll运算结果为:", ret)
        }
    
    }
    
    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))
        if err != nil {
            fmt.Println("DllTestDef的运算结果为:", ret)
        }
    }
    
    func main() {
        Lib_add(4, 5)
        DllTestDef_add(4, 5)
        DllTestDef_add2(4, 5)
    }

    所有源码下载

  • 相关阅读:
    练习三
    练习四
    练习二
    软件生命周期
    练习一 第六题
    练习一 第五题
    练习一 第四题
    练习一 第三题
    练习一 第二题
    AngularJs模块
  • 原文地址:https://www.cnblogs.com/lxsky/p/5203940.html
Copyright © 2011-2022 走看看