How to detect launching from a "Startup"-folder shortcut? - c++

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

Related

Run own code elevated at will from non-elevated plugin DLL

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.

Windows AutoStart sometimes (randomly?) not working

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()));

How can I determine whether the current process has a UI open?

I am writing some library code which will rerun the current process as an administrator/root. The problem is (for linux at least) that if the calling code is a command line application the best way would be to call sudo whereas if it is a gui application, gksudo is appropriate. For completeness sake though, solutions (or pointers to solutions) for other os's are also welcome.
Also, this is useful so that for GUI apps, I can turn off printf statements.
I'd run gksu(do) if the environment variable DISPLAY is set. It doesn't really matter if the application has a GUI or not, if there's an X-server running, and we can use it, why shouldn't we?
Doesn't allow you to determine if you should disable stdout output. However, stderr output is generally captured in .xsession-errors, even if no terminal is connected, so you might not want to disable that output afterall.

Using the console in a GUI app in windows, only if its run from a console

My application is a GUI app that has helpful (though optional) information through the terminal (via cout).
In Windows I either have a console appear (by compiling as a console app, or allocating it dynamically) or I don't.
My intention is to make use of the console IF it is being run from the console, but ignore the console completely if it was not. (Essentially what happens in Linux and OS X).
I do not wish to redirect to a file (and in the case of using cin, this is not a viable solution anyway).
Is there a way to attach a GUI app in Windows to the console it is run from, if and only if it is run from a console?
and in the case of using cin, this is not a viable solution anyway
This is the killer detail in your question. It is simple on paper, just first call AttachConsole(ATTACH_PARENT_PROCESS) to try to attach to an existing console. That will fail when your program got started from a GUI program like Explorer or a desktop shortcut. So if it returns FALSE then call AllocConsole() to create your own console.
Using cin is a problem however. The command processor pays attention to your EXE and checks if it is console mode app or a GUI app. It will detect a GUI app in your case and then doesn't wait for the process to complete. It displays the prompt again and waits for input. You will then also wait for input but you'll lose, the command processor got there first. Your output is also intermingled with the command prompt, the easy problem to solve.
There's a simple workaround for that, your user should start your program with start /wait yourapp to tell the command processor to wait for the process to complete. Problem is: nobody ever uses that. And the user will not realize what happens when they type input, intending it to go into your program but it is actually interpreted by the command processor. Producing a mystifying error message or formatting the hard drive.
Only two good ways to solve this unsolvable problem. Either build your program as a console mode app and call FreeConsole() when you find out you want to display a GUI. Or always call AllocConsole(). These are not great alternatives. The first approach is the one used by the Java JVM on Windows. One of the oldest bugs filed against the JVM and driving Java programmers completely batty from the flashing console window.
The third alternative is the only decent one, and the one you don't want, create another EXE that will always use the console. Like Java does, javaw.exe vs java.exe.
A trick is possible, you can rename that file from "yourapp2.exe" to "yourapp.com". It will be picked first when the user types "yourapp" at the command line prompt, a desktop shortcut can still point to "yourapp.exe". Visual Studio uses this trick, devenv.com vs devenv.exe.
You can check CONSOLE_SCREEN_BUFFER_INFO (via GetConsoleScreenBufferInfo) on startup to determine if you've been run from within an existing console. If the buffer's position is 0,0, you were run from outside of the console. For details, see this Microsoft Knowledgebase Article which describes the process.
In order for this to work, you need to compile your application as a console application (using /SUBSYSTEM:CONSOLE), and then detach yourself from the console if the application started a new console (buffer at 0,0). This will cause the program to properly "attach" to the calling console when launched from a command line.
As others have pointed out you have to create a console app and a window app. So, you'd end up with console.exe and app.exe. To make it less obvious at the command-line, you can take advantage of the PATHEXT trick like devenv does. cmd.exe treats a file as a command if its extension is in the PATHEXT environment variable. COM is there by default so you could rename console.exe as app.com, allowing the command app to start the console app attached to the current console.
Note: Of course, a console app can show a GUI if desired.
The difference in the build between app.com and app.exe depends on your build system but it could just be the one attribute that sets the output type. With msbuild (for .vcxproj files), it's just a matter of another build configuration.
you can create an application in console that get a line using argc and prints it;
////
int main(int argc, char *argv[])
{
//here print argv....using cout or printf
}
save the file as console.exe in the folder of your app.
now in your app if you want to see any line in console you can call the command
system("console.exe this is the line i want to print and see in console");

How can I disable the Program Compatibility Assistant for my program in C++/Win32?

When my application exits, the Windows "Program Compatibility Assistant" appears. I want to not have that window appear when my application terminates.
This is the solution by my problem http://msdn.microsoft.com/en-us/library/dd371711(v=vs.85).aspx
I added custom manifest.
If you're seeing this dialog, one of two things can be happening:
Your program was detected as an installer, and Windows is offering to elevate the installer for you. There's little you can do about this, because this elevation check is heuristically determined by the filename. If your program contains "setup", "instal" (yes, a single l), or a few others in it's filename, the dialog will appear, and there's nothing you can do about it.
EDIT: Apparently there might be a way around this... see comments.
Alternately, you could be calling some API that is deprecated for the current version of Windows, or calling some API incorrectly, triggering compatibility heuristics. If this is the case, you just have to find the place in your program which is triggering the heuristic. You can use the Application Compatibility Toolkit (ACT) to determine what's triggering the dialog, IIRC.
There's no way to just "disable" this dialog -- you have to fix what's triggering it in the first place to make it go away.