Some people seem to think that calling ShellExecute or ShellExecuteEx and passing the path to an executable will have the effect of telling the shell to launch an application for you. However, that’s not quite what happens. These functions simply allow your application to take an action (like launching a process) in the manner the shell typically would (for instance, recreating the behavior of using the Run box).
What’s the difference? Well, child processes inherit several things from their parents. They inherit processor affinity, for example. Most important these days, it seems, is the fact that processes inherit Integrity Level from the process that started them. That is, except in the case of elevation from medium to high IL (the operation that causes the UAC dialog to appear).
So let’s say you write an installer, and you want to run the application installed at the end of the installation process. Or heck, maybe you just want to call the application once with a special “/setup” parameter that tells it to do something you couldn’t do from your chosen setup utility.
Where do problems begin? Well, installers typically run with admin rights. When your installer launches your application as a convenience to the user, it’s now running with admin rights. The primary concern here isn’t even the security implications of running at high IL. After all, the next time your program starts it will run at its normal privilege level.
The problem is that your program is now running in a manner you may not have accounted for when writing it. For example, users won’t be able to drag-and-drop anything to your application from normal processes. If your program interacts with other non-admin processes, you may face other problems. My own Start++ application faced this problem, as it needs to inject a small amount of code into Explorer.exe and then communicate with that code to coordinate its magic. It can’t do this when running as an admin.
The recent 0.8.x release of Start++ solved this issue, and Start++ now runs immediately after install, in the proper non-admin context. This is accomplished by having Explorer launch the application on the installer’s behalf.
Others have addressed this problem in the past. However, the proposed solutions always seem to take one of these forms:
I don’t like #1 because it’s cumbersome and limits how you can name your installer.
#2 also seems cumbersome to me, and is a bit hacky.
#3 is totally hacky, and not something I trust people to do without accidentally destabilizing Explorer (there’s a reason the code Start++ injects into Explorer is incredibly tiny and very carefully crafted). It can also introduce complications when dealing with multiple target platforms (x86 versus x64). For example, the CodeProject sample linked to above doesn’t even restrict its WH_CALLWNDPROCRET hook to the thread that it’s targetting. That means this hook code is immediately going to be loaded by every process on the desktop with a window. Yuck.
Fortunately, there is a better way.
In Part 2, I describe a better way to get Explorer to run code for you, without having to inject anything into Explorer or use cumbersome workarounds like those described above.
[powered by WordPress.]
Hi. I'm Brandon. I'm a geek, and I work on Search technology for Windows at Microsoft. This is my blog.
The views expressed within my blog are my own - and are not in any way indicative of those of the company I work for, Microsoft, or it's employees. No warranties or other guarantees will be offered as to the quality of the opinions or anything else offered here.
Most popular searches that brought people here today:
an expression
contains an inva (2)search (1)windows vista start
search bar (1)google desktop
search crawl sh (1)windows vista 64 bit
+ downl (1)64 bit version of
silverlight (1)wds x64 (1)
April 27th, 2008 at 4:08 pm
Your claim that “…this hook code is immediately going to be loaded by every process on the desktop with a window” is incorrect. The hook code gets loaded into a process only when the conditions for the hook to execute for that process occur, not immediately. Since the CodeProject article you mentioned installs the hook for a very short time (just enough to send a message to the shell), and then removes the hook, it means that the hook code will not be loaded into every process or thread, it will only be loaded into the shell process, as it was intended to.
April 27th, 2008 at 4:25 pm
Hi Andrei -
There is no way to know what other window threads will pump messages while you have the hook installed. The fact is that the hook will almost always be loaded into other processes.
Since you know which window you’re targetting, you should always restrict the hook to the thread that owns that window. There is no reason *not* to as a call to GetWindowThreadProcessId is cheap and easy as cake. Passing NULL for the fourth parameter to SetWindowsHookEx is meant for the rare case when you actually want to hook every window’s message loop.