When investigating application compatibility issues on Windows Vista, a significant percentage of the failures that I debug are not failures with the platform itself, but rather applications that would have failed as a standard user on Windows XP or earlier, and begin to fail on Windows Vista because the default is to have everyone running with at least standard-user-like privileges most of the time. So, LUA Bugs that existed before are really showing themselves on Vista because of UAC (and UAC is fixing a lot of them – it’s a feature that fixes stuff, not that breaks it).
One interesting LUA Bug that catches some people off guard: apps that attempt to be single instance. An approach I have seen many times is to use the System.Diagnostic.Process class in managed code, call the GetProcesses(…) method, and then look for your name. (Doing things based on names is kind of fragile, but for the most part in the real world, while not foolproof, it will do the trick.) However, if your managed code is built on the 1.1 framework, you’re going to run into an issue here.
Rather than going into the details myself, I’ll let the BCL team address the problem from the System.Diagnostics.Process FAQ:
Why does the Process class have a dependency on the performance counter?
The Process class exposes performance information about processes. In order to get performance information about remote processes, we need to query performance information on a remote machine. We used the same code to get performance information about processes on a local machine in Everett. That’s why the Process class has a dependency on the performance counter. However, this approach has several problems:
Performance information is not available to a non-admin account, which is not in the Performance Counter Users Group on Windows Server 2003. So the Process class could not get process performance information in this case.
Getting performance data from all the processes on the machine is pretty expensive. The operating system (OS) might load lots of DLLs and it might take seconds to complete. The floppy drive light will be on when the OS tries to find the index for some performance counter.
If the performance counter data was corrupted for any reason, the Process class could throw an exception while trying to convert some raw performance information into DateTime.
The Process class could not be used to get process information on machines without the process performance counter. Performance counters can be disabled in Windows. See the following link for details: http://www.microsoft.com/windows2000/techinfo/reskit/en-us/default.asp?url=/windows2000/techinfo/reskit/en-us/regentry/94214.asp
The good news is that we have changed the implementation of the Process class in Visual Studio 2005 (our next release, code-named Whidbey). The Process class doesn’t have a dependency on performance counter information any more (this is only true for local processes).
Well, the good news is that 1.1 code that is recompiled for 2.0 will start working, but what if you can’t just recompile the code? What can you do to achieve the same thing while only changing the implementation of the single instance detection? Well, I was going to put up some sample code, but it turns out that Steve Toub already has, so I’ll just point you to his.
Now, the next question is, do you really need the application to be single instance? Does your user really want that? Obviously, if the application is already single-instance, there are probably a number of dependencies (intentional or not) on this design, but is the decision the best one? For example, it makes me crazy that I can’t have two instances of Outlook. I have two Exchange servers (work and personal), and I have to close out of one completely before I can open it back up and connect to the other. I’d love to be able to connect to both with two instances of Outlook, but I can’t. Single instance breaks a scenario that’s personally important to me. Some people are confused that they cannot right click and launch Explorer elevated because it’s important to them – single instance breaks a scenario that’s personally important to them. What scenarios are you breaking, and what are you gaining in this trade-off when you do this detection?