SERVICE.C
// 
// 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 ); 
    } 
}