Go标准库syscall调用dll
什么是系统调用
了解syscall包之前先了解下什么是系统调用。系统调用是程序向操作系统内核请求服务的过程,通常包含硬件相关的服务(例如访问硬盘),创建新进程等。系统调用提供了一个进程和操作系统之间的接口。
fmt中的syscall
最常见的关于syscall的使用是在fmt.Println中,具体代码的大家可以一步步往下看怎么调用的,这里使用了系统的syscall.Stdout
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Go调用dll库
dll是windows动态库,go去调用动态库使用的是syscall标准库,一般dll库会提供两个固定函数,申请内存和释放内存,先申请完内存再执行业务逻辑的函数,执行完后释放内存。
dll, err := syscall.LoadDLL("scan.dll")
//根据名称从dll中查找proc
MemoryStream_Get = dll.FindProc("AllocateMemory")
MemoryStream_Get.Call()
主要就是三步:LoadDLL加载dll文件名,然后用FindProc判断查找调用的dll库函数名,然后Call进行调用。整体的调用方式还是比较简单。
LoadDLL会返回一个结构体DLL,注意Handle是一个uinptr类型(uintptr 是 Go 内置类型,表示无符号整数,可存储一个完整的地址,常用于指针运算),也就是会返回方法的地址值,后面的传参和解析通过结合只 unsafe.Pointer 类型转换成 uintptr 类型,做完加减法后,转换成 unsafe.Pointer,通过 * 操作,取值或者修改值都可以。
type DLL struct {
Name string
Handle Handle
}
调用dll如何传参
Proc的Call()方法是可接收多个uintptr的所以在传参的试试需要将参数转为uintptr
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
传递整型参数,将整型转为uintptr
func IntToPtr(n int) uintptr {
return uintptr(n)
}
传递字符串参数,将字符串转为uintptr,但是这里使用到了unsafe.Pointer,它是可以指向任意类型的指针,而syscall.StringBytePtr是将string转为 *btye指针。进而一步步转为uintptr
func StringToUintPtr(val string) uintptr {
return uintptr(unsafe.Pointer(syscall.StringBytePtr(val)))
}
接收dll库中返回值
读取调用库的返回值其实真正涉及到指针偏移的计算。因为uintptr指向的实际的整型地址值(申请内存方法会返回),我们可以根据返回的比如字符串在内存中长度来进行计算,比如长度是length(业务函数:GetDeviceInfo会返回),mem是实际调用dll库后返回的uintptr。因为调用dll库一般是返回char,所以这里转为byte即可。
type MemoryStream struct {
handle uintptr //空间地址值
lenHandle uintptr //数据长度
}
//获取设备信息 m.handle是申请内存的地址
func (m *MemoryStream) GetDeviceInfo() (result string) {
pd, _, _ := GetDeviceInfo.Call(m.handle)
m.lenHandle = pd
result = string(m.Bytes())
return result
}
//返回内存的数据内容byte[]
func (m *MemoryStream) Bytes() []byte {
buffer := new(bytes.Buffer)
length := m.Size()
mem := m.Memory()
if length == 0 {
return []byte{}
}
//根据长度,unsafe.Pointer进行指针运算
for i := int64(0); i < length; i {
buffer.WriteByte(*(*byte)(unsafe.Pointer(mem uintptr(i)))) //byte是uint8, sizeof长度是1
}
return buffer.Bytes()
}
总结
syscall库支持对dll库的调用,当然它的功能很强大,可以实现很多我们没有接触过的业务场景。调用的方式比较清晰,但是设计到传参和解析返回值的时候需要用到unsafe.Pointer和uintpre之间的转换、dll库返回的char强制转换为byte,这一块有点逻辑转换。下次专门做个笔记记录下指针、uintptr、unsafe.Pointer之间的使用。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfbkgh
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01