如何在Go中处理Windows进程



我正在尝试调用user32.dll的函数RegisterDeviceNotificationW。但函数的第一个参数是"将接收设备事件的窗口或服务的句柄"(这是我从Microsoft获得的(。

基于Cloud Printer Connector,我尝试使用svc.StatusHandler()获取处理程序,但对我不起作用,每次运行时我都会收到以下错误:

句柄无效。

好吧,使用sys示例的相同代码,我创建了自己的"服务",用RegisterDeviceNotification(谷歌的相同代码(替换了beep功能,并发送了我的服务名称和从svc.StatusHandler()返回的值,但我再次收到相同的消息:"句柄无效。">

函数寄存器设备通知

var (
u32                            = syscall.MustLoadDLL("user32.dll")
registerDeviceNotificationProc = u32.MustFindProc("RegisterDeviceNotificationW")
)   

这是我需要发送一个有效的处理的地方

func RegisterDeviceNotification(handle windows.Handle) error {
var notificationFilter DevBroadcastDevinterface
notificationFilter.dwSize = uint32(unsafe.Sizeof(notificationFilter))
notificationFilter.dwDeviceType = DBT_DEVTYP_DEVICEINTERFACE
notificationFilter.dwReserved = 0
// BUG(pastarmovj): This class is ignored for now. Figure out what the right GUID is.
notificationFilter.classGuid = PRINTERS_DEVICE_CLASS
notificationFilter.szName = 0
r1, _, err := registerDeviceNotificationProc.Call(uintptr(handle), uintptr(unsafe.Pointer(&notificationFilter)), DEVICE_NOTIFY_SERVICE_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)
if r1 == 0 {
return err
}
return nil
}

调用函数

func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
h := windows.Handle(uintptr(unsafe.Pointer(m)))
err := RegisterDeviceNotification(h)
fmt.Println(err)
}

注意:我也试过使用"myService"的指针:

h := windows.Handle(uintptr(unsafe.Pointer(m)))
err := RegisterDeviceNotification(h)

编辑:我尝试了GetCurrentProcess,但不起作用:

检索当前进程的伪句柄。

h, err := syscall.GetCurrentProcess()
err = RegisterDeviceNotification(windows.Handle(h))

问题:如何在Go中获得流程的有效句柄

PS:如果我的问题有任何问题,请告诉我以改进。

syscall.GetCurrentProcess((可以这样使用。

package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
kernel32, err := syscall.LoadDLL("kernel32.dll")
if err != nil {
fmt.Println(err)
}
defer kernel32.Release()
proc, err := kernel32.FindProc("IsWow64Process")
if err != nil {
fmt.Println(err)
}
handle, err := syscall.GetCurrentProcess()
if err != nil {
fmt.Println(err)
}
var result bool
_, _, msg := proc.Call(uintptr(handle), uintptr(unsafe.Pointer(&result)))
fmt.Printf("%vn", msg)
}

import (
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
func main() {
ProcessUtils{}.SetWinNice(13716, windows.HIGH_PRIORITY_CLASS)
}
var (
kernel32        = syscall.MustLoadDLL("kernel32.dll")
procOpenProcess = kernel32.MustFindProc("OpenProcess")
)
const PROCESS_ALL_ACCESS = 0x1F0FFF
type ProcessUtils struct {
}

func (ProcessUtils) GetProcessHandle(pid int) windows.Handle {
handle, _, _ := procOpenProcess.Call(ToUintptr(PROCESS_ALL_ACCESS), ToUintptr(true), ToUintptr(pid))
return windows.Handle(handle)
}
func (u ProcessUtils) SetWinNice(pid int, priority uint32) error {
handle := u.GetProcessHandle(pid)
return windows.SetPriorityClass(handle, priority)
}
func ToUintptr(val interface{}) uintptr {
switch t := val.(type) {
case string:
p, _ := syscall.UTF16PtrFromString(val.(string))
return uintptr(unsafe.Pointer(p))
case int:
return uintptr(val.(int))
default:
_ = t
return uintptr(0)
}
}

这是我不久前写的一些代码来处理这个问题,上次检查时它还在工作。我已经为一堆winapi调用创建了包装器函数。

package main
import "syscall"
// import the required winapi DLLs and functions
var (
dllKernel32 := syscall.NewLazyDLL("kernel32.dll")
procOpenProcess = dllKernel32.NewProc("OpenProcess")
procCloseHandle = dllKernel32.NewProc("CloseHandle")
)
// when passing this to the OpenProcess function it will get
// a handle with the PROCESS_ALL_ACCESS permissions
const PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | uintptr(0xFFFF)
func main() {
pid := uint32(123456)
inheritHandle := uint32(1)
handle, err := OpenProcess(PROCESS_ALL_ACCESS, inheritHandle, pid)

if err != nil {
panic(err)
}

... // whatever your code wants to do
err = CloseHandle(handle)
if err != nil {
panic(err)
}
}
// Wraps the winapi OpenProcess function
func OpenProcess(desiredAccess uintptr, inheritHandle uint32, pid uint32) (uintptr, error) {
// call the winapi function to get a handle
handle, _, err := procOpenProcess.Call(desiredAccess, uintptr(inheritHandle), uintptr(pid))
// check for errors
if handle == 0 || err != nil {
return r1, err
}
// return the handle
return handle, nil
}
// Wraps the winapi CloseHandle function
func CloseHandle(handle uintptr) error {
// call the winapi function to close the handle
r, _, err := procCloseHandle.Call(handle)
// check for errors
if r == 0 || err != nil {
return r1, err
}
return nil
}

确保在使用完手柄后关闭手柄,不要让随机手柄无限期地打开。

这里有一些资源可以帮助你了解这里发生的事情:

https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess

https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle

https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights

以下是如何在给定PID:的情况下获得进程的句柄

import (
"golang.org/x/sys/windows"
)
// https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
const PROCESS_ALL_ACCESS = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0xffff
func GetWindowsHandle(pid int) windows.Handle {
handle, err := windows.OpenProcess(PROCESS_ALL_ACCESS, false, uint32(pid))
if err != nil {
return err
}
return handle
}

我相信你也需要确保在完成后致电windows.CloseHandle(handle)

完整示例:

package main
import (
"log"
"os/exec"
"golang.org/x/sys/windows"
)
// https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
const PROCESS_ALL_ACCESS = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0xffff
func SetPriorityWindows(pid int, priority uint32) error {
handle, err := windows.OpenProcess(PROCESS_ALL_ACCESS, false, uint32(pid))
if err != nil {
return err
}
defer windows.CloseHandle(handle) // Technically this can fail, but we ignore it
err = windows.SetPriorityClass(handle, priority)
if err != nil {
return err
}
return nil
}
func main() {
cmd := exec.Command("python", "hello.py")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
// Set priority to above normal
err = SetPriorityWindows(cmd.Process.Pid, windows.ABOVE_NORMAL_PRIORITY_CLASS)
if err != nil {
log.Fatal(err)
}
err = cmd.Wait()
}

最新更新