go版小博客即将出炉,疯狂开发中...

go 调用windows api

go zhangshun 4个月前 (06-13) 594次浏览 已收录 1个评论

go调用 windows api 分为两种方式,一种是懒加载(第一次调用函数时才加载 dll),一种是立即加载。

需要注意的是,windows api 里面有很多常量和结构体需要自己转化成go的才可以用(文档中有对应的说明),如下获取系统进程列表时需要用到的部分其实都是根据官方文档转化而来。windows api 链接地址

需要特别注意的是,API 函数的参数都是 uintptr 类型,对指针类型需要通过 unsafe.Pointer 函数来转换,如果是 false 和 null 就用 0 代替

不再需要使用 DLL 里的函数之后可以卸载 DLL,可使用 syscall.FreeLibrary 来卸载。

1、懒加载:kernel32 =syscall.NewLazyDLL(“kernel32.dll”)

package main

import (
"fmt"
"syscall"
"unsafe"
)

//todo windows api 相关
type (
BOOL uint32
BOOLEAN byte
BYTE byte
DWORD uint32
DWORD64 uint64
HANDLE uintptr
HLOCAL uintptr
LARGE_INTEGER int64
LONG int32
LPVOID uintptr
SIZE_T uintptr
UINT uint32
ULONG_PTR uintptr
ULONGLONG uint64
WORD uint16
)

type PROCESSENTRY32 struct {
dwSize DWORD
cntUsage DWORD
th32ProcessID DWORD
th32DefaultHeapID ULONG_PTR
th32ModuleID DWORD
cntThreads DWORD
th32ParentProcessID DWORD
pcPriClassBase LONG
dwFlags DWORD
szExeFile [260]byte
}

const (
//Tool Help Library tlhelp.h
//CreateToolhelp32Snapshot==>可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。说到底,可以获取系统中正在运行的进程信息,线程信息,等。
TH32CS_INHERIT = 0x80000000 //声明快照句柄是可继承的
TH32CS_SNAPHEAPLIST = 0x00000001 //在快照中包含在 th32ProcessID 中指定的进程的所有的堆
TH32CS_SNAPMODULE = 0x00000008 //在快照中包含在 th32ProcessID 中指定的进程的所有的模块
TH32CS_SNAPMODULE32 = 0x00000010 //包括所有的 32 位模块的 th32ProcessID 在快照时从 64 位进程调用中指定的进程
TH32CS_SNAPPROCESS = 0x00000002 //在快照中包含系统中所有的进程
TH32CS_SNAPTHREAD = 0x00000004 //在快照中包含系统中所有的线程
TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE) //在快照中包含系统中所有的进程和线程。
)

func main() {
//懒加载获取进程列表==>懒加载
Kernel32 := syscall.NewLazyDLL("Kernel32.dll")
//获取快照
CreateToolhelp32Snapshot := Kernel32.NewProc("CreateToolhelp32Snapshot")
//调用函数
phandle, _, _ := CreateToolhelp32Snapshot.Call(uintptr(TH32CS_SNAPPROCESS), uintptr(0))
//延迟关闭快照句柄
defer func() {
CloseHandle := Kernel32.NewProc("CloseHandle")
_, _, _ = CloseHandle.Call(phandle)
}()

Process32Next := Kernel32.NewProc("Process32Next")
for {
var pe32 PROCESSENTRY32
pe32.dwSize = DWORD(unsafe.Sizeof(pe32))

rt, _, _ := Process32Next.Call(uintptr(phandle), uintptr(unsafe.Pointer(&pe32)))
if int(rt) == 1 {
fmt.Println("进程 pid:",pe32.th32ProcessID,"进程名称:",string(pe32.szExeFile[0:]),"线程数量:",pe32.cntThreads)
} else {
break
}
}
}

2、立即加载:kernel32,_ = syscall.LoadLibrary(“kernel32.dll”)

package main

import (
"fmt"
"syscall"
"unsafe"
)

//todo windows api 相关
type (
BOOL uint32
BOOLEAN byte
BYTE byte
DWORD uint32
DWORD64 uint64
HANDLE uintptr
HLOCAL uintptr
LARGE_INTEGER int64
LONG int32
LPVOID uintptr
SIZE_T uintptr
UINT uint32
ULONG_PTR uintptr
ULONGLONG uint64
WORD uint16
)

type PROCESSENTRY32 struct {
dwSize DWORD
cntUsage DWORD
th32ProcessID DWORD
th32DefaultHeapID ULONG_PTR
th32ModuleID DWORD
cntThreads DWORD
th32ParentProcessID DWORD
pcPriClassBase LONG
dwFlags DWORD
szExeFile [260]byte
}

const (
//Tool Help Library tlhelp.h
//CreateToolhelp32Snapshot==>可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。说到底,可以获取系统中正在运行的进程信息,线程信息,等。
TH32CS_INHERIT = 0x80000000 //声明快照句柄是可继承的
TH32CS_SNAPHEAPLIST = 0x00000001 //在快照中包含在 th32ProcessID 中指定的进程的所有的堆
TH32CS_SNAPMODULE = 0x00000008 //在快照中包含在 th32ProcessID 中指定的进程的所有的模块
TH32CS_SNAPMODULE32 = 0x00000010 //包括所有的 32 位模块的 th32ProcessID 在快照时从 64 位进程调用中指定的进程
TH32CS_SNAPPROCESS = 0x00000002 //在快照中包含系统中所有的进程
TH32CS_SNAPTHREAD = 0x00000004 //在快照中包含系统中所有的线程
TH32CS_SNAPALL = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE) //在快照中包含系统中所有的进程和线程。
)

func main() {
//获取进程列表==>立即加载
kernel32,_:=syscall.LoadLibrary("kernel32")
//调用函数
CreateToolhelp32Snapshot, _ :=syscall.GetProcAddress(kernel32,"CreateToolhelp32Snapshot")
//其他参数补 0 就行了
pHandle,_,_:=syscall.Syscall(CreateToolhelp32Snapshot,2, uintptr(TH32CS_SNAPPROCESS), uintptr(0),0)
if int(pHandle) == 0{
panic("CreateToolhelp32Snapshot 调用失败")
}

Process32Next,err:=syscall.GetProcAddress(kernel32,"Process32Next")
if err != nil{
panic(Process32Next)
}

for {
var pe32 PROCESSENTRY32
pe32.dwSize = DWORD(unsafe.Sizeof(pe32))
ret, _, _ := syscall.Syscall(Process32Next,2,uintptr(pHandle), uintptr(unsafe.Pointer(&pe32)),0)
if int(ret) == 1 {
fmt.Println("进程 pid:",pe32.th32ProcessID,"进程名称:",string(pe32.szExeFile[0:]),"线程数量:",pe32.cntThreads)
} else {
break
}
}
}

其他的 api 调用套路都是这样,其他就需要是对文档熟悉程度,用到哪块就调用哪块就行了。

最后的最后,一个简易网页版进程管理:https://gitee.com/iwhot/task-manager


石叶川博客, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明go 调用 windows api
喜欢 (8)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(1)个小伙伴在吐槽
  1. 大佬
    aaa2020-06-16 11:54 回复 Windows 7 | Chrome 78.0.3904.108