在windows上使用go編譯dll文件,供C++調用

  1. C++項目是win32的,所以go的編譯環境也要改成win32的
cmd下,修改環境變量:
set GOARCH=386
set CGO_ENABLED=1
使用go env 查看是否生效

參考:https://bbs.csdn.net/topics/394513992.
2. 安裝編譯環境
MinGW下載安裝gcc,g++編譯器
參考:https://blog.csdn.net/cbb944131226/article/details/82940273
3. 編寫go相關文件和代碼
編寫def文件
比如我要編譯的dll文件,導出函數為GetIP
那么編寫一個 godll.def (名字隨便起)
godll.def

EXPORTSGetIP
package mainimport "C"import ("bytes""crypto/cipher""crypto/des""encoding/hex""fmt""io""math/rand""net/http""strings""time"
)func EncryptDES_ECB(src, key string) string {data := []byte(src)keyByte := []byte(key)block, err := des.NewCipher(keyByte)if err != nil {panic(err)}bs := block.BlockSize()//對明文數據進行補碼data = PKCS5Padding(data, bs)if len(data)%bs != 0 {panic("Need a multiple of the blocksize")}out := make([]byte, len(data))dst := outfor len(data) > 0 {//對明文按照blocksize進行分塊加密//必要時可以使用go關鍵字進行并行加密block.Encrypt(dst, data[:bs])data = data[bs:]dst = dst[bs:]}return fmt.Sprintf("%X", out)
}func DecryptDES_ECB(src, key string) string {data, err := hex.DecodeString(src)if err != nil {panic(err)}keyByte := []byte(key)block, err := des.NewCipher(keyByte)if err != nil {panic(err)}bs := block.BlockSize()if len(data)%bs != 0 {panic("crypto/cipher: input not full blocks")}out := make([]byte, len(data))dst := outfor len(data) > 0 {block.Decrypt(dst, data[:bs])data = data[bs:]dst = dst[bs:]}out = PKCS5UnPadding(out)return string(out)
}func EncryptDES_CBC(src, key string) string {data := []byte(src)keyByte := []byte(key)block, err := des.NewCipher(keyByte )if err != nil {panic(err)}data = PKCS5Padding(data , block.BlockSize())//獲取CBC加密模式iv := keyByte //用密鑰作為向量(不建議這樣使用)mode := cipher.NewCBCEncrypter(block, iv)out := make([]byte, len(data))mode .CryptBlocks(out, data)return fmt.Sprintf("%X", out)
}func DecryptDES_CBC(src, key string) string {keyByte := []byte(key)data, err := hex.DecodeString(src)if err != nil {panic(err)}block, err := des.NewCipher(keyByte)if err != nil {panic(err)}iv := keyByte //用密鑰作為向量(不建議這樣使用)mode := cipher.NewCBCDecrypter(block, iv)plaintext := make([]byte, len(data))mode.CryptBlocks(plaintext, data)plaintext = PKCS5UnPadding(plaintext)return string(plaintext)
}func PKCS5Padding(ciphertext []byte, blockSize int) []byte {padding := blockSize - len(ciphertext)%blockSizepadtext := bytes.Repeat([]byte{byte(padding)}, padding)return append(ciphertext, padtext...)
}func PKCS5UnPadding(origData []byte) []byte {length := len(origData)unpadding := int(origData[length-1])return origData[:(length - unpadding)]
}func Get(url string) string {// 超時時間:5秒client := &http.Client{Timeout: 5 * time.Second}resp, err := client.Get(url)defer resp.Body.Close()if err != nil {//panic(err)//fmt.Println(err.Error())return "networkError"}var buffer [512]byteresult := bytes.NewBuffer(nil)for {n, err := resp.Body.Read(buffer[0:])result.Write(buffer[0:n])if err != nil && err == io.EOF {break} else if err != nil {//panic(err)result = bytes.NewBuffer([]byte("networkError"))}}return result.String()
}//export GetIP
func GetIP(signal int32, domainParam string) *C.char {defer func() {err := recover()if err != nil {//fmt.Println(err)}}()if signal != 8956142 { //  做一下驗證防止被 惡意調用return C.CString("authError")}key := "xxxxxxxwww"domain := "xxx.com"//domain := "xxxx.cn"enc_str := EncryptDES_ECB(domain, key)httpDnsUrl := "http://xxxxx/d?dn=" + enc_str + "&id=888&ttl=1"respTxt := Get(httpDnsUrl)if respTxt == "networkError" {return C.CString("networkError")}descStr := DecryptDES_ECB(respTxt, key)ips_str := strings.Split(descStr, ",")[0]ips_slice := strings.Split(ips_str, ";")ips_length := len(ips_slice)if ips_length == 1 {return C.CString(ips_slice[0])} else {rand.Seed(time.Now().Unix())index := rand.Intn(ips_length)return C.CString(ips_slice[index])}
}func main() {}

注意:在要導出的函數(GetIP)上面 寫上 //export GetIP, 還要有main函數

實際上我應該將 C.CString 創建的內存,釋放掉。
參考:
https://blog.csdn.net/weixin_34128501/article/details/91709373
https://blog.csdn.net/liangguangchuan/article/details/52920054
https://blog.csdn.net/qq_30549833/article/details/86157744

  1. 編譯dll文件
go build -buildmode=c-archive httpdns.go
gcc godll.def httpdns.a -shared -lwinmm -lWs2_32 -o httpdns.dll -Wl,--out-implib,httpdns.lib

生成 .dll .lib. h文件

  1. 用C++調用, vs2017 (需要用到上面的.dll 和.h)
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <stdio.h>
#include "httpdns.h" // dll的頭文件
// 其中 httpdns.h里面的
//typedef __SIZE_TYPE__ GoUintptr;
//typedef float _Complex GoComplex64;
//typedef double _Complex GoComplex128; 這三行要注釋掉// 根據httpdns.h 里面導出函數定義下面類型
typedef char*(*funcPtrGetIP)(GoInt32, GoString);
using namespace std;
int main() {//加載動態庫HINSTANCE hInstance = LoadLibrary("httpdns.dll");funcPtrGetIP pFunc_GetIP = (funcPtrGetIP)GetProcAddress(hInstance, "GetIP");int signal = 8956142;char* domain = const_cast<char *>("xxx.com");GoString gostr_domain{ domain,(ptrdiff_t)strlen(domain) };//就是go中的string類型char* ipstr = pFunc_GetIP(signal, gostr_domain);cout << strlen(ipstr) << endl;cout << ipstr << endl;//FreeLibrary(hInstance); //release模式會崩潰,原因未知return 0;
}

----2020-12-29----
補充下:
關于在go中使用C.String后,內存需要釋放的,寫一個釋放內存的接口

/*
#include <stdio.h>
#include <stdlib.h>
*/
import "C"//export FreeDecryUserKey
func FreeDecryUserKey(pointer *C.char) {fmt.Println("will free pointer ")fmt.Println(pointer)C.free(unsafe.Pointer(pointer))//釋放內存 必須引入stdlib.h 標準庫
}

在Cpp中這樣使用

#include <iostream>
#include <string>
#include <Windows.h>
#include "aesdecry.h"
using namespace std;typedef char*(*funcPtrGetDecryUserKey)(GoString, GoString);
typedef void (*funcPtrFreeDecryUserKey)(char*);int main() {std::string user_base64_key = "1a07b51b220c5083ede4903cf0e1da88823e8134eb81b6a78396234a6de8d06de6f94a55d0e8762849ae58c70d436217";HINSTANCE hInstance = LoadLibrary("main.dll");funcPtrGetDecryUserKey pFunc_GetDecryUserKey = (funcPtrGetDecryUserKey)GetProcAddress(hInstance, "GetDecryUserKey");funcPtrFreeDecryUserKey pFunc_FreeDecryUserKey = (funcPtrFreeDecryUserKey)GetProcAddress(hInstance, "FreeDecryUserKey");char* encry_data = const_cast<char *>(user_base64_key.c_str());char* password = const_cast<char *>("aa6e8b08e4db270c");GoString gostr_encry_data{ encry_data,(ptrdiff_t)strlen(encry_data) };//就是go中的string類型GoString gostr_password{ password,(ptrdiff_t)strlen(password) };//就是go中的string類型char* real_user_key = pFunc_GetDecryUserKey(gostr_encry_data, gostr_password);printf("%x\n", real_user_key);printf("%p\n", real_user_key);std::string targetkey = real_user_key;cout << targetkey << endl;pFunc_FreeDecryUserKey(real_user_key);  // 釋放掉內存cout << targetkey << endl;return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382417.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382417.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382417.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

go語言急速入門

Go 語言極速入門1 - 環境搭建與最簡姿勢 Go 語言極速入門2 - 基礎語法 Go 語言極速入門3 - 內建容器 Go 語言極速入門4 - 面向對象 Go 語言極速入門5 - 面向接口 Go 語言極速入門6 - 閉包 Go 語言極速入門7 - 資源管理與錯誤處理 Go 語言極速入門8 - Goroutine Go 語言極速入門…

windows遠程桌面mstsc使用 代理

轉自 https://blog.csdn.net/bodybo/article/details/6638005

go語言掃描四位數可用域名

域名注冊查詢接口(API)的說明 原文出處 域名查詢 接口采用HTTP&#xff0c;POST&#xff0c;GET協議&#xff1a; 調用URL&#xff1a;http://panda.www.net.cn/cgi-bin/check.cgi 參數名稱&#xff1a;area_domain 值為標準域名&#xff0c;例&#xff1a;hichina.com 調用…

cmake構建工具 初步01

記錄下cmake學習過程&#xff0c;以后還會補充 單目錄單文件 demo1 目錄下只有一個a1.cpp, 如下圖 [rootlocalhost demo1]# tree . ├── a1.cpp └── CMakeLists.txt編寫CMakeLists.txt 1 CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)2 3 PROJECT(demo1)4 5 ADD_EXECUTABLE(d…

Mysql5.7后的password加密和md5

5.7之后 password函數舊版16位&#xff0c;新版41位&#xff0c;可用select password(‘123456’)查看。md5加密算法&#xff0c;只有16位和32位兩種 authentication_string 且5.7之后移除了password&#xff0c;它采用了新的算法 5.7之前 mysql> select user,host,pas…

用python寫的簡單的http文件服務器demo

import socket import os import re import time from multiprocessing import Processclass CHttpServer(object):"""Httpserver服務端類"""def __init__(self):self.m_serverSocket socket.socket(socket.AF_INET,socket.SOCK_STREAM)self.m_…

從《四驅兄弟》到“聯想中國”

《四驅兄弟》 小學的時候看過一個日本的動畫片叫四驅兄弟&#xff0c;里面就是一群小朋友代表國家各種比賽&#xff0c;其中讓我象比較深刻的是他把美國隊描述的非常邪惡&#xff0c;各種破壞別人的車子&#xff0c;通過卑鄙手段取得勝利。然后最后好像是正義戰勝邪惡的劇情還…

Mac SecureCRT解決中文亂碼

下載地址 https://xclient.info/s/navicat-premium.html#versions SecureCRT解決中文亂碼問題 在設置中設置為utf-8之后&#xff0c;還需要 $ sudo vi /etc/profile $打開文件&#xff0c;最后一行添加export LANGzh_CN.UTF-8

音視頻之使用sonic.cpp實現音頻倍速播放功能

sonic.cpp 是一個音頻處理庫&#xff0c;可以實現倍速播放。 如果單純通過修改pcm的采樣率來實現音頻倍速播放的話&#xff0c;就會出現聲音變調的情況。 以下是通過采集windows 虛擬聲卡獲取到的音頻數據&#xff0c; 我的聲卡采樣率是44100次/秒&#xff0c;audio_buffer_si…

SecurtCRT連接服務器自動斷開

mac Terminal-->Anti-idle-->send protocol NO-OP 60勾中

位圖原理、代碼實現及應用實例

位圖的原理&#xff1a; 在位圖中采用比特位表示對應的元素存在或者不存在 0&#xff1a;不存在 1&#xff1a;存在例如一個int整數有32個比特位可以表示0-31個整數。 再舉一個例子 存入的數字為8988 首先&#xff1a; 8988/32 280 其次&#xff1a; 8988%32 28 再來一個例…

通過修改注冊表,實現網頁鏈接中的私有協議啟用本地exe進程

私有協議為 coffeeclass://xxxxxx.mp4 注冊表如下 Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\coffeeclass] "coffeeClass Protocol" "URL Protocol"""[HKEY_CLASSES_ROOT\coffeeclass\DefaultIcon] "D:\\Program Files (x…

布隆過濾器的原理、應用場景和源碼分析實現

原理 布隆過濾器數據結構 布隆過濾器是一個 bit 向量或者說 bit 數組&#xff0c;長這樣&#xff1a; 如果我們要映射一個值到布隆過濾器中&#xff0c;我們需要使用多個不同的哈希函數生成多個哈希值&#xff0c;并對每個生成的哈希值指向的 bit 位置 1。 例如針對值 “baid…

判斷一個數字是否存在于某一個數據之中

哈希表 這個沒啥說的&#xff0c;后面補充 位圖 https://blog.csdn.net/csdn_kou/article/details/95337121 布隆過濾器 哈希表位圖 https://blog.csdn.net/csdn_kou/article/details/95371085

根據語句自動生成正則表達式

自動生成 http://www.txt2re.com 速查手冊 https://www.jb51.net/shouce/jquery/regexp.html

免密登錄堡壘機和服務器

免密登錄堡壘機 安裝oathtool和sshpass 這兩個文件安裝比較耗費時間&#xff01; brew install oath-toolkit brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb免密登錄堡壘機 書寫shell腳本 #!/usr/bin/env bash …

mysql建表sql

mysql建表 文章目錄mysql建表mysql學生表插入數據建表&#xff0c;學生和idgroup byinner joinmysql學生表 CREATE TABLE courses ( id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 自增id, student VARCHAR(255) DEFAULT NULL COMMENT 學生, class VARCHAR(255) DEFAU…

Effective C++學習第一天

1&#xff1a;區分C中的術語聲明、定義、初始化的概念聲明&#xff08;declaration&#xff09;&#xff1a;告訴編譯器某個東西的名稱和類型&#xff0c;但略去其他細節&#xff08;可以出現多次&#xff0c;編譯器不分配內存&#xff09;。定義&#xff08;definition&#x…

Redis運維和開發學習筆記(1) Redis簡介

文章目錄Redis的特性速度快持久化多種數據結構主從復制高可用和分布式典型的應用場景Redis啟動和可執行文件Redis可執行文件說明啟動方式驗證redisredis常用配置redis數據結構和內部編碼Redis是單線程&#xff0c;不會同時執行兩條命令哈希慢查詢pipelineRedis的特性 速度快 …

Effective C++學習第二天

1&#xff1a;確保對象被使用前已先被初始化&#xff0c;讀取未初始化的值會造成不明確的行為&#xff0c;可能導致程序終止運行或者其他不可預期的現象&#xff1b;在C中&#xff0c;當你使用C part of C(C中C語言部分的內容&#xff09;且初始化可能導致運行期成本&#xff0…