|
|
/*
* server.cxx */
#ifdef UNICODE
#define _UNICODE 1
#endif
#include "server.hxx"
#include "factory.hxx"
#include "tchar.h"
long ObjectCount = 0;
TCHAR * AtStorageFileName = TEXT("c:\\tmp\\atbits.dat");
#ifdef USERPCPERFDOMAIN
TCHAR * UserName = TEXT("rpcperf\\oleuser"); #else
TCHAR * UserName = TEXT("redmond\\oleuser"); #endif
TCHAR * Password = TEXT("TwoFor1"); TCHAR * ServiceName = TEXT("ActTestService"); TCHAR * ServiceDisplayName = TEXT("ActTestService"); BOOL fStartedAsService = FALSE; HANDLE hStopServiceEvent; #ifdef FREETHREADED
HANDLE hFreeThreadEvent; #endif
SERVICE_STATUS SStatus; SERVICE_STATUS_HANDLE hService; BOOL InstallService(TCHAR * );
HKEY ghClsidRootKey = 0; HKEY ghAppIDRootKey = 0;
DWORD RegHandleLocal; DWORD RegHandleRemote; DWORD RegHandleAtStorage; DWORD RegHandlePreConfig; DWORD RegHandleRunAsLoggedOn; DWORD RegHandleService; DWORD RegHandleServerOnly; unsigned uClassIndex = 0;
//+---------------------------------------------------------------------------
//
// Function: main
//
// Synopsis: main entry point for SCM
//
// History: 1-18-96 stevebl Created
//
//----------------------------------------------------------------------------
void _cdecl RealMain( int argc, char ** argv ) { HRESULT hr; MSG msg;
if ( (argc > 1) && ((strcmp(argv[1],"-?") == 0) || (strcmp(argv[1],"/?") == 0)) ) PrintUsageAndExit();
if ( (argc > 1) && (strcmp(argv[1],"-r") == 0) ) { DebuggerType eDebug = same_debugger; int n;
n = 2;
if ( n < argc ) { if (strcmp(argv[n],"-d") == 0) eDebug = windbg_debugger; else if (strcmp(argv[n],"-n") == 0 ) eDebug = ntsd_debugger; else if (strcmp(argv[n],"-x") == 0 ) eDebug = clear_debugger; }
if ( hr = InitializeRegistry( eDebug ) ) printf("InitializeRegistry failed with %08x\n", hr); else printf("Registry updated successfully.\n");
return; }
// Started manually. Don't go away.
if ( (argc == 1) && ! fStartedAsService ) ObjectCount = 1;
if ( ! fStartedAsService ) { if ( (argc >= 3 && strcmp(argv[2], "-Embedding") == 0) ) uClassIndex = argv[1][0] - '0'; else uClassIndex = 0; }
if ( fStartedAsService ) { uClassIndex = 8;
#ifdef NT351
hr = E_FAIL; #else
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); #endif
} else { #ifdef FREETHREADED
hFreeThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); hr = CoInitializeEx(NULL,COINIT_MULTITHREADED); #else
hr = CoInitialize(NULL); #endif
}
if ( FAILED(hr) ) { printf( "Server: CoInitialize failed(%x)\n", hr ); return; }
if (0 == uClassIndex || 2 == uClassIndex) { hr = CoRegisterClassObject( CLSID_ActLocal, (IUnknown *)new FactoryLocal(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &RegHandleLocal );
if ( FAILED(hr) ) { printf("Server: CoRegisterClassObject failed %x\n", hr); CoUninitialize(); return; } }
if (0 == uClassIndex || 3 == uClassIndex) { hr = CoRegisterClassObject( CLSID_ActRemote, (IUnknown *)new FactoryRemote(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &RegHandleRemote );
if ( FAILED(hr) ) { printf("Server: CoRegisterClassObject failed %x\n", hr); if (0 == uClassIndex) { CoRevokeClassObject( RegHandleLocal ); } CoUninitialize(); return; } }
if (0 == uClassIndex || 4 == uClassIndex) { hr = CoRegisterClassObject( CLSID_ActAtStorage, (IUnknown *)new FactoryAtStorage(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &RegHandleAtStorage );
if ( FAILED(hr) ) { printf("Server: CoRegisterClassObject failed %x\n", hr); if (0 == uClassIndex) { CoRevokeClassObject( RegHandleLocal ); CoRevokeClassObject( RegHandleRemote ); } CoUninitialize(); return; } }
if (0 == uClassIndex || 6 == uClassIndex) { hr = CoRegisterClassObject( CLSID_ActPreConfig, (IUnknown *)new FactoryAtStorage(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &RegHandlePreConfig );
if ( FAILED(hr) ) { printf("Server: CoRegisterClassObject failed %x\n", hr); if (0 == uClassIndex) { CoRevokeClassObject( RegHandleLocal ); CoRevokeClassObject( RegHandleRemote ); CoRevokeClassObject( RegHandleAtStorage ); } CoUninitialize(); return; } }
if (0 == uClassIndex || 7 == uClassIndex) { hr = CoRegisterClassObject( CLSID_ActRunAsLoggedOn, (IUnknown *)new FactoryAtStorage(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &RegHandleRunAsLoggedOn );
if ( FAILED(hr) ) { printf("Server: CoRegisterClassObject failed %x\n", hr); if (0 == uClassIndex) { CoRevokeClassObject( RegHandleLocal ); CoRevokeClassObject( RegHandleRemote ); CoRevokeClassObject( RegHandleAtStorage ); CoRevokeClassObject( RegHandlePreConfig ); } CoUninitialize(); return; } }
if (0 == uClassIndex || 9 == uClassIndex) { hr = CoRegisterClassObject( CLSID_ActServerOnly, (IUnknown *)new FactoryAtStorage(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &RegHandleServerOnly );
if ( FAILED(hr) ) { printf("Server: CoRegisterClassObject failed %x\n", hr); if (0 == uClassIndex) { CoRevokeClassObject( RegHandleLocal ); CoRevokeClassObject( RegHandleRemote ); CoRevokeClassObject( RegHandleAtStorage ); CoRevokeClassObject( RegHandlePreConfig ); CoRevokeClassObject( RegHandleRunAsLoggedOn ); } CoUninitialize(); return; } }
if (fStartedAsService) { hr = CoRegisterClassObject( CLSID_ActService, (IUnknown *)new FactoryAtStorage(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &RegHandleService );
if ( FAILED(hr) ) { CoUninitialize(); return; }
WaitForSingleObject(hStopServiceEvent, INFINITE); } else { #ifdef FREETHREADED
WaitForSingleObject(hFreeThreadEvent, INFINITE); //
// Make sure the thread who signaled the event executes for a while
// before we exit.
//
Sleep(100); #else
// Only do message loop if apartment threaded non-service.
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } #endif
}
CoUninitialize();
return; }
int gargc; char * gargv[100];
BOOL UpdateStatus(DWORD dwState) { if (SERVICE_RUNNING == SStatus.dwCurrentState && SERVICE_START_PENDING == dwState) { return(TRUE); }
SStatus.dwCurrentState = dwState; if (SERVICE_START_PENDING == dwState || SERVICE_STOP_PENDING == dwState) { SStatus.dwCheckPoint++; SStatus.dwWaitHint = 1; } else { SStatus.dwCheckPoint = 0; SStatus.dwWaitHint = 0; }
return(SetServiceStatus(hService, &SStatus)); }
DWORD StartMyMain(void * pArg) { // reconstruct the command line args and call the real main
RealMain(gargc, gargv); UpdateStatus(SERVICE_STOPPED); return(0); }
void Handler(DWORD fdwControl) { switch (fdwControl) { case SERVICE_CONTROL_STOP: UpdateStatus(SERVICE_STOP_PENDING); SetEvent(hStopServiceEvent); break; case SERVICE_CONTROL_INTERROGATE: UpdateStatus(SERVICE_RUNNING); break; default: break; } }
//+---------------------------------------------------------------------------
//
// Function: ServiceMain
//
// Synopsis: main entry point for service
//
// History: 1-18-96 stevebl Created
//
//----------------------------------------------------------------------------
void ServiceMain(DWORD argc, LPTSTR * argv) { fStartedAsService = TRUE;
// register the service handler
hService = RegisterServiceCtrlHandler(ServiceName, Handler);
if (!hService) return;
SStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SStatus.dwControlsAccepted = SERVICE_CONTROL_STOP | SERVICE_CONTROL_INTERROGATE; SStatus.dwWin32ExitCode = NO_ERROR; SStatus.dwServiceSpecificExitCode = 0; SStatus.dwCheckPoint = 0; SStatus.dwWaitHint = 0;
if (!UpdateStatus(SERVICE_START_PENDING)) return;
// create an event to signal when the service is to stop
hStopServiceEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!hStopServiceEvent) { return; }
UpdateStatus(SERVICE_RUNNING);
StartMyMain( NULL ); }
void _cdecl main( int argc, char ** argv) { if (argc > 1 && strcmp(argv[1], "8") == 0) { gargc = argc;
// save the command line arguments
gargc = (int) argc; if (gargc > 100) { gargc = 100; } for (int k = 1; k <= gargc; k++) { gargv[k-1] = (char *) malloc(strlen(argv[k-1]) + 1); strcpy(gargv[k-1], argv[k-1]); }
// Start as a service
SERVICE_TABLE_ENTRY ServiceStart[2]; ServiceStart[0].lpServiceName = ServiceName; ServiceStart[0].lpServiceProc = ServiceMain; ServiceStart[1].lpServiceName = NULL; ServiceStart[1].lpServiceProc = NULL;
if (!StartServiceCtrlDispatcher (ServiceStart)) { ExitProcess(GetLastError()); } ExitProcess(0); } else { // start as a regular app
RealMain(argc, argv); } }
long InitializeRegistry( DebuggerType eDebugServer ) { long RegStatus; ulong Disposition; HKEY hActKey; HKEY hDebugKey; HANDLE hFile; TCHAR Path[256]; TCHAR * pwszServerExe; TCHAR * pwszDebuggerName; DWORD DebugFlags;
if ( ! GetModuleFileName( 0, Path, sizeof(Path) ) ) return ERROR_BAD_PATHNAME;
hFile = CreateFile( AtStorageFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
if ( hFile == INVALID_HANDLE_VALUE ) { printf("Couldn't create file %ws\n", AtStorageFileName ); return GetLastError(); }
CloseHandle( hFile );
RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_ALL_ACCESS, &ghClsidRootKey );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = RegOpenKeyEx( HKEY_CLASSES_ROOT, TEXT("APPID"), 0, KEY_ALL_ACCESS, &ghAppIDRootKey );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
DeleteClsidKey( ClsidGoober32String ); DeleteClsidKey( ClsidActLocalString ); DeleteClsidKey( ClsidActRemoteString ); DeleteClsidKey( ClsidActAtStorageString ); DeleteClsidKey( ClsidActInprocString ); DeleteClsidKey( ClsidActPreConfigString ); DeleteClsidKey( ClsidActRunAsLoggedOnString ); DeleteClsidKey( ClsidActServiceString ); DeleteClsidKey( ClsidActServerOnlyString );
//
// Local CLSID entries.
//
_tcscat(Path, TEXT(" 2"));
RegStatus = SetClsidRegKeyAndStringValue( ClsidActLocalString, TEXT("LocalServer32"), Path, NULL, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDSecurity( ClsidActLocalString );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
//
// Remote CLSID entries.
//
Path[_tcslen(Path)-1] = TEXT('3');
RegStatus = SetClsidRegKeyAndStringValue( ClsidActRemoteString, TEXT("LocalServer32"), Path, NULL, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDSecurity( ClsidActRemoteString );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
//
// AtStorage CLSID entries.
//
Path[_tcslen(Path)-1] = TEXT('4');
RegStatus = SetClsidRegKeyAndStringValue( ClsidActAtStorageString, TEXT("LocalServer32"), Path, NULL, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDSecurity( ClsidActAtStorageString );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
//
// RunAs CLSID entries.'
//
Path[_tcslen(Path)-1] = TEXT('6');
RegStatus = SetClsidRegKeyAndStringValue( ClsidActPreConfigString, TEXT("LocalServer32"), Path, NULL, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDRegKeyAndNamedValue( ClsidActPreConfigString, TEXT("RunAs"), UserName, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDSecurity( ClsidActPreConfigString );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
if (!SetPassword(ClsidActPreConfigString, Password)) return(FALSE);
if (!AddBatchPrivilege( UserName ) ) return(FALSE);
//
// RunAs logged on user CLSID entries.
//
Path[_tcslen(Path)-1] = TEXT('7');
RegStatus = SetClsidRegKeyAndStringValue( ClsidActRunAsLoggedOnString, TEXT("LocalServer32"), Path, NULL, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDRegKeyAndNamedValue( ClsidActRunAsLoggedOnString, TEXT("RunAs"), TEXT("Interactive User"), NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDSecurity( ClsidActRunAsLoggedOnString );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
//
// Service CLSID entries.
//
RegStatus = SetAppIDRegKeyAndNamedValue( ClsidActServiceString, TEXT("LocalService"), ServiceName, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDSecurity( ClsidActServiceString );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
// Get the services key
HKEY hServices; RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services"), 0, KEY_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hServices );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
Path[_tcslen(Path)-1] = TEXT('8');
if (!InstallService(Path)) return TRUE;
//
// Server only CLSID entry.
//
Path[_tcslen(Path)-1] = TEXT('9');
RegStatus = SetClsidRegKeyAndStringValue( ClsidActServerOnlyString, TEXT("LocalServer32"), Path, NULL, NULL );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetAppIDSecurity( ClsidActServerOnlyString );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
//
// Add entries to launch server in debugger.
//
if ( eDebugServer == same_debugger ) return ERROR_SUCCESS;
Path[_tcslen(Path)-2] = 0; pwszServerExe = Path + _tcslen(Path); while ( (pwszServerExe > Path) && (pwszServerExe[-1] != TEXT('\\')) ) pwszServerExe--;
RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_ALL_ACCESS, &hDebugKey );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = RegCreateKeyEx( hDebugKey, TEXT("Image File Execution Options"), 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hDebugKey, &Disposition );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
if ( eDebugServer == clear_debugger ) { RegDeleteKey( hDebugKey, pwszServerExe ); return ERROR_SUCCESS; }
RegStatus = RegCreateKeyEx( hDebugKey, pwszServerExe, 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hDebugKey, &Disposition );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
if ( eDebugServer == ntsd_debugger ) { pwszDebuggerName = TEXT("ntsd.exe -d"); } else { pwszDebuggerName = TEXT("windbg.exe"); }
DebugFlags = 0x10f0;
RegStatus = RegSetValueEx( hDebugKey, TEXT("Debugger"), 0, REG_SZ, (const BYTE *)pwszDebuggerName, (_tcslen(pwszDebuggerName) + 1) * sizeof(TCHAR) );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = RegSetValueEx( hDebugKey, TEXT("GlobalFlag"), 0, REG_DWORD, (const BYTE *)&DebugFlags, sizeof(DWORD) );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
return ERROR_SUCCESS; }
long SetClsidRegKeyAndStringValue( TCHAR * pwszClsid, TCHAR * pwszKey, TCHAR * pwszValue, HKEY * phClsidKey, HKEY * phNewKey ) { long RegStatus; DWORD Disposition; HKEY hClsidKey;
if ( phClsidKey ) *phClsidKey = 0;
if ( phNewKey ) *phNewKey = 0;
RegStatus = RegCreateKeyEx( ghClsidRootKey, pwszClsid, 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hClsidKey, &Disposition );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
if ( phClsidKey ) *phClsidKey = hClsidKey;
return SetRegKeyAndStringValue( hClsidKey, pwszKey, pwszValue, phNewKey ); }
long SetAppIDRegKeyAndNamedValue( TCHAR * pwszAppID, TCHAR * pwszKey, TCHAR * pwszValue, HKEY * phClsidKey ) { long RegStatus; DWORD Disposition; HKEY hClsidKey;
if ( phClsidKey ) *phClsidKey = 0;
// first, make sure the clsid has appid={appid}
RegStatus = RegCreateKeyEx( ghClsidRootKey, pwszAppID, 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hClsidKey, &Disposition );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = SetNamedStringValue( hClsidKey, TEXT("AppID"), pwszAppID );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = RegCreateKeyEx( ghAppIDRootKey, pwszAppID, 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hClsidKey, &Disposition );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
if ( phClsidKey ) *phClsidKey = hClsidKey;
return SetNamedStringValue( hClsidKey, pwszKey, pwszValue ); }
long SetNamedStringValue( HKEY hKey, TCHAR * pwszKey, TCHAR * pwszValue ) { long RegStatus; DWORD Disposition;
RegStatus = RegSetValueEx( hKey, pwszKey, 0, REG_SZ, (const BYTE *)pwszValue, (_tcslen(pwszValue) + 1) * sizeof(TCHAR) );
return RegStatus; }
long SetRegKeyAndStringValue( HKEY hKey, TCHAR * pwszKey, TCHAR * pwszValue, HKEY * phNewKey ) { long RegStatus; DWORD Disposition; HKEY hNewKey;
if ( phNewKey ) *phNewKey = 0;
RegStatus = RegCreateKeyEx( hKey, pwszKey, 0, TEXT("REG_SZ"), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hNewKey, &Disposition );
if ( RegStatus != ERROR_SUCCESS ) return RegStatus;
RegStatus = RegSetValueEx( hNewKey, TEXT(""), 0, REG_SZ, (const BYTE *)pwszValue, (_tcslen(pwszValue) + 1) * sizeof(TCHAR) );
if ( phNewKey ) *phNewKey = hNewKey;
return RegStatus; }
BOOL InstallService(TCHAR * Path) { #ifndef CHICO
SC_HANDLE hManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); if (NULL == hManager) { printf("OpenSCManager returned %d\n",GetLastError()); return(FALSE); }
SC_HANDLE hService = OpenService( hManager, ServiceName, SERVICE_ALL_ACCESS);
if (NULL != hService) { if (!ChangeServiceConfig( hService, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, Path, NULL, NULL, NULL, NULL, NULL, ServiceDisplayName ) ) { printf("ChangeService returned %d\n",GetLastError()); CloseServiceHandle(hService); CloseServiceHandle(hManager); return(FALSE); } return(TRUE); }
hService = CreateService( hManager, ServiceName, ServiceDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, Path, NULL, NULL, NULL, NULL, NULL); if (NULL == hService) { printf("CreateService returned %d\n",GetLastError()); CloseServiceHandle(hManager); return(FALSE); }
CloseServiceHandle(hService); CloseServiceHandle(hManager); #endif
return(TRUE); }
void PrintUsageAndExit() { printf("Usage : actsrv [-r [-d | -n | -x]]\n"); printf("\t-r : Make necessary registry changes.\n"); printf("\t-d : Register server to start in windbg.\n"); printf("\t-n : Register server to start with ntsd -d.\n"); printf("\t-x : Register server and clear debugger.\n");
ExitProcess(0); }
void ShutDown() { // The last object has been destroyed.
if (fStartedAsService) { CoRevokeClassObject( RegHandleService ); }
switch( uClassIndex ) { case 0 : CoRevokeClassObject( RegHandleLocal ); CoRevokeClassObject( RegHandleRemote ); CoRevokeClassObject( RegHandleAtStorage ); CoRevokeClassObject( RegHandlePreConfig ); CoRevokeClassObject( RegHandleRunAsLoggedOn ); CoRevokeClassObject( RegHandleServerOnly ); break; case 2: CoRevokeClassObject( RegHandleLocal ); break; case 3: CoRevokeClassObject( RegHandleRemote ); break; case 4: CoRevokeClassObject( RegHandleAtStorage ); break; case 6: CoRevokeClassObject( RegHandlePreConfig ); break; case 7 : CoRevokeClassObject( RegHandleRunAsLoggedOn ); break; case 9 : CoRevokeClassObject( RegHandleServerOnly ); break; }
if (fStartedAsService) { SetEvent(hStopServiceEvent); } else { #ifdef FREETHREADED
SetEvent(hFreeThreadEvent); #else
PostQuitMessage(0); #endif
} }
|