Reputation: 498
I'm trying to call function RegisterDeviceNotificationW
of user32.dll
. But the first param of the function is the "handle to the window or service that will receive device events" (this I getted from Microsoft).
Based on Cloud Printer Connector I tried to get the handler with svc.StatusHandler()
, but does not work for me, every time I run I get the follow error:
The handle is invalid.
Well, using the same code of the examples of sys
I created my own "service", replacing the beep
function by RegisterDeviceNotification
(the same code of google) and sent the name of my service and the value returned from svc.StatusHandler()
, but I received again the same message: "The handle is invalid."
var (
u32 = syscall.MustLoadDLL("user32.dll")
registerDeviceNotificationProc = u32.MustFindProc("RegisterDeviceNotificationW")
)
Here is where I need sent a valid Handler
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(¬ificationFilter)), 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)
}
NOTE: I tried too with the pointer of "myService":
h := windows.Handle(uintptr(unsafe.Pointer(m)))
err := RegisterDeviceNotification(h)
EDIT: I tried with GetCurrentProcess, but does not work:
Retrieves a pseudo handle for the current process.
h, err := syscall.GetCurrentProcess()
err = RegisterDeviceNotification(windows.Handle(h))
The question: How can I get a valid handle of the process in Go?
PS: If exists any problem with my question, please, let me know to improve.
Upvotes: 14
Views: 5763
Reputation: 6561
Here's how you can get the handle of a process given the 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
}
I believe you also need to make sure to call windows.CloseHandle(handle)
when you are done with it.
Full example:
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()
}
Upvotes: 1
Reputation: 371
Here's some code I wrote a while ago to handle this, it was working last time I checked. I've created wrapper functions for a bunch of winapi calls.
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
}
Make sure to close the handle when you're done using it, don't want to keep random handles open indefinitely.
Here's some resources to help you with what's going on here:
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
Upvotes: 1
Reputation: 139
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)
}
}
Upvotes: 1
Reputation: 1610
syscall.GetCurrentProcess () can be used like this.
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)
}
Upvotes: 1