如何在 Go 中获取 Windows 进程的句柄?

Posted

技术标签:

【中文标题】如何在 Go 中获取 Windows 进程的句柄?【英文标题】:How can I get handle of Windows process in Go? 【发布时间】:2018-12-21 07:59:09 【问题描述】:

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

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

句柄无效。

好吧,使用sys 的examples 的相同代码我创建了自己的“服务”,将beep 函数替换为RegisterDeviceNotification(与google 相同的代码)并发送名称我的服务和从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:如果我的问题存在任何问题,请告诉我以改进。

【问题讨论】:

你有没有进步? 查看 RegisterDeviceNotification 文档,您需要服务或窗口的句柄。也许有问题。 不,我没有任何进展 可惜。我遇到了类似的问题,如果我发现了什么会告诉你 服务类型有一个成员h,就是你需要的句柄。 github.com/golang/sys/blob/… 【参考方案1】:

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("%v\n", msg)

【讨论】:

【参考方案2】:

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)
    

【讨论】:

请添加更多详细信息来解释您的代码。

以上是关于如何在 Go 中获取 Windows 进程的句柄?的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个 .NET 进程获取对象的句柄?

如何从进程 ID 获取主窗口句柄?

如何从进程 ID 获取主窗口句柄?

如何在 C++ 中按名称获取进程句柄?

如何在C ++中通过其名称获取进程句柄?

如何获取窗体中组件的句柄