How to locate the current path of a Windows service in Qt? - c++

I have an application which is installed and run as a Windows service. In a given time, I need to locate the current application path (that is, the installation path) where other, needed files are located.
Unfortunately I'm being unable to find this directory using the traditional methods (QCoreApplication::applicationDirPath(), dir.absolutePath(), QDir::currentPath()). Every time this functions are called, they either return blank or the system32 folder.
I tried to improvise using QStandardPaths::findExecutable, but it didn't solve my problems. My last resort for now is creating a script that creates an entry in the registry telling the service where to look for, but since the installation is supposed to be just an "extract from compressed file", I'd like to avoid this option.
So which other method Qt makes available to make this specific circunstancial task?

Related

How to execute code after application closure?

for a self-built installer I need a way to execute code after closing of an application itself.
Application structure
Main application: The installer is started from it when needed, it closes itself in the process.
Installer: This is also located in the folder of the main application and therefore also accesses all dll files. When an update is available, a zip file is first downloaded and then unpacked into the temp folder. Afterwards, all files are moved from there to the shared application directory.
The problem
The problem is that the updater can only update a few dll files at runtime that are not used by itself, because some are write-protected due to the installer's access.
A solution
Moving the files from the temp folder to the shared application folder must happen after closing the installer. But I don't know how to realize that.
Thanks a lot!
If your problem are the DLLs shared by the installer and main application, then you can do this: Before you run the installer, your main application can copy all the needed DLLs and the installer EXE from your main application folder to a temporary folder and run it from there. Your installer must then only wait until the main application gets closed and then replace all its files in the main folder. And once your update is finished, delete this temporary copy of the installer with its DLLs.
Note that if you want to overwrite files in Program Files folder, your installer will have to be run with elevated privileges. Google for "runas" command... you will need it when starting your installer with QProcess.
But there may be also other problems. If your first installation was with normal installer, it typically creates some entries in registry and also generates list of files for later uninstall. And if your new versions will contain different files than originally installed version, then your subsequent uninstall may malfunction or may leave some files existing on users' computers. And you certainly do not want this.
And yet another potential problem. You may have running several instances of your application. In that case quitting one instance will still leave the other instances running and hence their files will not be replacable by the installer - it will fail.
So as you can see, these are quire serious aspects to take into account.
How I do it in my software and I suggest you try it too? I prepare one installer file (.exe) with InnoSetup (freeware!). This can be used for first installation as well as for automatic updates. Then if I create a new version and put it on the server, the running main application detects it, downloads the new installer and runs this installer (of course it asks the user if it should proceed). The installer then asks for elevated privileges, asks to close the running application (it usually is closed automatically when starting the installer) and overwrites the existing installation. All this is standard functionality built in the installer created by InnoSetup. And correctly updates the uninstall instructions... It took me several days to set up everything to my needs but it works well. The only "drawback" is that it is not completely silent, it shows some dialogs. But this is no real issue for me. Maybe it is better for the users to see what is happening on their computer...
Your question implies Windows. I'll make a suggestion from a Win32 perspective.
In our application, we have a similar issue. Periodically, our application downloads an update executable into a temp folder and then launches it. When the update EXE runs, it makes sure the main application has exited, unpacks the files into the application's installation folder, and then starts the application back up again. It's actually more complicated than that, as it really copies the new files into a different install folder, but I'll save those details unless you really need it.
The problem is that the updater can only update a few dll files at runtime that are not used by itself, because some are write-protected due to the installer's access.
This is the core of your issue. My advice is to have the Installer EXE statically linked to both the VC runtime and the other code its sharing with the application. That is, no DLL dependencies all. If you really need to share code between the installer and the application, but still want the application to use a DLL, you can do this. Have the shared code built as both a DLL (with a stub lib) and also built as a full LIB. May require some minor refactoring to your build or redundantly build the same source files. ​The Installer code links with the full LIB. The application code links with the stub LIB for the DLL like it does now.
If you are just looking for a way to launch the process, the API you want is CreateProcess.
Also, have you looked at the open source options like Omaha - which is what Google Chrome has used for silent updates?
Moving the files from the temp folder to the shared application folder must happen after closing the installer. But I don't know how to realize that.
The "Windows way" would be to use PendingFileRenameOperations as described in this blog-post and have Windows do the move during the next startup. Of course that implies one more of the annoying "Please reboot to finish the installation" messages.

Application deployment doesn't work after adding QSound

I have an application that I could deploy on other machines (Visual Studio). I added the module QtMultimedia to use the QSound class.
Wanting redeploy my app, the executable indicates me first that I need Qt5Multimedia.dll then Qt5Network.dll (which I have not added in my project).
Now my application doesn't launch, but no error message, I do not understand ...
I did not find much on the internet.
First of all - use dependency walker to list all the dependencies and make sure you have all the required dlls right besides the binary.
Next, make sure you've copied all the required plugins to the appropriate plugin folder besides the binary. In particulary take a look at plugins/audio/qtaudio_windows.dll, I think you might need to deploy it.
Also a good way to check what you app uses is to use process explorer on the machine you have no troubles on to check all the dlls it uses when the app is running.
I finally found !
First I need to go in the folder of my exe
Then use : "windeployqt.exe ." (whithout the quotes).
That add all I need to execute my exe. :)

Get the config folder of a third-party Click-Once application

Currently I am messing around with a Click-Once WPF application. That application is some third-party application that was not developed by me. I also do not have access to its sources.
It is run on a Windows server periodically and automatically (using a self made launcher written in standard C++) by executing the corresponding *.appref-ms link that was placed in the start menu path on installation of the application. This works fine.
Due to periodically arising problems with that application my launcher needs to wipe all configuration files before starting it so I get a well defined run at all times. Those files are placed in one of the application's folders. That config path for its settings reads like this (I found it by searching the AppData tree manually):
C:\Users\<UserName>\AppData\Local\Apps\2.0\Data\WM4WPKCW.P5Z\67QVXD6C.0NT\<app>_f6187a2321850a68_0003.0004_1a67f9f1633c43fc\Data\AppFiles\
Please note that this config path is pretty different from the application path (which uses differently named folders):
C:\Users\<User>\AppData\Local\Apps\2.0\5HN2CKMO.MPL\YOL20MYR.O8L\<app>_f6187a2321850a68_0003.0004_f6ab8c93b3a43b7c\
Since this config path changes on each update of the Click-Once application I need to find it by code (preferably C++) automatically. Unfortunately I could not figure out a way to do this.
How can I make my launcher find the config path of the Click-Once application based on its *.appref-ms file?
From Raghavendra Prabhu’s blog entry “Client Settings FAQ”:
” If you want to get to the path programmatically, you can do it using the Configuration Management API (you need to add a reference to System.Configuration.dll). For example, here is how you can get the local user.config file path:
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
Console.WriteLine("Local user config path: {0}", config.FilePath);
The code is C# (evidently), but shouldn't be that hard to translate to C++/CLI.
Raghavendra Prabhu further writes:
” If you need to store the settings in a different location for some reason, the recommended way is to write your own SettingsProvider. This is fairly simple to implement and you can find samples in the .NET 2.0 SDK that show how to do this. Keep in mind however that you may run into the same isolation issues mentioned above .
Disclaimer: I have not tested any of this.

How to specify a standard directory in a Qt project file

I have developed an application that I plan to deploy on Windows, Mac, and Linux. The program requires access to some files (scripts and the like) at run-time.
The installation process should install the files to a location that my application can later determine without user-intervention (or perhaps just a prompt allowing the user to change the location, if desired).
What is the best way to achieve this? I can't seem to find any way to:
1. Use a "standardized path" variable in the project file's INSTALLS statement. (e.g., my application could use QStandardPaths to initialize the location, but I can't figure out how to access this path from the INSTALLS statement)
2. Save the path to my project's QSettings (.plist, registry, whatever) for later retrieval
That leaves me with creating a custom project file and INSTALLS command for each environment, and then I still can't install to the user's directory because I don't know the user's name when I deploy the make command. It seems as if there must be a better way, but I can't seem to find any documentation for this. Am I just using the wrong keywords in my searches? Thanks in advance!
What standard directory? What type of getting that standard directory?
For instance, you can put such thing in your windows branch of .pro file:
win32 {
APPDATA_DIR = $$system(echo %APPDATA%) # should be %LOCALAPPDATA% as requested
message($$APPDATA_DIR)
}
Just unsure of what exact kind of standartized path you are talking about. QStandardPaths knows many. It makes sense to be more concrete to find the correspondence with concrete OS.
Also somewhat relative reply on mine, on how to check the correspondence with certain variable, etc: Qt .pro file - how to add conditioning on OSX version?
Maybe this class will help you
QStandardPaths documentation
But your problem is still little bit unclear for me.

File path of .exe File in windows 7

I am working in a C++ project. I need to obtain the path of a installed software. (Eg. skype.exe) Is there any way to find the path via C++ coding or via Widows command prompt
Depends what you are needing it for, and how generic you want it.
You can use GetEnvironmentVariable to get the PATH variable, and search these paths.
You can use the App Paths registry key, as Gabe says. See also...
Usually there are pretty clear application-specific ways to find the path via the registry. Either via the HKLM/Software key or Uninstall. Careful with localization and hard-coding application names...
If you are just trying to launch the app, ShellExecute doesn't need the full path, it works almost like the "run" dialog box in the start menu.
It's in the App Paths registry key. For skype.exe you would look in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\skype.exe
You can call the standard Win32 API RegQueryValue to read it.