So i wrote myself a handy application that i always want to run.
It's written in C++ with QT.
Autostart is done trough the registry
If the user clicks the autorun checkbox, this code gets executed
QSettings RegSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
QSettings::NativeFormat);
if (ui.cb_autorun->isChecked())
{
RegSettings.setValue("FanControlV2", "\"" + QDir::currentPath().remove("/platforms").replace("/", "\\") + "\\FanControllerV2.exe\"");
}
else {
RegSettings.remove("FanControlV2");
}
This works fine, at least most of the time
But sometimes the application just won't start, and i have to run it manually
I don't really know what I am doing wrong here, since many many other applications start up just fine everytime...
Any advice?
Edit: problem occurs on win7, 8.1 and 10
The use of currentPath to determine the location of your application's executable is always an error. You should never do that. On most operating systems you have no control whatsoever as to what the working directory of your application is. It can literally be anything. Moreover, outside of OS X the users are free to, likely to, nah, encouraged to set the working folder for your application to their liking, so that the file access dialogs will point to a useful, default location.
Most likely, it succeeds when the working directory of your process happens to be the same as its installation folder when the settings are stored in the registry. But this state is just a happy coincidence, as you yourself have experimentally determined.
You should use QCoreApplication::applicationFilePath() to get the correct path. You should also use QDir::toNativeSeparators instead of a hand-rolled replacement.
Your code should look as follows:
RegSettings.setValue("FanControlV2", QDir::toNativeSeparators(
QCoreApplication::applicationFilePath()));
Related
I am making a suite of 64-bit plugin DLLs for a Windows host application using Visual Studio/C++, and from the current version onward, the setup.exe that they come in creates a single shared user-writable folder under ProgramData in which I cache all sorts of (non-user specific) data files. Older versions didn't have that folder yet.
However, the distribution of my plugin binaries is often out of my hands too. They are repackaged by a 3rd party bundle which can only do dumb file copies of the DLLs (so no real setup.exe functionality I need like creating folder + set permissions). And since my binary DLLs are all 100% self-contained, users also historically have a hand of just copying the DLLs around to other machines as they see fit, but that ofc also lacks the new folder setup phase.
I am looking into a workaround to have my DLLs create the folder at runtime if it is missing. I know I can't elevate the host process in-place whenever I want, but I thought of the following ways:
Have an extra "FixSetup" entry point in my DLL, and when the need arises, start an elevated RunDLL32.exe and let it use this entry point in my DLL.However, I see all sorts of people all over the place talking about RunDLL being as good as deprecated and advising against using it, but then again that was already since Windows XP and it's still with us. I also hear of RunDLL having it's own runtime context which can change with every Windows release (like switching to high-DPI aware when that came available), and that it thus is a 'hostile' environment to run in (read it on Raymond Chan's blog IIRC). Should I really be afraid of using it, or is my use case so simple it can barely break? (no GUI, just a wrapped CreateDirectory call)
Create a small "FixSetup.exe" which just does the folder creation, package it into my DLL's resources, and extract-to-temp + run-elevated it at runtime.While this would bloat my DLLs (depending on how small I can get the .exe), I feel like it's also a more fragile + convoluted solution than 1. above (with file extraction and all; prob. best to sign the utility exe too to keep HIPS / antivirus from acting funny etc?).
Alter my DLLs so that they're actually .exes in disguise which happen to export the host-expected DLL entry points, so that I can call them directly (elevated).I know there are some major caveats here (like conflicts between the C runtime being included in DLL or non-DLL mode, Visual Studio prob. not approving of these shenanigans, etc.), and honestly I already feel I need a shower just after talking about this one. So while theoretically maybe feasible, it is my last resort.
Does anyone have any advise on my uncertainties above? Or maybe an even better suggestion?
EDIT
I've already managed to get option 1. working, and while it works seamlessly there's one drawback I spotted: the UAC prompt (understandably) asks whether the user wants to run RunDLL32.exe, signed by Microsoft. This might confuse/scare people no end (that is: if they even read these prompts...). I'd rather have the UAC prompt asking about MyPluginSetup.exe signed by MyCompany, so now I'm more inclined to go with option 2. instead.
New to Qt. Kindly bear if this question too naive.
On Windows OS environmemt, I have Qt Dialog frame application which has "Duplicate" - push button . In the same directory, there is Qt application - (a Dialog widget with close button) A1.exe. Now, after click of Duplicate button, would like to copy the A1 exe and rename it as B1.exe (on the fly) in the same directory and execute it.
So, at the end two Qt applications (A1 exe and B2) running till manually cancel it. After brief research, there seems to be 2 optoins to do - QFile copy or QProcess. or any other method ? Appreciate any quick (detailed as well) thought!
Thanks
char name = 'A';
do {
INCREMENT NAME...
} while ( name + 1.exe ) exists...
Then do qfile copy from the original to the new file path made in the loop. From therw qprocess is what youre looking for to launch.
It is a bad idea to assume that you have write access to any location where executables are stored. On most modern operating systems, installing applications requires granting of temporary elevated privileges. On Windows specifically, you simply cannot assume write access to the install location, period. Anyway, you don't need to copy the executable. Why would you? If you think of modifying the executable: sorry, that doesn't work either. You'll have to sign your executables, no matter what platform you deploy to (linux has package signatures too!). Modifications will break things. Just don't.
I have a Native WinApi C++ Application that finds media(.wmv, .mp3 etc.) files in a specified directory & creates random playlists. The first time the application is run(& only the first time) I want to prompt the user to specify a 'home' directory that the Application will always check for media files & create a playlist from.
My Problem: I dont know of a way how I could determine when the Application is run for the 1st time?
Is there a standard way, maybe a Win32 function that I can use to detect when the Application is run for the 1st time?
Some ideas I have come up with are: (but they seem like hacks or overkill(installer idea))
The application .exe is 322kb(which is tiny & doesn't require an
installer right?) in size so I could create an installer (I was
thinking if someone is installing the application then I know its the
first run & I can prompt them then).
I could have a text file(or xml) called appData.txt & have the 1st
line where I store the home path directory. So "home_path=undefined",
on application run, I look in the text file, if the home_path ==
undefined then I prompt them to specify a home path if its not undefined then I read that directory for media files.
Any ideas of how I can determine when my Application is run for the very first time?
In the installer you could create a registry value for your program.
Then when you start your program, check the registry value.
When you run the program for the first time update that value to so you know it's been run already.
I would use the text file because you are going to have to store the user's directory somewhere anyway, might as well use it for first run detection as well. It has the added bonus that if the file is deleted, you will know that you have to prompt the user again since you no longer know what their home directory is.
You can set some registry value when your App runs for first time and check it on every run. If it is already set then App was already run. If not - set it.
Create a log file on first run. If it exists, then it's not the first time.
try
{
// open log.txt
// do second time run logic here
}
catch(file does not exist)
{
// create log.txt
// first run logic here
}
I'm writing a Win32 DLL with a function that adds a directory to the Windows PATH environment variable (to be used in an installer).
Looking at the environment variables in Regedit or the Control Panel after the DLL has run shows me that my DLL has succeeded in adding the path to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment and HKEY_CURRENT_USER\Environment.
But when I start up a new Command Prompt (after running the DLL), the directory I added does not show up in the output of echo %PATH% and I can not access the executable that lives in that directory by typing its name.
I think my program is not doing a good job of notifying the system that the PATH has changed, or maybe it is notifying them before the change has fully taken effect. I read an article by Microsoft that says to broadcast the WM_SETTINGCHANGE message after changing an environment variable, and I am doing that with this code:
DWORD result2 = 0;
LRESULT result = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &result2);
if (result == 0){ /* ... Display error message to user ... */ }
The order of my calls is: RegCreateKeyEx, RegSetValueEx, RegCloseKey, SendMessageTimeout
If I press "OK" in the Control Panel "Environment Variables" window, the changes made by my DLL to the PATH show up in newly-created command prompts, so there is something that the Control Panel is doing to propagate PATH changes; I want to figure out what it is and do the same thing.
Does anyone know what I should do?
I'm running 64-bit Windows Vista but I want this to work on all Windows XP, Vista and Windows 7 operating systems.
Update: The problem with the code I posted above is that I did not put the L prefix on the "Environment" string. Although it does not say it explicitly anywhere in the Microsoft documentation that I can find, the LPARAM needs to be a pointer to a WCHAR string (2-byte characters) as opposed to a CHAR string, which is what Visual Studio's compiler generates by default when I write a string literal. The solution to my problem was to change "Environment" to L"Environment". (I thought I already tried that before posting this question, but apparently I didn't try it correctly!) But anyone who wants a complete C++ solution for this task should look at Dan Moulding's answer.
It turns out there really isn't anything new under the sun. This has already been done before, at least once. By me. I created a DLL very much like what you describe for exactly the same purpose (for use in modifying the path from an NSIS installer). It gets used by the Visual Leak Detector installer.
The DLL is called editenv.dll. The source is available at github. I just tested the installer and it updated the system PATH environment variable, no problem. Based on what you've written, I don't see anything that stands out as being wrong. I also don't see anything obvious that's missing. But it may be worth a look at the editenv.dll source (you'd be most interested in EnvVar::set() in EnvVar.cpp, and possibly the pathAdd() and pathRemove() C APIs in editenv.cpp).
I have a program which calls the same Win32 API to yours to update the environment, and it works fine.
One thing to be careful of is how you are opening up the command prompt.
If you open up the command prompt by doing this:
Start -> Run -> cmd.exe
then the environment in the prompt shows that the new variable is set.
However, I also have a programmable function key on my keyboard which I have set to run the cmd.exe process. If I open a command prompt via that function key and then type env, it doesn't show the variable as being set.
I'm not sure why it works differently, but it must have something to do with the way the cmd.exe process is launched (although both are running under my user name, not SYSTEM).
How are you opening up the command prompt?
I need to add the "Run when Windows starts" option to my program CintaNotes, but do not want to sacrifice the "cleanness" of it: it is a 100% portable freeware and should not leave traces in the system.
I've come up with the idea to autodetect running from the Startup shortcut and automatically minimizing to the system tray. Is there a way to do it? I'm using C++ and raw Winapi.
So:
- No writing to the registry
- No command line parameters
Thanks!
UPD: The question is NOT how to minimize to the system tray! The question is how can a program differentiate between being run normally and being run from a startup-folder shortcut without using registry and command-line parameters.
Your "cleanness" appears to be an artificial construct at best. If you're telling the user to create a shortcut in the start-up folder, you're already leaving a footprint (and, to be honest, there's little difference between "myprog.exe" and "myprog.exe -m"). In that case, there are some easier approaches than automagically trying to detect where you're running from.
I would simply provide a menu option in your program ("Install") which would then install the software to a fixed-disk location (as opposed to the flash drive), including the requisite Programs entry (Start, All Programs, CintaNotes).
As part of that process (or even after install), you can let them specify "Start with Windows" and then you create the start-up folder shortcut for the user with a command line option so your program can tell if it's running that way. There's no point in allowing "Start with Windows" unless the program's available (i.e., on the fixed disk, not the flash drive).
Your user need never have to worry about creating shortcuts at all, let alone ones with parameters. And this gives your program the control over how it's run - two modes, "installed" (and start minimized) or "running without installing first" (and start normal).
Something like finding the directory of the executable won't work simply because the start-up folder item that starts your program is likely to be a shortcut to it, so you won't have that path.
I think this is a classic case of asking the wrong question. In answer to your specific question, I say: no, there is no way to tell that you've been launched from a start up folder entry without some command-line parameters. But, I've been wrong before, just ask my wife :-). Some-one else may well know a way.
Adding this an an edit since comments don't allow enough space:
You ask:
What do you think of just disabling the "Start when Windows starts" option when program detects it is being run from the flash drive? I guess there's a way to detect this.
That's a good idea since it doesn't make sense to allow automatic running until it's installed (since the flash drive may not be there). One possibility:
1/ Running from flash, you start with "myprog.exe" since you just double-clicked the executable and you run in a normal window. This presents the option to "Install to fixed disk" but not "Start with Windows". As part of the install process, you may allow them to set up the installed copy to "Start with Windows" but not the current running copy.
2/ Your installed program can be set up to run as "myprog.exe -i", since you create the item in Start/AllPrograms. This would disable "Install to fixed disk" but allow you to toggle "Start with Windows". You can choose whether you want explicit running (by the user) to start normal or minimized (see (3)).
3/ The shortcut in StartUp can be "myprog.exe -s" (again, you control this because you created it). This is identical to (2) but starts minimized (if (2) started minimized anyway, there's no distinction between (2) and (3) and no reason for different command-line options).
That way, each option can have different behavior as you see fit.
Even though you have already solver the problem I just wanted to say that it's possible to detect if the program was launched from shortcut. Once you have the shortcut path you can compare it to startup folder.
See the section "Detect if an executable was started from a Short-Cut
" at Undocumented CreateProcess
Check the registry for this key.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run and add a new String key with the path of your application as value. and use NOTIFYICONDATA structure for minimizing your application to the tray.
Why don't you use an argument to start the application minimized like:
YourProgram.exe -m