Saturday, March 12, 2005

Application Preloading at System Startup

Sometimes I wonder if we (as software developers) should have some form of a code of ethics, where violations can get you barred from writing software in the future. Mainly, this would apply to the spyware/malware developers (or perhaps the ethical violation is more directable to those who bundle the spyware).

If this ethical code existed, I would add a violation for any application that did not inform and offer a choice to the user at install time that some startup or background task will always be running. Some typical offenders are QuickTime, Real, Adobe, Microsoft Office, Microsoft Messenger, printer driver "status monitors", and more. These startup applications increase boot time and memory/pagefile requirements. Most of the time, I don't use these applications each time I boot the PC.

If the goal is to make your application start up faster (or appear to start up faster) there are ways of accomplishing this. Rebasing your DLL's, background/on demand loading of plugins, delay loading dependent DLL's, etc. are a few common tricks that can be used. The utility "Adobe Reader SpeedUp" accomplishes a magnificent improvement in load times, and this doesn't involve rewriting any of Adobe's code. If you wrote one of these startup applications anyway, at least offer the user the option at install time if they wish to use it.

Checking or Changing System Settings

Raymond Chen reminded me of a story I wanted to share. In non-MSI setups (and I am only using setups as an example of a larger problem in application programming), installing a service was a bit strange and usually flaky. Some installation engines would simply write the service registry keys directly into the "CurrentControlSet" section of the registry and require a reboot for the service to work. The reason was the Service Control Manager only looks at that portion of the registry when the machine is starting. Some engines decided to write values to the HKLM\System\ControlSet001 key - an even worse idea. Recall that "CurrentControlSet" does not really exist, it is mapped to the "real" ControlSet001 or ControlSet002 based on how the machine was booted. This is sort of like the HKEY_CLASSES_ROOT virtual key I blogged about before. If you need to query information about services, install them, etc. use the API's intended for this purpose - not the registry keys. Not only is this good advice for services, but in general. If you are using a registry key to check or change a setting, check for an API to set/check for the setting first. This generally isolates you from potential incompatibilities across future OS versions.

Raymond's post relates to User Interface settings, and describes an application that crashed under Windows 2000 because of the reliance on registry keys and not API's. Rephrasing my earlier point - if there is an API that reads or writes registry key data, it should be considered "Private".

One commenter to Raymond's post responded "sometimes its extremely hard to find the right api, with so many apis hanging around" - and he is 100% correct. This is where having experienced people around your development shop helps. If you don't have the former, this is a case where reading portions of the MSDN library (and blogs like Raymond's and Larry's) helps. If you are short a photographic memory, you won't retain everything - but you may remember reading something in the past and a few keywords that you can Google for later. Microsoft can help programmers avoid this trap somewhat by adding the keys that are read from or changed by API's in the MSDN documentation with a disclaimer - "The following key stores data related to this API but should not be relied upon as an implementation detail in future OS releases."

Sometimes it is hard to follow these "rules." Take for instance the Distributed Transaction Coordinator, or DTC for short. If you wanted to get or change any particular setting related to DTC you can't do it the same way across OS versions. In Windows 2003, there is the IDtcNetworkAccessConfig interface you can use. To change the same settings on Windows XP, the registry appears the only option. Furthermore, the upcoming Windows 2003 SP1 DTC changes (which mirror the XP SP2 changes) has not updated the API to reflect the change (at least in the SP1 RC2 version of the SDK documentation). Specifically, there is no updated method of allowing or disallowing specific transaction permissions such as inbound or outbound, so the API is useless - back to registry keys! Checking the DTC authentication level never had an API - just some registry keys documented in a KB article. I hope they fix this oversight for the final SP1 release - but in the meantime, what is a developer expected to do?