- NSIS Discussion
- $(^Name) and MUI
Archive: $(^Name) and MUI
Asterix86
9th November 2008 10:20 UTC
$(^Name) and MUI
Hi,
I try to use the code from [1] to not allow 2 installers to run at the same time. The problem is that it uses $(^Name) to the window name. But I also use MUI, so window name changes according to the current page ("Language Installer", "Installation de XXX", ...)
So my question is: Is it possible to get all those window names from MUI so I can test them all to detect if installer is already running?
Thanks for your help,
Asterix
[1] http://nsis.sourceforge.net/Games_Ex...nce_at_a_time.
Animaether
9th November 2008 10:28 UTC
A much easier solution is to simply define your installer's name yourself as something unique and fixed.
!define myAppName "Asterix86-SomeAppName"
And then replace ${^Name} in the mutex code with ${myAppName}
Asterix86
9th November 2008 10:42 UTC
Will it really work? I mean user32::GetWindowText will return ${myAppName} ? I thought it returns window name ...
Animaether
10th November 2008 00:30 UTC
Don't use GetWindowText at all. You're just using a string (-any- string) and using windows' APIs to create a mutex. If you try to create a mutex with that same string, windows will return an error.
Thus in its simplest form:
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "hello") i .r1 ?e'
Pop $0
IntCmp $0 0 +2
MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running."
Asterix86
10th November 2008 05:52 UTC
ok, this is the first code of the example, but I like the second example that gives focus to the first installer when I run a second one. But for that, I need the window instance. In the example it's done by cycling on all NSIS windows and looking at its name. There is no problem if there is only one installer running, but if there are others you could give focus to the wrong one.
Animaether
10th November 2008 08:56 UTC
Well if finding the window (to give it focus) is the main issue, then we can ignore the mutex stuff ;)
You could...
- just hard code the various page titles, and test for each of the titles (lots of work and requires you to make sure each page title still fits any time you change your installer)
- prefix the page titles with a presumably unique string, in the existing script, this code..
StrCmp $2 "$(^Name)" 0 loop
Will then become something like
StrCpy $2 $2 length-of-prefix
StrCmp $2 "your-prefix" 0 loop
Very little work, and this is mostly maintenance-free, as long as you keep your prefix the same.
- let your installer write to the registry that it is running, and under what title (or maybe hwnd, as an integer), it can be found. That way you can just read that out directly.
This is a bit more work than the prefix method, but is somewhat more future-proof; if you don't like your page titles prefixed / or change the prefix in the future, that method will break - while your registry location probably wouldn't change.
This does mean registry i/o where it's not strictly necessary.
Ideally you'd somehow figure out who owns a mutex you're trying to create and which failed - but I don't think there's a way within the mutex object itself..
Asterix86
10th November 2008 15:56 UTC
I don't know how to access MUI window name (that was my first question) But I don't like the idea to prefix those names.
registery sounds a better solution, but there are several windows, so I have to change the hwnd when a new one open, and once again I don't know how to access it.
But that sounds too hard to achieve. So I'll stick with my simple solution, to focus the first NSIS installer. Most likely there will be only one.
Thanks a lot for your help though.
Animaether
11th November 2008 03:56 UTC
; findPrefixedWindow
; usage:
; Push "prefix"
; Call findPrefixedWindow
; Pop result
; Result will be empty and Error flag will be set if no window found
Function findPrefixedWindow
; Stack: <prefix>
Exch $0 ; Stack: $0
Push $1 ; Stack: $1 $0
Push $2 ; Stack: $2 $1 $0
Push $3 ; Stack: $3 $2 $1 $0
Push $4 ; Stack: $4 $3 $2 $1 $0
Push $5 ; Stack: $5 $4 $3 $2 $1 $0
Push $R0 ; Stack: $R0 $5 $4 $3 $2 $1 $0
; $0 - prefix
; $1 - prefix length
; $2 - window hwnd
; $3 - window text
; $4 - sub-part of window text
; $5 - callback identifier
; $R0 - callback pointer
StrLen $1 $0
SetPluginUnload alwaysoff
System::Get "(i.r2, i) iss"
Pop $R0
System::Call "user32::EnumWindows(k R0, i) i.s"
_loop:
Pop $5
StrCmp $5 "callback1" 0 _notfound
System::Call "user32::GetWindowText(ir2,t.r3,i${NSIS_MAX_STRLEN})"
StrCpy $4 $3 $1 ""
StrCmp $4 $0 _found _next
_next:
Push 1 # callback's return value
System::Call "$R0"
goto _loop
_found:
StrCpy $0 $3
goto _done
_notfound:
StrCpy $0 ""
SetErrors
_done:
SetPluginUnload manual
System::Free $R0
; Stack: $R0 $5 $4 $3 $2 $1 $0
Pop $R0 ; Stack: $5 $4 $3 $2 $1 $0
Pop $5 ; Stack: $4 $3 $2 $1 $0
Pop $4 ; Stack: $3 $2 $1 $0
Pop $3 ; Stack: $2 $1 $0
Pop $2 ; Stack: $1 $0
Pop $1 ; Stack: $0
Exch $0 ; Stack: <result>
FunctionEnd
Example use:
Function .onInit
StrCpy $R0 "${myPrefix}"
Push $R0
Call findPrefixedWindow
Pop $0
IfErrors _boo _yay
_boo:
MessageBox MB_OK "Could not find any window title beginning with: [$R0]"
goto _end
_yay:
MessageBox MB_OK "Found window title beginning with: [$R0]$\nWindow title: [$0]"
Abort
_end:
FunctionEnd
But you don't want prefixes, so that wouldn't help much.
As for the window handle thingy (hwnd)
$HWNDPARENT
The decimal HWND of the parent window.
Shouldn't change at all - for a single installer.. unless you're launching different installers throughout the installation.. which would be weird.
And there should be only one installer running, given that you wouldn't allow more than 1 installer to run at the same time (what all this code is partly about, no?)