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)
}

所有源碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM