find hwnd on win 10

427 views
Skip to first unread message

Robert Solomon

unread,
Jun 20, 2022, 7:24:01 PM6/20/22
to golang-nuts
Hi.  I'm struggling to get this code to return a non-zero hwnd.  I'm compiling w/ Go 1.18.3
Any help would be most appreciated.
package main

import (
"fmt"
w32a "github.com/JamesHovious/w32"
w32 "github.com/gonutz/w32/v2"
"runtime"

const lastModified = "June 20, 2022"

func main() {

fmt.Printf("goclicksimple to use Go to activate a process so can be clicked on the screen. Last modified %s. Compiled by %s\n",
lastModified, runtime.Version())

fmt.Printf(" Now to use w32.FindWindow\n")

target := "*firefox*"
hwnd := w32.FindWindow("MDIClient", target)
fmt.Printf(" target=%q, MDIClient hwnd=%d\n", target, hwnd)

hwnd = w32.FindWindow("", target)
fmt.Printf(" target=%q, empty class hwnd=%d\n", target, hwnd)

hwnd = w32.FindWindow("*", target)
fmt.Printf(" target=%q, * hwnd=%d\n", target, hwnd)

hwnd = w32.FindWindow("*lient*", target) // covers Client and client
fmt.Printf(" target=%q, *lient* hwnd=%d\n", target, hwnd)

var classString string
hwnd2 := w32a.FindWindowS(&classString, &target)
fmt.Printf(" w32a.FindWindowS empty class, target=%q, hwnd2=%v\n", target, hwnd2)

classString = "*"
hwnd2 = w32a.FindWindowS(&classString, &target)
fmt.Printf(" w32a.FindWindowS '*' class, target=%q, hwnd2=%v\n", target, hwnd2)

classString = "*lient*"
hwnd2 = w32a.FindWindowS(&classString, &target)
fmt.Printf(" w32a.FindWindowS '*lient*' class, target=%q, hwnd2=%v\n", target, hwnd2)

classString = "*lass*"
hwnd2 = w32a.FindWindowS(&classString, &target)
fmt.Printf(" w32a.FindWindowS '*lass*' class, target=%q, hwnd2=%v\n", target, hwnd2)
}

Howard C. Shaw III

unread,
Jun 21, 2022, 10:18:02 AM6/21/22
to golang-nuts
On what basis are you using globs ("*lient*", etc) in FindWindow? If I understand correctly, the w32 and w32a packages are just wrapping Windows APIs, so the semantics of the use should match the equivalent use of the windows API. The documentation for FindWindow says "Retrieves a handle to the top-level window whose class name and window name match the specified strings." - that does not appear to me to be implying that it supports globbing.


You might find the EnumWindows function more useful, as you can loop over the returned windows, and use GetClassName and GetWindowText to get some text you can then compare against.

 

Robert Solomon

unread,
Jun 26, 2022, 12:58:50 PM6/26/22
to golang-nuts
The following code will flash the found window on the task bar, but will not show it so I can see it.  I'm looking for something that is similar to takecommand by JPSoft, which has an activate command that will make the desired window pop up and be active.

package main

import (
"flag"
"fmt"
w32a "github.com/JamesHovious/w32"
ct "github.com/daviddengcn/go-colortext"
ctfmt "github.com/daviddengcn/go-colortext/fmt"
w32 "github.com/gonutz/w32/v2"
"os"
"runtime"
"strings"
"time"
// ps "github.com/mitchellh/go-ps"
//"github.com/lxn/win" I can't get this to be useful.
//w32 "github.com/gonutz/w32/v2" I also can't get this to be useful.
//w32a "github.com/JamesHovious/w32"
// ct "github.com/daviddengcn/go-colortext"
// ctfmt "github.com/daviddengcn/go-colortext/fmt"
)

const lastModified = "June 26, 2022"

const (
SW_HIDE = iota // 0 = hide window and activate another one
SW_ShowNormal // 1 = activates and displays a window. If window is min'd or max'd, restores it to its original size and posn. App should use this when 1st showing window.
SW_ShowMinimized // 2 = activate the window and display it minimized.
SW_ShowMaximized // 3 = activate the window and display it maximized.
SW_ShowNoActivate // 4 = display window in its most recent size and position, but window is not activated.
SW_Show // 5 = activate window and display it in its current size and posn.
SW_Minimize // 6 = minimize window and activate the next top-level window in the Z-order.
SW_MinNoActive // 7 = display the window as a minimized window, but don't activate it.
SW_ShowNA // 8 = display the window in its current size and position, but don't activate it.
SW_Restore // 9 = activate and display the window, and if min or max restore it to its original size and posn.
SW_ShowDefault // 10 = sets the show state based on the SW_ value specified in the STARTUPINFO struct passed to the CreateProcess fcn by the pgm that started the app.
SW_ForceMinimize // 11 = minimize the window even if the thread that started it is not responding. Should only be used for windows from a different thread.
)

var target = "w32" // this is a firefox window that's opened.

type htext struct {
h w32.HWND
title string // this is the title of the window as returned by w32.GetWindowText
isWindow bool
isEnabled bool
isVisible bool
className string
}

func main() {
fmt.Printf("w32 testing routine. Last modified %s. Compiled by %s\n",
lastModified, runtime.Version())

flag.Parse()

// w32 section

foreground := w32.GetForegroundWindow() // this is the same as forgroundWindowH below.
focus := w32.GetFocus()
fmt.Printf(" ForegroundWindow()=%v, Getfocus() = %v\n", foreground, focus)

activeWindowH := w32.GetActiveWindow() // these are of type hwnd. This one is zero.
consoleWindowH := w32.GetConsoleWindow() // this one is 69412 from both w32 and w32a routines
desktopWindowH := w32.GetDesktopWindow() // this one is 65552
foregroundWindowH := w32.GetForegroundWindow() // this one is 131244
consoleW32a := w32a.GetConsoleWindow() // this one is same as from w32, and is 69412 this run.
topWindowH := w32.GetTopWindow(foregroundWindowH) // this one is 68854.
fmt.Printf(" HWND for ... ActiveWindow = %d, ConsoleWindow = %d and %d, DesktopWindow = %d, ForegrndWin = %d, prev foregroundwin = %d, topwin=%d\n",
activeWindowH, consoleWindowH, consoleW32a, desktopWindowH, foregroundWindowH, foreground, topWindowH)

fmt.Printf("\n--\n")

w32ProcessIDs, ok := w32.EnumAllProcesses()
fmt.Printf(" EnumAllProcesses returned ok of %t and %d processes.\n\n", ok, len(w32ProcessIDs))

computerName := w32.GetComputerName()
version := w32.GetVersion() // don't know what this means.
fmt.Printf(" ComputerName = %v, version = %v\n\n", computerName, version)

hwndText := make([]htext, 0, 1000) // magic number I expect will be large enough.

enumCallBack := func(hwnd w32.HWND) bool {
if hwnd == 0 {
return false
}

ht := htext{
h: hwnd,
title: strings.ToLower(w32.GetWindowText(hwnd)),
isWindow: w32.IsWindow(hwnd),
isEnabled: w32.IsWindowEnabled(hwnd),
isVisible: w32.IsWindowVisible(hwnd),
}
ht.className, _ = w32.GetClassName(hwnd)
hwndText = append(hwndText, ht)
return true
}
w32.EnumWindows(enumCallBack)
ctfmt.Printf(ct.Green, true, " \n Found %d elements in the hwnd text slice. \n Now will find the target of %q.\n", len(hwndText), target)

var ctr int
var found bool

for i, ht := range hwndText {
if ht.title == "" {
continue // skip the Printf and search
}

ctr++

fmt.Printf(" i:%d; hwnd %d, title=%q, isWndw %t, isEnbld %t, isVis %t; className = %q\n",
i, ht.h, ht.title, ht.isWindow, ht.isEnabled, ht.isVisible, ht.className) // className is of type string.

if ctr%40 == 0 && ctr > 0 {
if pause() { // allows exiting the test if 'n' is hit.
os.Exit(0)
}
}

if target != "" && strings.Contains(ht.title, target) {
found = true
} else {
found = false
}

if found {
ctfmt.Printf(ct.Yellow, true, " window is found. Will now attempt to activate it.\n")
hWnd := ht.h

ctfmt.Printf(ct.Magenta, true, " hWnd = %d\n", hWnd)
ok2 := w32.ShowWindow(hWnd, SW_ShowNormal)
time.Sleep(10 * time.Millisecond)
ok3 := w32.ShowWindow(hWnd, SW_Restore)
time.Sleep(10 * time.Millisecond)
ok4 := w32.ShowWindow(hWnd, SW_Show)
time.Sleep(10 * time.Millisecond)
ok6 := w32.ShowWindow(hWnd, SW_Restore)
time.Sleep(10 * time.Millisecond)
ok7 := w32.SetForegroundWindow(hWnd)
fmt.Printf(" hwnd[%d]=%d, ShowWindow Normal = %t, Restore = %t, Show = %t, Restore = %t and setforegroundwindow = %t.\n",
i, hWnd, ok2, ok3, ok4, ok6, ok7)
pause()
}
}
}

// --------------------------------------------------------------------------------------------

func pause() bool {
fmt.Print(" Pausing. Hit <enter> to continue. Or 'n' to exit ")
var ans string
fmt.Scanln(&ans)
ans = strings.ToLower(ans)
if strings.Contains(ans, "n") {
return true
}
return false
}

Howard C. Shaw III

unread,
Jun 26, 2022, 3:44:01 PM6/26/22
to golang-nuts

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow

"The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:
  • The process is the foreground process.
  • The process was started by the foreground process.
  • The process received the last input event.
  • There is no foreground process.
  • The process is being debugged.
  • The foreground process is not a Modern Application or the Start Screen.
  • The foreground is not locked (see LockSetForegroundWindow).
  • The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
  • No menus are active.
An application cannot force a window to the foreground while the user is working with another window. Instead, Windows flashes the taskbar button of the window to notify the user."


This is more of a Windows API question than a Golang question, so you might do better to direct your questions to a Windows forum. The second link above does describe a workaround involving AttachThreadInput. I'm not sure if w32 has that function mapped or not - if not, you can try https://pkg.go.dev/github.com/xpzed/win32

Good luck!

Robert Solomon

unread,
Jun 27, 2022, 6:04:25 PM6/27/22
to golang-nuts
Howard, based on your advice, my basic code now works as I wanted.  I got it working without needing xpzed/win32.

Thank you again.
--rob solomon
Reply all
Reply to author
Forward
0 new messages