Old 4th September 2022, 13:45   #1
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
SetForegroundWindow by PID

Hello everyone, this is my first post so please be gentle - if there is something wrong about the question format, let me know.

My intention is to bring a window back to foreground with my Process ID.

Here is what I'v found so far:

code:
Function .onGUIEnd
FindWindow $0 "WindowClass" "Title"
IsWindow $0 0 +2
System::Call 'user32::SetForegroundWindow(i r0)'



It works, but to make absolutely sure choosing the correct application (in case of multilingual or same name of windows), I would rather bring the window to foreground providing the process ID, not the window class or the title. I already have my necessary PID.

Do you have any ideas how I can perform the SetForegroundWindow with PID?
Dragodraki is offline   Reply With Quote
Old 4th September 2022, 15:50   #2
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,538
PHP Code:
FindWindow $....
System::Call 'USER32::GetWindowThreadProcessId(p$0,*i0r1)'
${If} $$mypid ... 
It is possible to call FindWindow in a loop by using the childafter parameter...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 5th September 2022, 19:59   #3
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
Thank you very much. I'll try it out the next days.
Dragodraki is offline   Reply With Quote
Old 8th September 2022, 14:22   #4
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
Unfortunately it doesn't work:
Error: unterminated string parsing line at C:\InnoSetup-Software\Source - NSIS\Focus.nsi:52

-> System::Call 'USER32::GetWindowThreadProcessId(p$0,*i0r1)

!include LogicLib.nsh
;!define mypid "3044"

Function .onGUIEnd
FindWindow $0 "" "Aqua'S KeyTest"
IsWindow $0 0 +2
System::Call 'USER32::GetWindowThreadProcessId(p$0,*i0r1)
${If} $1 == $mypid
System::Call 'user32::SetForegroundWindow(i r0)'
${EndIf}
FunctionEnd



Can you send me a little more specific code example I can work with?
Dragodraki is offline   Reply With Quote
Old 8th September 2022, 15:43   #5
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,538
Just a typo, missing the final '. I edited my post.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 9th September 2022, 11:43   #6
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
thanks, the line is accepted now.

But I'm afraid I dont know how to search trough all windows in a loop until the process id matches the defined one (that was passed as argument to .exe). That's the final taget for my project.

The code I've now shows endless the same item and can't compare the id I gave as parameter (not even when hardcoded as variable) - it always says they match.

Can you help me a little bit with this task as I'm very new to NSIS and struggling with the help websites at all?
Dragodraki is offline   Reply With Quote
Old 9th September 2022, 13:52   #7
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
Got a few steps close to my aim, but fails if there are two instances of the Windows. The script should go through all one after the other...



Function .onGUIEnd
loop:
Pop $0
StrCpy $mypid "2424"
;FindWindow $0
;IsWindow $0 0 +2
;System::Call 'user32::SetForegroundWindow(i r0)'

FindWindow $0 "" "AquaKeyTest"
IsWindow $0 0 +2
System::Call 'USER32::GetWindowThreadProcessId(p$0,*i0r1)'
MessageBox MB_OK "mypid(Gesucht)=$mypid und PID(Gefunden)=$1"
${If} $1 = $mypid
MessageBox MB_OK "Test"
System::Call 'user32::SetForegroundWindow(i r0)'
IsWindow $0 done
${EndIf}
System::Call "$R0"
goto loop
Dragodraki is offline   Reply With Quote
Old 11th September 2022, 20:15   #8
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,538
PHP Code:
!include LogicLib.nsh
!include WinMessages.nsh
ExecShell 
'' Notepad '' SW_SHOWMINIMIZED Instance we don't care about
!define /IfNDef STARTF_USESHOWWINDOW 0x0001
!define /IfNDef SW_SHOWMINNOACTIVE 7
System::Call '
*(&l${NSIS_PTR_SIZE},p,p,p,i,i,i,i,i,i,i,${STARTF_USESHOWWINDOW},${SW_SHOWMINNOACTIVE},p,p,p,p)p.r1'
System::Call '
*(p,p,i,i)p.r2'
System::Call '
KERNEL32::CreateProcess(p0,"notepad.exe",p0,p0,i0,i0,p0,p0,pr1,pr2)i.r0'
${If} $0 <> 0
    System::Call "*$2(p.r3,p.r4,i.r0,i)"
    System::Call '
KERNEL32::CloseHandle(pr3)'
    System::Call '
KERNEL32::CloseHandle(pr4)'
${EndIf}
System::Free $1
System::Free $2
ExecShell '' Notepad '' SW_SHOWMINIMIZED ; Instance we don'
t care about
Sleep 1234 
Wait for Notepad to start

!define CLASS "Notepad"
StrCpy $""
loop:
FindWindow $"${CLASS}" "" "" $2
StrCpy 
$$1
${If} $1 P<> 0
${AndIf} $<> PID
    System
::Call 'USER32::GetWindowThreadProcessId(p$1,*i0r3)'
    
System::Call 'USER32::IsWindowVisible(p$1)i.r4'
    
${If} $= $0
    
${AndIf} $<> 0
        System
::Call 'USER32::SetForegroundWindow(p$1)'
        
System::Call 'USER32::SwitchToThisWindow(p$1,i1)'
    
${Else}
        Goto 
loop
    
${EndIf}
${EndIf} 

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 12th September 2022, 15:12   #9
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
!include WinMessages.nsh
!include LogicLib.nsh
StrCpy $mypid "4128" ;example PID (ok) - later this should applied from command-line parameter

StrCpy $2 ""
loop:
FindWindow $1 "" "Aquakeytest" "" $2 ;Windowtitle (not ok) should be determined automatically from PID
StrCpy $2 $1
${If} $1 P<> 0
;${AndIf} $0 <> 0 ; PID
System::Call 'USER32::GetWindowThreadProcessId(p$1,*i0r3)'
;MessageBox MB_OK "mypid(Search)=$mypid und PID(Found)=$3"
${If} $3 = $mypid
System::Call 'USER32::SetForegroundWindow(p$1)'
System::Call 'USER32::SwitchToThisWindow(p$1,i1)'
${Else}
Goto loop
${EndIf}
${EndIf}


Thank you very much - I changed the code a little bit so that it compares the result with my defined PID and use an existing process in general instead of creating a new one. So far it works.
Now the PID and Windowtitle is necessary to know, but the Windowtitle should be created from PID automatically - is this possible?
Dragodraki is offline   Reply With Quote
Old 12th September 2022, 15:54   #10
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,538
Not sure I understand. If you don't know the window title you can leave it as "" like my example.

If you know the title and the pid is part of it then you don't even need the loop

Quote:
StrCpy $mypid ....
; if the title is "fooPIDbar"
FindWindow $1 "AquaKeyTest" "foo$mypidbar"

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 13th September 2022, 10:06   #11
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
Yes, I don't know the title, so the query for PID is indeed necessary.

But if I try to leave the title blank (FindWindow $1 "" "" "" $2), it doesn't work - in this case the entry it shows does't fit (${If} $1 P<> 0 seems to fail) and it repeats the loop infinte.

So I have to retrieve the windotitle from pid before everything else... but how can I achieve this?
Dragodraki is offline   Reply With Quote
Old 13th September 2022, 17:26   #12
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,538
There is nothing stopping you from enumerating all windows if you don't know the title nor class. If your loop is infinite you have a bug somewhere.

PHP Code:
!include LogicLib.nsh
Section
StrCpy 
$""
loop:
    
FindWindow $"" "" "" $2
    StrCpy 
$$1
    
${If} $1 P<> 0
        System
::Call 'USER32::IsWindowVisible(p $1)i.r4'
        
System::Call 'USER32::GetWindowText(p $1, t ""r5, i ${NSIS_MAX_STRLEN})'
        
${If} $!= ""
        
${AndIf} $<> 0
            DetailPrint 
"Visible window $1 has title $5"
        
${EndIf}
        Goto 
loop
    
${EndIf} 
SectionEnd 

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 19th September 2022, 11:30   #13
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
Thank you - you code works like a charm now!

May I ask to help me one more time?
How can I compare the process name instead of the PID if the process name is known only?

Input (search): -Process name-
Output (found): -Process name- for "p $1"

I tried with GetWindowModuleFilename, GetModuleBaseName and several others too, but never get a result at all.
Dragodraki is offline   Reply With Quote
Old 19th September 2022, 12:50   #14
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,538
Those functions only work for the current process. https://stackoverflow.com/questions/...me-of-a-window

I'd say, use one of the process plug-ins, https://nsis.sourceforge.io/PS_plug-in etc.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 19th September 2022, 14:05   #15
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
Unfortunately, I tried already. Either they don't include retrieving process name or it simply don't work.
I managed to call a result via wmic, but I cant get it to display each line of the variable separately.
Dragodraki is offline   Reply With Quote
Old 19th September 2022, 14:38   #16
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,538
Seems to me you did not try very hard.
PHP Code:
!include LogicLib.nsh
Function PSEnum
${If} $$MyPid
    DetailPrint 
"Found $1"
    
StrCpy $""
${EndIf}
FunctionEnd
 
Section
GetFunctionAddress 
$0 PSEnum
PS
::Enum $0
SectionEnd 

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 19th September 2022, 15:22   #17
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
Maybe, but I didn't focus on that one

In the meantime I get another solution with wmic... it's slow but seems to work:

Quote:
Call_ProcessName:

StrCpy $2 ""
searchnamecontinue:
FindWindow $1 "" "" "" $2
StrCpy $2 $1
${If} $1 P<> 0
System::Call 'USER32::GetWindowThreadProcessId(p$1,*i0r3)'
System::Call 'USER32::IsWindowVisible(p $1)i.r4'
System::Call 'USER32::GetWindowText(p $1, t ""r5, i ${NSIS_MAX_STRLEN})'
${If} $5 != ""
${AndIf} $4 <> 0
nsExec::ExecToStack "wmic process where $\"name like '$ProcessID' and ProcessID like '$3'$\" get processid
/format:$\"$PLUGINSDIR\${XlsSheet}$\""
Pop $0
Pop $7
${StrRep} $7 $7 "processid=" ""
Push ' $7 '
Call Trim
Pop $8 ;$8 now contains the trimmed string.
${If} $3 == $8
;MessageBox MB_OK "Erkannt! PID: $3"
System::Call 'USER32::SetForegroundWindow(p$1)'
System::Call 'USER32::SwitchToThisWindow(p$1,i1)'
${EndIf}
${EndIf}
Goto searchnamecontinue
${EndIf}
Goto EndSearch
Dragodraki is offline   Reply With Quote
Old 28th September 2022, 08:32   #18
Dragodraki
Junior Member
 
Join Date: Sep 2022
Posts: 11
OK, with WMIC as for prcessname-based call and some other improvements here is my final solution as a ready-to-use binary download:

https://github.com/Dragodraki/BringExeToFront

Hope, that helps somebody else in the future.
Dragodraki is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Tags
findwindow, process id, setforegroundwindow

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump