golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/ui/raise.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package ui
     7  
     8  import (
     9  	"os"
    10  	"runtime"
    11  
    12  	"github.com/lxn/win"
    13  	"golang.org/x/sys/windows"
    14  
    15  	"golang.zx2c4.com/wireguard/windows/l18n"
    16  )
    17  
    18  func raise(hwnd win.HWND) {
    19  	if win.IsIconic(hwnd) {
    20  		win.ShowWindow(hwnd, win.SW_RESTORE)
    21  	}
    22  
    23  	win.SetActiveWindow(hwnd)
    24  	win.SetWindowPos(hwnd, win.HWND_TOPMOST, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_SHOWWINDOW)
    25  	win.SetForegroundWindow(hwnd)
    26  	win.SetWindowPos(hwnd, win.HWND_NOTOPMOST, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_SHOWWINDOW)
    27  }
    28  
    29  func raiseRemote(hwnd win.HWND) {
    30  	runtime.LockOSThread()
    31  	defer runtime.UnlockOSThread()
    32  	win.SendMessage(hwnd, raiseMsg, 0, 0)
    33  	currentForegroundHwnd := win.GetForegroundWindow()
    34  	currentForegroundThreadId := win.GetWindowThreadProcessId(currentForegroundHwnd, nil)
    35  	currentThreadId := win.GetCurrentThreadId()
    36  	win.AttachThreadInput(int32(currentForegroundThreadId), int32(currentThreadId), true)
    37  	win.SetWindowPos(hwnd, win.HWND_TOPMOST, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_SHOWWINDOW)
    38  	win.SetWindowPos(hwnd, win.HWND_NOTOPMOST, 0, 0, 0, 0, win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_SHOWWINDOW)
    39  	win.SetForegroundWindow(hwnd)
    40  	win.AttachThreadInput(int32(currentForegroundThreadId), int32(currentThreadId), false)
    41  	win.SetFocus(hwnd)
    42  	win.SetActiveWindow(hwnd)
    43  }
    44  
    45  func RaiseUI() bool {
    46  	hwnd := win.FindWindow(windows.StringToUTF16Ptr(manageWindowWindowClass), nil)
    47  	if hwnd == 0 {
    48  		return false
    49  	}
    50  	raiseRemote(hwnd)
    51  	return true
    52  }
    53  
    54  func WaitForRaiseUIThenQuit() {
    55  	var handle win.HWINEVENTHOOK
    56  	runtime.LockOSThread()
    57  	defer runtime.UnlockOSThread()
    58  	handle, err := win.SetWinEventHook(win.EVENT_OBJECT_CREATE, win.EVENT_OBJECT_CREATE, 0, func(hWinEventHook win.HWINEVENTHOOK, event uint32, hwnd win.HWND, idObject, idChild int32, idEventThread, dwmsEventTime uint32) uintptr {
    59  		class := make([]uint16, len(manageWindowWindowClass)+2) /* Plus 2, one for the null terminator, and one to see if this is only a prefix */
    60  		n, err := win.GetClassName(hwnd, &class[0], len(class))
    61  		if err != nil || n != len(manageWindowWindowClass) || windows.UTF16ToString(class) != manageWindowWindowClass {
    62  			return 0
    63  		}
    64  		win.UnhookWinEvent(handle)
    65  		raiseRemote(hwnd)
    66  		os.Exit(0)
    67  		return 0
    68  	}, 0, 0, win.WINEVENT_SKIPOWNPROCESS|win.WINEVENT_OUTOFCONTEXT)
    69  	if err != nil {
    70  		showErrorCustom(nil, l18n.Sprintf("WireGuard Detection Error"), l18n.Sprintf("Unable to wait for WireGuard window to appear: %v", err))
    71  	}
    72  	for {
    73  		var msg win.MSG
    74  		if m := win.GetMessage(&msg, 0, 0, 0); m != 0 {
    75  			win.TranslateMessage(&msg)
    76  			win.DispatchMessage(&msg)
    77  		}
    78  	}
    79  }