生活随笔
收集整理的这篇文章主要介绍了
在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++调用的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。