While searching Google, I found one post from Anders Evensen, who had contacted Microsoft directly about the issue. According to him, "The problem is that Microsoft requires StartServiceCtrlDispatcher to be called before CoRegisterClassObject. However, this requirement has not been implemented in earlier versions of Windows than 2003. Windows 2003 checks that the service has been started before it allows CoRegisterClassObject to be called."
Delphi does this backwards, since StartServiceCtrlDispatcher is called in TService.Execute, and CoRegisterClassObject is called during the call to Application.Initialize. I ended up with the following solution, and things now work wonderfully on all Windows versions.
function IsRunningInInstallMode : Boolean; function FindSwitch(const Switch: string): Boolean; begin Result := FindCmdLineSwitch(Switch, ['-', '/'], True); end; begin Result := FindSwitch('REGSERVER') or FindSwitch('UNREGSERVER') or FindSwitch('INSTALL') or FindSwitch('UNINSTALL'); end; procedure TService1.ServiceExecute(Sender: TService); begin { Windows 2003 Server support. The problem is that you should always call StartServiceCtrlDispatcher (done in VCL) before calling CoRegisterClassObject (done from Application.Initialize). Win2003 now enforces this explicitly, but earlier versions did nothing if this was done improperly. } if not IsRunningInInstallMode then SvcMgr.Application.Initialize; while not Terminated do begin ServiceThread.ProcessRequests(false); Sleep(500); end; end;
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.