GO语言调用DLL,填平所有的坑,最详尽攻略

2024-05-07 10:08

本文主要是介绍GO语言调用DLL,填平所有的坑,最详尽攻略,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

由于业务需要,购买了别人写好的一个DLL模块,于是磨难开始了,经历多天的折磨,终于完美解决。

首先DLL如果是32位的,编译前运行 

set GOARCH=386

第一个DLL函数,第一个参数,要求传入一个指针,直接指向[]byte类型,注意,是直接指向;第2个参数为[]byte长度;第三个参数为一个直接指向string类型指针;返回一个整数,标识调用成功或失败。

最折磨我的就是直接指向某种类型的指针传递问题,查了N多资料,都是类似下面这样:

p:= unsafe.Pointer(&dat)
g:=dll32.NewProc("XXX")
r, _, _ :=g.Call(uintptr(p),uintptr(cdat),uintptr(pk))
我开始也这样用,怎么弄都不对,然后我用OD载入调试,发现传进去的东西根本不是DLL想要的。

这样传进去的数据会被2层指针指向,ptrA->ptrB->[]byte,传进去的是ptrA,所以导致无法正常调用。那么问题来了,怎么才能传进去的指针直接指向数据,达到类似ptrA->[]byte这样的效果呢?

问题的重点就在这里,研究了好几天uintptr发现不是它的问题,问题出在

unsafe.Pointer

它上面,它会在指针外面再包一层指针,怎么解决呢?我只能考虑先把指针转成整数再传进去,结果

p:= *((*int32)(unsafe.Pointer(&dat)))
r, _, _ :=g.Call(uintptr(p),uintptr(cdat),uintptr(pk))
这样成功了。下面传递整数指针就简单多了

cdat:=len(dat)
这样即可,再后面传递字符串指针,指针获取方式和byte一样即可。但是问题又来了,执行不成功,继续OD,发现有问题,问题在于GO语言字符串后面在内存中没有结尾标志。那GO自己怎么判断字符串结尾呢?我想应该是每个字符串GO都同时记录了长度吧,不过不确定,有明白的大神请告知,这个问题我就只能这样,先把字符串转换成byte,然后在byte最后加0,类似这样

keystr:=[]byte{49,50,51,0}
pk:= *((*int32)(unsafe.Pointer(&keystr)))
这个问题就解决了,这个字符串就变成windows识别的了。返回值整数,直接就能用,这点我很奇怪,不知道为什么,比如这里,可以直接

r, _, _ =g.Call(uintptr(p),uintptr(cdat),uintptr(pk))
if r!=1 {
按理说,返回的是个指向整数的指针,应该*r才对,不懂,大神告知。

然后现在所有传递参数的问题解决了,后面问题又来了,第2个函数,调用后返回值是指向字符串的指针,这个指针指向的内容字符串当然是0结尾的windows格式了,GO依然无法正确读取。怎么办呢,只能自己写了个函数处理这个问题

//根据DLL返回的指针,逐个取出字节,到0字节时判断为字符串结尾,返回字节数组转成的字符串
func prttostr(vcode uintptr) string {var vbyte []byte
   for i:=0;i<10;i++{sbyte:=*((*byte)(unsafe.Pointer(vcode)))if sbyte==0{break
      }vbyte=append(vbyte,sbyte)vcode += 1
   }return string(vbyte)
}
原理就是操作指针一直向后移动,发现0了就停止,这样问题解决了,虽然所有的资料和大神都告诉我,不要轻易操作指针,但是这种情况下,不这么弄,怎么弄呢?谁能告诉我。

无论如何问题终于解决了,也许解决的不够完美,我想应该有更简单的办法,但是我不知道。


这篇关于GO语言调用DLL,填平所有的坑,最详尽攻略的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/967050

相关文章

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Java调用Python脚本实现HelloWorld的示例详解

《Java调用Python脚本实现HelloWorld的示例详解》作为程序员,我们经常会遇到需要在Java项目中调用Python脚本的场景,下面我们来看看如何从基础到进阶,一步步实现Java与Pyth... 目录一、环境准备二、基础调用:使用 Runtime.exec()2.1 实现步骤2.2 代码解析三、

Go中select多路复用的实现示例

《Go中select多路复用的实现示例》Go的select用于多通道通信,实现多路复用,支持随机选择、超时控制及非阻塞操作,建议合理使用以避免协程泄漏和死循环,感兴趣的可以了解一下... 目录一、什么是select基本语法:二、select 使用示例示例1:监听多个通道输入三、select的特性四、使用se

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路

Python如何调用另一个类的方法和属性

《Python如何调用另一个类的方法和属性》在Python面向对象编程中,类与类之间的交互是非常常见的场景,本文将详细介绍在Python中一个类如何调用另一个类的方法和属性,大家可以根据需要进行选择... 目录一、前言二、基本调用方式通过实例化调用通过类继承调用三、高级调用方式通过组合方式调用通过类方法/静