//
// This program installs the PROCSRV.exe into the Service Control Manager. It also
// adds a service entry to the SQL Service Manager.
// The service name "ProcSrv" will be added to the registry under the tree
// "\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SQLServer\"
//
// Copyright 1994, Microsoft.
//
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PROCSRV "ProcSrv"
#define PROCSRV_KEY_PATH "SOFTWARE\\Microsoft\\MSSQLServer\\ProcSrv\\"
#define SQL_SM_KEY "SOFTWARE\\Microsoft\\MSSQLServer\\SQL Service Manager\\"
#define NAMED_PIPE_DLL "SSNMPN60"
#define NAMED_PIPE_ADDRESS "\\\\.\\pipe\\sql\\query"
#define TCP_IP_DLL "SSMSSO60"
#define TCP_ADDRESS "1433"
void AddToRegistry();
void RemoveFromRegistry();
BOOL DuplicateEntry();
void RefreshStoplight();
void main( int argc, char ** argv )
{
if( argc != 2 )
goto Usage;
if( !stricmp("add", argv[1]) )
AddToRegistry();
else if( !stricmp("remove", argv[1]) )
RemoveFromRegistry();
else
goto Usage;
RefreshStoplight();
return;
Usage:
printf( "Usage: service {add|remove}\n"
" where \"add\" adds ProcSrv and \"remove\" removes it\n" );
}
// **************************************************************************
//
// FUNCTION: AddToRegistry()
//
// PURPOSE: Add ProcSrv to Registry and Service Control Manager
//
// **************************************************************************
void AddToRegistry()
{
int i;
HKEY hKey;
HKEY hKeySM;
DWORD dwDisposition;
DWORD dwSize = 0;
DWORD dwSizeSM;
DWORD dwType;
DWORD dwPathLength;
char szPath[1024];
char szSMvalues[1024];
char szSaveListenOn[1024];
char * szSaveListenOnPos = szSaveListenOn;
SC_HANDLE hSCM; // Handle to opened Service Control Manager
SC_LOCK LockSCM; // Lock of Service Control Manager
SC_HANDLE hSrvc; // Handle to service
// Check for existance of "ProcSrv" in registry
//
if( DuplicateEntry() )
{
printf( "Duplicate entry 'ProcSrv' found in Registry, remove 'ProcSrv' from Registry\n" );
return;
}
// ======== Update SQL Service Manager info ===========
//
if( RegCreateKeyEx(HKEY_LOCAL_MACHINE,
SQL_SM_KEY,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKeySM,
&dwDisposition)
!= ERROR_SUCCESS )
goto AddExit2;
dwSizeSM = sizeof( szSMvalues );
// Get list of SQL Service Manager entries
//
if( RegQueryValueEx(hKeySM,
"Services",
NULL,
&dwType,
szSMvalues,
&dwSizeSM)
!= ERROR_SUCCESS )
{
dwSizeSM = 1;
szSMvalues[0] = '\0';
}
if( (dwSizeSM+strlen(PROCSRV)+1) < sizeof(szSMvalues) )
{
// Append new value to list of SQL Service Manager entries.
//
memcpy( (szSMvalues+dwSizeSM-1),
PROCSRV,
(strlen(PROCSRV)+1) );
dwSizeSM += strlen(PROCSRV);
szSMvalues[dwSizeSM] = '\0';
dwSizeSM++;
}
// Note that we delay write of new values to Stoplight Registry entry.
// First well will try to update the Service Control Manager.
// ==== Write entry to Service Control Manager ====
//
hSCM = OpenSCManager( NULL,
"ServicesActive",
SC_MANAGER_ALL_ACCESS );
if( hSCM == NULL )
goto AddExit4;
i = 0;
while( TRUE )
{
LockSCM = LockServiceDatabase( hSCM );
if( LockSCM != NULL )
break;
if( i++ >= 5 )
goto AddExit3; // Can't lock database
Sleep( 1000 ); // sleep for a second
}
// Get the path of this process. We'll use it to constuct the path of the
// ProcSrv.exe
//
szPath[0] = '\0';
dwPathLength = GetModuleFileName( GetModuleHandle(NULL), szPath, sizeof(szPath) );
// Stip off process name (i.e. "service.exe")
//
while( dwPathLength > 1 )
{
--dwPathLength;
if( szPath[dwPathLength] == '\\' || szPath[dwPathLength] == ':' )
{
dwPathLength++;
szPath[dwPathLength] = '\0'; // Null terminate after the back slash
break;
}
}
// Append "procsrv.exe" to path
//
strcat( szPath, PROCSRV );
strcat( szPath, ".exe" );
// Let's create the service entry
//
hSrvc = CreateService( hSCM,
PROCSRV, // Service name to start
PROCSRV, // Display name
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
szPath,
NULL,
NULL,
NULL,
NULL,
NULL );
if( hSrvc == NULL )
goto AddExit3;
CloseServiceHandle( hSrvc );
UnlockServiceDatabase( LockSCM );
CloseServiceHandle( hSCM );
// Now we'll update Registry with new ProcSrv entry
//
if( RegCreateKeyEx(HKEY_LOCAL_MACHINE,
PROCSRV_KEY_PATH,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition)
!= ERROR_SUCCESS )
goto AddExit2;
// ==== Update ListenOn ====
//
strcpy( szSaveListenOnPos, NAMED_PIPE_DLL );
strcat( szSaveListenOnPos, "," );
strcat( szSaveListenOnPos, NAMED_PIPE_ADDRESS );
dwSize += (strlen(szSaveListenOnPos) + 1);
szSaveListenOnPos = szSaveListenOn + dwSize;
strcpy( szSaveListenOnPos, TCP_IP_DLL );
strcat( szSaveListenOnPos, "," );
strcat( szSaveListenOnPos, TCP_ADDRESS );
dwSize += (strlen(szSaveListenOnPos) + 1);
szSaveListenOnPos = szSaveListenOn + dwSize;
szSaveListenOn[dwSize] = '\0';
dwSize++;
if( RegSetValueEx(hKey,
"ListenOn",
0,
REG_MULTI_SZ,
szSaveListenOn,
dwSize)
!= ERROR_SUCCESS )
goto AddExit1;
// ==== Complete the update of the SQL Service Manager info ============
// We do it here to avoid a duplicate entry if other registry updates
// fail.
//
if( RegSetValueEx(hKeySM,
"Services",
0,
REG_MULTI_SZ,
szSMvalues,
dwSizeSM)
!= ERROR_SUCCESS )
{
RegCloseKey( hKeySM );
goto AddExit1;
}
RegFlushKey( hKeySM );
RegCloseKey( hKeySM );
return;
AddExit1:
RegCloseKey( hKey );
AddExit2:
printf( "Unable to Update Registry\n" );
return;
AddExit3:
UnlockServiceDatabase( LockSCM );
CloseServiceHandle( hSCM );
AddExit4:
printf( "Unable to Update Service Control Manager\n" );
return;
}
// **************************************************************************
//
// FUNCTION: RemoveFromRegistry()
//
// PURPOSE: Remove ProcSrv From Registry and Service Control Manager
//
// **************************************************************************
void RemoveFromRegistry()
{
int i;
HKEY hKey;
DWORD dwSizeSM;
DWORD dwType;
char szSMvalues[1024];
char * szSMvaluesPos;
SC_HANDLE hSCM; // Handle to opened Service Control Manager
SC_LOCK LockSCM; // Lock of Service Control Manager
SC_HANDLE hSrvc; // Handle to service
// Check for non-existance of "ProcSrv" in registry
//
if( !DuplicateEntry() )
{
printf( "'ProcSrv' not found in Registry\n" );
return;
}
// =============== Remove 'ProcSrv' key from Registry =============
//
RegDeleteKey( HKEY_LOCAL_MACHINE, PROCSRV_KEY_PATH );
// =============== Update SQL Service Manager info ================
//
if( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SQL_SM_KEY,
0,
KEY_ALL_ACCESS,
&hKey)
!= ERROR_SUCCESS )
goto RemoveExit2;
dwSizeSM = sizeof( szSMvalues );
// Get SQL Service Manager entries
//
if( RegQueryValueEx(hKey,
"Services",
NULL,
&dwType,
szSMvalues,
&dwSizeSM)
!= ERROR_SUCCESS )
goto RemoveExit1; // No SQL Service Manager entries.
szSMvaluesPos = szSMvalues;
while( szSMvaluesPos < (szSMvalues + dwSizeSM) )
{
if( !stricmp(szSMvaluesPos, PROCSRV) )
{
// Remove 'ProcSrv' from SQL Service Manager entries.
//
memcpy( szSMvaluesPos,
szSMvaluesPos + sizeof(PROCSRV),
((szSMvalues + dwSizeSM) - (szSMvaluesPos + sizeof(PROCSRV))) );
dwSizeSM -= sizeof( PROCSRV );
break;
}
// 'ProcSrv' entry not found, position to next entry.
//
szSMvaluesPos += (strlen( szSMvaluesPos ) + 1);
}
// Write back out new list of SQL Service Manager entries.
//
if( RegSetValueEx(hKey,
"Services",
0,
REG_MULTI_SZ,
szSMvalues,
dwSizeSM)
!= ERROR_SUCCESS )
{
RegCloseKey( hKey );
goto RemoveExit1;
}
RegFlushKey( hKey );
RegCloseKey( hKey );
// ==== Remove entry from Service Control Manager ====
//
hSCM = OpenSCManager( NULL,
"ServicesActive",
SC_MANAGER_ALL_ACCESS );
if( hSCM == NULL )
goto RemoveExit4;
i = 0;
while( TRUE )
{
LockSCM = LockServiceDatabase( hSCM );
if( LockSCM != NULL )
break;
if( i++ >= 5 )
goto RemoveExit3; // Can't lock database
Sleep( 1000 ); // sleep for a second
}
// Let's remove the service entry
//
hSrvc = OpenService( hSCM,
PROCSRV, // Service name
SERVICE_ALL_ACCESS );
if( hSrvc == NULL )
goto RemoveExit3;
DeleteService( hSrvc );
CloseServiceHandle( hSrvc );
UnlockServiceDatabase( LockSCM );
CloseServiceHandle( hSCM );
return;
RemoveExit1:
RegCloseKey( hKey );
RemoveExit2:
printf( "Unable to Update Registry\n" );
return;
RemoveExit3:
UnlockServiceDatabase( LockSCM );
CloseServiceHandle( hSCM );
RemoveExit4:
printf( "Unable to Update Service Control Manager\n" );
return;
}
// **************************************************************************
//
// FUNCTION: DuplicateEntry
//
// PURPOSE: Determines if a duplicate "ProcSrv" exist in
// the registry.
//
// RETURNS:
// TRUE if name exist, else
// FALSE if name not found.
//
//
// **************************************************************************
BOOL DuplicateEntry()
{
HKEY hKey;
if( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
PROCSRV_KEY_PATH,
0,
KEY_ENUMERATE_SUB_KEYS,
&hKey)
!= ERROR_SUCCESS )
return FALSE;
RegCloseKey( hKey );
return TRUE;
}
// **************************************************************************
//
// FUNCTION: RefreshStoplight()
//
// PURPOSE: This routine causes the SQL Service Manager to refresh its
// list.
//
// **************************************************************************
void RefreshStoplight()
{
HANDLE hEvent;
hEvent = OpenEvent( EVENT_MODIFY_STATE,
TRUE,
"MICROSOFTSQLServiceControlManagerRefresh" );
if( hEvent )
{
SetEvent( hEvent );
CloseHandle( hEvent );
}
}