Skip to content

runtime: Windows callbacks are not working #59650

Closed
@vault-thirteen

Description

@vault-thirteen

What version of Go are you using (go version)?

1.20.3.

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

Windows 10,
Intel x86-64.

What did you do?

I create a callback and try to get it working.
I create a hook method to listen to system's events from a keyboard.
I send some keyboard events, but the callback is not started.
When the callback should be "fired", it does not "fire".

Code example is following.

package main

import "C"
import (
	"fmt"
	"log"
	"time"

	"golang.org/x/sys/windows"
)

var (
	kernel32DLL = windows.NewLazySystemDLL("kernel32.dll")
	user32DLL   = windows.NewLazySystemDLL("user32.dll")

	procGetCurrentThreadId = kernel32DLL.NewProc("GetCurrentThreadId")
	procSetWindowsHookExW  = user32DLL.NewProc("SetWindowsHookExW")
	procCallNextHookEx     = user32DLL.NewProc("CallNextHookEx")
)

var hook uintptr

const (
	// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw
	WH_KEYBOARD    = 2
	WH_KEYBOARD_LL = 13
)

func mustBeNoError(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	var err = kernel32DLL.Load()
	mustBeNoError(err)
	defer func() {
		derr := windows.FreeLibrary(windows.Handle(kernel32DLL.Handle()))
		if derr != nil {
			log.Println(derr)
		}
	}()

	err = user32DLL.Load()
	mustBeNoError(err)
	defer func() {
		derr := windows.FreeLibrary(windows.Handle(user32DLL.Handle()))
		if derr != nil {
			log.Println(derr)
		}
	}()

	threadId, _, _ := procGetCurrentThreadId.Call()
	fmt.Println("ThreadId:", threadId)

	//callback := syscall.NewCallback(callbackFunc)
	callback := windows.NewCallback(callbackFunc)
	defer func() {
		// Callback release is not available in Golang.
		// What should I do when the limit is reached ? ...
	}()

	hook, _, _ = procSetWindowsHookExW.Call(WH_KEYBOARD, callback, 0, threadId)
	fmt.Println("hook:", hook)

	time.Sleep(time.Second * 10)
}

func callbackFunc(code, wParam, lParam uintptr) uintptr {
	ret, _, _ := procCallNextHookEx.Call(hook, code, wParam, lParam)
	fmt.Println("inside callbackFunc")
	return ret
}

I tried:

  • callback := syscall.NewCallback(callbackFunc)
  • callback := windows.NewCallback(callbackFunc)
  • with import "C"
  • without import "C"
  • WH_KEYBOARD
  • WH_KEYBOARD_LL

but the result stays the same. It does not work.

What did you expect to see?

I expect to see working callbacks on Windows O.S. in Golang.

What did you see instead?

I see broken callbacks on Windows O.S. in Golang.

Program's output was:

ThreadId: 12984
hook: 30737909

Metadata

Metadata

Assignees

Labels

FrozenDueToAgeOS-WindowsWaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions