WinMove to move an admin window? Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

WinMove to move an admin window?

Post by sirksel » 23 May 2022, 07:06

I have several hotkeys that trigger WinMove to move and/or resize the active window. They understandably never work on processes run as administrator. Say, for example, diskmgmt.msc is the target window. I get an access denied message when I try to move it. I think I understand WHY this is but I'm hoping there might me a way to fix it? Specifically,

1. Is there a way to detect that the window owner is admin and that the access denied is about to occur. I know I can use Try/Catch, but is there some attribute about a window of an admin process that I could check for programmatically to tell me to use the alternate approach?

2. Is there in fact an alternate approach to move such an admin window? Do I have to relaunch the script elevated as admin? Could I launch a helper script that could move it? I'm not sure where to start on this.

Any help or pointers would be much appreciated. Many thanks!

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: WinMove to move an admin window?  Topic is solved

Post by Helgef » 23 May 2022, 09:06

sirksel wrote:
23 May 2022, 07:06
1. Is there a way to detect that the window owner is admin and that the access denied is about to occur.
I tried (updated),

Code: Select all

IsElevated(pid) {	
    local result := false, proc
    local hToken := 0
    static TOKEN_QUERY := 0x0008
	static PROCESS_QUERY_INFORMATION := 0x0400 
	try {
		if ! proc := OpenProcess(PROCESS_QUERY_INFORMATION, false, pid) {
			static ERROR_ACCESS_DENIED := 0x5
			if !a_isadmin && a_lasterror == ERROR_ACCESS_DENIED
				return true ; probably :=)
			else throw OSError(,, 'OpenProcess')
		}
		if OpenProcessToken( proc, TOKEN_QUERY, &hToken )  {
			
			static sizeof_elevation := 4 
			static TokenElevation := 20
			local cbSize := 4
			local Elevation := 0
			
			if GetTokenInformation( hToken, TokenElevation, &Elevation, sizeof_elevation, &cbSize ) 
				result := Elevation
			else 
				throw OSError(,, 'GetTokenInformation')
			
		}
		else 
			throw OSError(,, 'OpenProcessToken') 
	} finally {
		if hToken
			CloseHandle hToken
		if proc
			CloseHandle proc
	}
	return result
	
	; Windows lib:
	/*
	HANDLE OpenProcess(
	[in] DWORD dwDesiredAccess,
	[in] BOOL  bInheritHandle,
	[in] DWORD dwProcessId
	);
	*/
	OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId)
		=> dllcall('Kernel32.dll\OpenProcess', 'uint', dwDesiredAccess, 'int', bInheritHandle, 'uint', dwProcessId, 'ptr')

   /*
   BOOL OpenProcessToken(
	[in]  HANDLE  ProcessHandle,
	[in]  DWORD   DesiredAccess,
	[out] PHANDLE TokenHandle
	);
	*/
	
   OpenProcessToken(ProcessHandle, DesiredAccess, &TokenHandle)
		=> dllcall('Advapi32.dll\OpenProcessToken', 'ptr', ProcessHandle, 'uint', DesiredAccess, 'ptr*', &TokenHandle, 'int')
   /*
   BOOL GetTokenInformation(
  [in]            HANDLE                  TokenHandle,
  [in]            TOKEN_INFORMATION_CLASS TokenInformationClass,
  [out, optional] LPVOID                  TokenInformation,
  [in]            DWORD                   TokenInformationLength,
  [out]           PDWORD                  ReturnLength
	);
   */
	GetTokenInformation(
		TokenHandle,
		TokenInformationClass,
		&TokenInformation,
		TokenInformationLength,
		&ReturnLength
	)
		=> dllcall('Advapi32.dll\GetTokenInformation',
			'ptr',		TokenHandle,
			'ptr',		TokenInformationClass,
			'uint*',	&TokenInformation,
			'uint',		TokenInformationLength,
			'uint*',	&ReturnLength
		)
	/*
	BOOL CloseHandle(
	[in] HANDLE hObject
	);
	*/
	CloseHandle(hObject)
		=> dllcall('Kernel32.dll\CloseHandle', 'ptr', hObject, 'int')	
	; from: https://stackoverflow.com/questions/8046097/how-to-check-if-a-process-has-the-administrative-rights
}
example,

Code: Select all

; run as admin for hotkeys to work
full_command_line := DllCall("GetCommandLine", "str")

if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
    try
    {
        if A_IsCompiled
            Run '*RunAs "' A_ScriptFullPath '" /restart'
        else
            Run '*RunAs "' A_AhkPath '" /restart "' A_ScriptFullPath '"'
    }
    ExitApp
}

z::tooltip IsElevated(wingetpid(winexist('a')))
x::exitapp

Do I have to relaunch the script elevated as admin?
If that works, I'd do that. I have no idea though.

Cheers.
Last edited by Helgef on 24 May 2022, 05:48, edited 2 times in total.

sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: WinMove to move an admin window?

Post by sirksel » 24 May 2022, 00:40

This is great!!! Thanks so much. I'm testing it now. I'm trying to see if I have to be elevated to call any of it... or if I can see if something is elevated before elevating my own script? I am not as good as I should be with the windows DLLs. I'll keep monkeying with it, but this helps immensely. If I refine the question more I'll post an update. In the meantime, I'm marking it solved. Thanks again @Helgef!

Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: WinMove to move an admin window?

Post by Helgef » 24 May 2022, 03:03

It seems you get an access denied error from OpenProcess if you are not elevated and the target process is. I updated the code above to handle it.

But, there might be situations when this error is thrown for other reasons.

Cheers.
Last edited by Helgef on 24 May 2022, 05:43, edited 1 time in total.

lexikos
Posts: 9552
Joined: 30 Sep 2013, 04:07
Contact:

Re: WinMove to move an admin window?

Post by lexikos » 24 May 2022, 05:42

A safer alternative to running the script as administrator is to run with UI access, but since you don't have the v2 installer yet, you would have to create the UIA executable manually. That can be done by copying a v2 executable and passing its path to EnableUIAccess() from the v1 installer (using AutoHotkey v1 to execute it, of course).

sirksel
Posts: 222
Joined: 12 Nov 2013, 23:48

Re: WinMove to move an admin window?

Post by sirksel » 24 May 2022, 06:29

Interesting. Thanks, @lexikos! So, if I'm thinking of just the WinMove action to move an admin-launched window... and assuming I don't want to be interrupted by the UAC elevation prompt (or whatever it's called) just to reposition the window... are you saying I would make a companion script that took command-line parameters of PID,x,y,w,h and run it whenever I needed to move/resize an admin-launched window (i.e. when I've caught the access denied error or foretold its occurrence using Helgef's code)? I'm trying to see how the "run with UI access" context menu thing then fits into all that. Am I somehow triggering that when I call the special purpose mover script with a command line switch, or do I have to right click on something?

Sorry if I'm being overly dense here... I think I'm just missing it. So bottom line is I have a script with many unrelated hotkeys (including WinMove to predefined regions) running without elevation. When that main script sees the "WinMove hotkey" has triggered relative to moving an admin window (Helgef's code), then I need to call a companion script (which I'm trying to flesh out now), but with UI access (Lexikos' link, which I don't completely understand how to trigger the elevation (a) in this way, (b) from another script, (c) without further user prompting). Is that right? Many thanks!

lexikos
Posts: 9552
Joined: 30 Sep 2013, 04:07
Contact:

Re: WinMove to move an admin window?

Post by lexikos » 25 May 2022, 04:32

The context menu item just causes the shell to execute something like "C:\Program Files\AutoHotkey\AutoHotkeyU64_UIA.exe" "%1" %*, where %1 is the selected file and %* is usually empty. You don't need to use the context menu for this any more than for any of the other context menu items.
Scripts which need to run other scripts with UI access can simply Run the appropriate UIA.exe file with the normal command line parameters.
Source: Using the Program | AutoHotkey
I don't use the context menu, and wouldn't be bothered with switching to UIA at the last minute; I just run my main hotkey and gesture scripts with AutoHotkeyU32_UIA.exe via Run in a startup script.

In its current unreleased form, the v2 installer automatically and unconditionally creates the UIA files. After installation, it is possible to set (via a simple checkbox) v1 and/or v2 scripts to run with UI access by default. The installer and related scripts are nearly at a point where I am ready to share them for more testing.

IMTheNachoMan
Posts: 59
Joined: 01 Mar 2022, 17:07
Contact:

Re: WinMove to move an admin window?

Post by IMTheNachoMan » 25 Sep 2023, 22:31

@Helgef That is great. Thank you so much!

Post Reply

Return to “Ask for Help (v2)”