- NSIS Discussion
- FileLocked or FileInUse
Archive: FileLocked or FileInUse
zanz
21st July 2008 20:25 UTC
FileLocked or FileInUse
Searching these forums, I've haven't gotten a clear answer to this question:
How or what's the best way to detect a file that's locked by Windows or in use by another process?
Is there anything equivalent to IsFileLocked? or IsFileInUse in NSIS? that would return true or false depending if the file is locked or not? Any plugins (I couldn't find a built in function in the documentation either).
If there are no docs or plug-ins, then any guidance would be really appreciated on how i can get status of a file before uninstalling or upgrading the product.
Thanks!
LoRd_MuldeR
21st July 2008 20:36 UTC
I think this code should be enough:
ClearErrors
FileOpen $0 "$INSTDIR\Filename.foo" a
IfErrors FileIsLocked
FileClose $0
Goto FileIsNotLocked
FileIsLocked:
...
FileIsNotLocked
...
You could create a simple macro:
!define IfFileLocked "!insertmacro _IfFileLocked"
!macro _IfFileLocked label
ClearErrors
FileOpen $0 "$INSTDIR\Filename.foo" a
IfErrors ${label}
FileClose $0
!macroend
[...]
Section
${IfFileLocked} "$INSTDIR\Filename.foo" FileLocked
[...]
FileLocked:
...
SectionEnd
Afrow UK
21st July 2008 21:15 UTC
The LockedList plug-in may be handy.
Another option also is to replace files on reboot if they cannot be replaced there and then:
!macro InstallOnReboot Source Destination
SetFileAttributes `${Destination}` NORMAL
File `/oname=${Destination}.new` `${Source}`
Delete /rebootok `${Destination}`
Rename /rebootok `${Destination}.new` `${Destination}`
!macroend
!insertmacro InstallOnReboot file.exe $INSTDIR\file.exe
The MUI finish page will automatically have reboot now/reboot later options if the reboot flag gets set. Notice the SetFileAttributes. This allows files with hidden+system attributes to be overwritten.
Stu
zanz
21st July 2008 22:41 UTC
Thanks Stu,
Very useful suggestions. I'm going to test out each one of those options. I might have additional questions, but thanks so much for helping me out.
Zan
zanz
22nd July 2008 00:17 UTC
I noticed that Processes::FindProcess "MyProcessName" can also find a process that's running.
How reliable is the 'Process' plug-in, VS writing a function suggested by LoRd_MuldeR, and Stu?
LoRd_MuldeR
22nd July 2008 00:21 UTC
Well, Processes::FindProcess will find a running processes of a given name, while the functions suggested in this threads will check write-access to a given file. These are two completely different things! If you want to overwrite/replace a specific file, then you should check for write-access to this file. The file might be locked by some process you don't even know about! If you want to check whether a certain process is running or not, then use Processes::FindProcess instead...
zanz
22nd July 2008 00:31 UTC
Oh,okay...In that case I guess what I'm looking for is FindProcess. What I need to implement is to check if one of the executables of our software is running when the user:
1) Uninstalls
2) Upgrades/ or a patch install is launched.
In case if the executable/process is running, we'll prompt the user that "MyProcessName" is running. The user will need to quit the executable/process before 'Uninstalling' or Upgrading or press a button (i.e. 'Ignore') and we'll kill the process automatically.
If FindProcess can find a process with the given name, then I’ll just add the logic in a function to kill the process automatically if the user chooses that option. FindProcess is something I was looking for. I do not need to modify a locked file.
Thanks so much for the input!
LoRd_MuldeR
22nd July 2008 00:35 UTC
Yes, it seems that Processes::FindProcess is able to do what you want to achieve. Just keep in mind that the user might have renamed the executable file (.exe) to something else. In that case the process would also have a different name! So you cannot find it with Processes::FindProcess any more. The process might be running and your installer won't notice...
zanz
22nd July 2008 00:44 UTC
Thanks LoRd_MuldeR, you're absolutely correct about renaming part. We'll be at the mercy of user not renaming the executable. But FindProcess is exactly what I was looking for. Life is a lot easier with it. Thanks so much for helping me out.
LoRd_MuldeR
22nd July 2008 00:54 UTC
You could register a custom message using RegisterWindowMessage. Your application would listen for that message and exit immediately when the message is received. So your installer would simply broadcast that message to all processes and it can be sure your application will exit, if running. This will still work if the executable/process was renamed. Only problem I see is: The application might be busy or in an erroneous state. In that case it can't react to message immediately, maybe it won't exit at all. Maybe you combine both methods to be sure? First broadcast the message, then wait for a certain timeout and finally search/kill the process with the Processes plugin...
LoRd_MuldeR
22nd July 2008 02:12 UTC
If you just want to check whether an application is running or not, the best way is using a named Mutex by calling CreateMutex. Your application will create the named mutex at startup. It will destroy the mutex implicitly at termination. Your installer can simply try to create the same Mutex and it will get ERROR_ALREADY_EXISTS in case the application is running. I implemented that method several times to make sure only one instance of my application or installer is running at a time...
This macro will prevent multiple instances of your installer:
!define MUTEX "{083f1034-700a-4109-ae41-e36e97d618c2}"
!macro CheckInstances skip
!define ID ${__LINE__}
Push $0
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${MUTEX}") i .r1 ?e'
Pop $0
StrCmp $0 0 InstallerNotRunningYet_${ID}
MessageBox MB_OK|MB_ICONEXCLAMATION|MB_TOPMOST "$(AlreadyRunning)"
Quit
InstallerNotRunningYet_${ID}:
Pop $0
!undef ID
!macroend
Should be easy to adapt to check for a running application...
Afrow UK
22nd July 2008 12:35 UTC
Just to let you know none of the processes plug-ins (such as FindProcDll or Processes) work on Vista. I have not tested LockedList on Vista (had better though!)
Stu
zanz
22nd July 2008 17:18 UTC
LoRd_MuldeR, I will be looking into the macro you wrote. Thanks!
Stu,
I haven't tested the installer on Vista yet either, but Process::FindProcess works well on XP.
So you're 100% that it won't work on Vista? (I will test it sometime today).
Afrow UK
22nd July 2008 17:48 UTC
Although I have not tried it myself, you can search the forum and you will find a few topics.
Stu