生活随笔
收集整理的這篇文章主要介紹了
在windows上使用go编译dll文件,供C++调用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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 main
import "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
:= out
for len(data
) > 0 {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
:= out
for 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())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 {client
:= &http
.Client
{Timeout
: 5 * time
.Second
}resp
, err
:= client
.Get(url
)defer resp
.Body
.Close()if err
!= nil {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 {result
= bytes
.NewBuffer([]byte("networkError"))}}return result
.String()
}
func GetIP(signal
int32, domainParam
string) *C
.char
{defer func() {err
:= recover()if err
!= nil {}}()if signal
!= 8956142 { return C
.CString("authError")}key
:= "xxxxxxxwww"domain
:= "xxx.com"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
編譯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文件
用C++調用, vs2017 (需要用到上面的.dll 和.h)
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <stdio.h>
#include "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
) };char* ipstr
= pFunc_GetIP(signal
, gostr_domain
);cout
<< strlen(ipstr
) << endl
;cout
<< ipstr
<< endl
;return 0;
}
----2020-12-29----
補充下:
關于在go中使用C.String后,內存需要釋放的,寫一個釋放內存的接口
import "C"
func FreeDecryUserKey(pointer
*C
.char
) {fmt
.Println("will free pointer ")fmt
.Println(pointer
)C
.free(unsafe
.Pointer(pointer
))
}
在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
) };GoString gostr_password
{ password
,(ptrdiff_t
)strlen(password
) };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;
}
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的在windows上使用go编译dll文件,供C++调用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。