//+------------------------------------------------------------------
//
// File:        SETUPSVC.CXX
//
// Contents:
//
// Synoposis:
//
// Classes:     CService
//
// Functions:
//
// History:     May 19, 1993        AlokS       Created
//
//-------------------------------------------------------------------

#include <windows.h>
#include <ole2.h>
#include <windowsx.h>
#include <shlobj.h>
#include <registry.hxx>
#include <setupsvc.hxx>

#include "resource.h"

#include "messages.h"

#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
extern HINSTANCE g_hInstance;

//+-------------------------------------------------------------------------
//
//  Function:   MyFormatMessageText
//
//  Synopsis:   Given a resource IDs, load strings from given instance
//              and format the string into a buffer
//
//  History:    11-Aug-93 WilliamW   Created.
//
//--------------------------------------------------------------------------
VOID
MyFormatMessageText(
    IN HRESULT   dwMsgId,
    IN PWSTR     pszBuffer,
    IN DWORD     dwBufferSize,
    IN va_list * parglist
    )
{
    //
    // get message from system or app msg file.
    //

    DWORD dwReturn = FormatMessage(
                             FORMAT_MESSAGE_FROM_HMODULE,
                             g_hInstance,
                             dwMsgId,
                             LANG_USER_DEFAULT,
                             pszBuffer,
                             dwBufferSize,
                             parglist);

    if (0 == dwReturn)   // couldn't find message
    {
        WCHAR szText[200];
        LoadString(g_hInstance, IDS_APP_MSG_NOT_FOUND, szText, ARRAYLEN(szText));
        wsprintf(pszBuffer,szText,dwMsgId);
    }
}

VOID
MyFormatMessage(
    IN HRESULT   dwMsgId,
    IN PWSTR     pszBuffer,
    IN DWORD     dwBufferSize,
    ...
    )
{
    va_list arglist;

    va_start(arglist, dwBufferSize);
    MyFormatMessageText(dwMsgId, pszBuffer, dwBufferSize, &arglist);
    va_end(arglist);
}
//+------------------------------------------------------------------
//
// Class: CService
//
// Purpose: Helper class for dealing with Service Controller
//
// Interface: CService::CService()          = Constructor
//            CService::~CService()         = Destructor
//            CService::Init()              = Initializes the class
//            CService::_CreateService()    = Install a Win32 Service
//            CService::_OpenService()      = Open an existing service
//            CService::_QueryServiceStatus() = Query servcie status.
//            CService::_CloseService()     = Close all resources associated with
//                       the service
//            CService::_DeleteService()    = Remove a Win32 Service
//            CService::_DisableService()   = Disables a Win32 Service
//            CService::_StartService()     = Start an existing service
//            CService::_StopService()      = Stop an existing, running service
//            CService::_ConfigService()    = Combo operation. Create if
//                                         not present else reconfigure it
//
// History: May 20, 1993         AlokS       Created
//
// Notes: This is a smart wrapper class for Service APIs. But it is not
//        multi-thread safe.
//
//-------------------------------------------------------------------

//+------------------------------------------------------------------
//
// Member: CService::CService
//
// Synopsis: Create an instance
//
// Effects: Instantiates the class
//
// Arguments: -none-
//
// Returns  : None.
//
// History: May 20, 1993         AlokS       Created
//
// Notes: The class allows only one handle to service per instance of this
//        class. Plus, it is not written to close handles before opening
//        new service. However, it does guarantee to close handles
//        (SC database and one Service handle) at destruction time.
//
//-------------------------------------------------------------------

CService::CService():
       _schSCManager(NULL),
       _scHandle(NULL)
{
    ;
}
//+------------------------------------------------------------------
//
// Member: CService::Init
//
// Synopsis: Open handle to Service Controller
//
// Effects: -do-
//
// Arguments: -none-
//
// Returns  : 0 on success else error from opening SC.
//
// History: Nov 4, 1993         AlokS       Created
//
// Notes: The class allows only one handle to service per instance of this
//        class. Plus, it is not written to close handles before opening
//        new service. However, it does guarantee to close handles
//        (SC database and one Service handle) at destruction time.
//
//-------------------------------------------------------------------
DWORD   CService::Init()
{
    DWORD dwStatus = 0;
    // Open the local SC database
    _schSCManager =  OpenSCManager(NULL, // Machine Name
                                   NULL, // Database Name
                                   SC_MANAGER_CREATE_SERVICE|
                                   SC_MANAGER_LOCK
                                  );
    if (_schSCManager == NULL)
    {
        dwStatus = GetLastError();
        DSSCDebugOut(( DEB_IERROR, "Error: %lx in opening SCManager", dwStatus));
    }
    return(dwStatus);
}
//+------------------------------------------------------------------
//
// Member: CService::~CService
//
// Synopsis: Release all resources
//
// Effects: Closes SC database handle as well as any  service handle
//
// Arguments: none
//
// History: May 20, 1993         AlokS       Created
//
// Notes: Remember that we have only 1 service handle per instance.
//
//-------------------------------------------------------------------

CService::~CService()
{

    if (_schSCManager != NULL)
        CloseServiceHandle (_schSCManager);

    if (_scHandle != NULL)
        CloseServiceHandle (_scHandle);
}
//+------------------------------------------------------------------
//
// Member: CService::_CreateService
//
// Synopsis: This method is used to install a new Win32 Service or driver
//
// Effects: Creates a service.
//
// Arguments: all [in] parameters. See CreateService() API documentation
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes: The handle of newly created service is remembered and closed by
//        destructor
//
//-------------------------------------------------------------------

DWORD CService::_CreateService(const LPWSTR  lpwszServiceName,
                            const LPWSTR  lpwszDisplayName,
                                  DWORD   fdwDesiredAccess,
                                  DWORD   fdwServiceType,
                                  DWORD   fdwStartType,
                                  DWORD   fdwErrorControl,
                            const LPWSTR  lpwszBinaryPathName,
                            const LPWSTR  lpwszLoadOrderGroup,
                            const LPDWORD lpdwTagID,
                            const LPWSTR  lpwszDependencies,
                            const LPWSTR  lpwszServiceStartName,
                            const LPWSTR  lpwszPassword)
{
    if (_schSCManager==NULL)
    {
        return(ERROR_INVALID_HANDLE);
    }
    DWORD dwStatus =0;

    _scHandle  = CreateService(_schSCManager,
                                lpwszServiceName,
                                lpwszDisplayName,
                                fdwDesiredAccess,
                                fdwServiceType,
                                fdwStartType,
                                fdwErrorControl,
                                lpwszBinaryPathName,
                                lpwszLoadOrderGroup,
                                lpdwTagID,
                                lpwszDependencies,
                                lpwszServiceStartName,
                                lpwszPassword
                               );
    if (_scHandle==NULL)
    {
        dwStatus = GetLastError();
        DSSCDebugOut(( DEB_IERROR,
                   "Error: %lx in CreateService: %ws\n",
                   dwStatus,
                   lpwszServiceName));
    }

    return dwStatus;
}
//+------------------------------------------------------------------
//
// Member: CService::_OpenService
//
// Synopsis: Opens the service if caller has specified proper access
//
// Effects: Opens a service, if one exists
//
// Arguments: [in] lpwszServiceName = Name of the service
//            [in] fdwDesiredAccess = Open Access mode bits
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes: The handle of opened service is remembered and closed by
//        destructor
//
//-------------------------------------------------------------------

DWORD CService::_OpenService( const LPWSTR lpwszServiceName,
                                 DWORD fdwDesiredAccess
                        )
{

    if (_schSCManager==NULL)
    {
        return(ERROR_INVALID_HANDLE);
    }
    DWORD dwStatus =0;
    _scHandle = OpenService ( _schSCManager,
                              lpwszServiceName,
                              fdwDesiredAccess
                            );
    if (_scHandle==NULL)
    {
        dwStatus = GetLastError();
        DSSCDebugOut(( DEB_IERROR,
                       "Error: %lx in OpeningService: %ws\n",
                       dwStatus,
                       lpwszServiceName
                    ));
    }
    return dwStatus;

}

//+------------------------------------------------------------------
//
// Member: CService::_StartService
//
// Synopsis: Start the named service
//
// Effects: Opens a service, if one exists
//
// Arguments: [in] lpwszServiceName = Name of the service to start
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes: The handle of opened service is remembered and closed by
//        destructor
//
//-------------------------------------------------------------------

DWORD CService::_StartService( const LPWSTR lpwszServiceName
                          )
{

    if (_schSCManager==NULL)
    {
        return(ERROR_INVALID_HANDLE);
    }
    DWORD dwStatus =0;
    if (_scHandle)
        _CloseService();

    _scHandle = OpenService ( _schSCManager,
                              lpwszServiceName,
                              SERVICE_START|SERVICE_QUERY_STATUS
                             );
    if (_scHandle==NULL)
    {
        dwStatus = GetLastError();
        DSSCDebugOut(( DEB_IERROR,
                       "Error: %lx in Opening Service: %ws\n",
                       dwStatus,
                       lpwszServiceName
                    ));
    }
    else if (!StartService(_scHandle, NULL, NULL))
    {
        dwStatus = GetLastError();
        DSSCDebugOut(( DEB_IERROR,
                      "Error: %lx in Starting Service: %ws\n",
                      dwStatus,
                      lpwszServiceName
                   ));
    }
    return dwStatus;

}
//+------------------------------------------------------------------
//
// Member: CService::_StopService
//
// Synopsis: Stop the named service
//
// Effects: Opens a service, if one exists
//
// Arguments: [in] lpwszServiceName = Name of the service to stop
//
// Returns: 0 on success
//
// History: May 9, 1994         DaveStr       Created
//
// Notes: The handle of opened service is remembered and closed by
//        destructor
//
//-------------------------------------------------------------------

DWORD CService::_StopService( const LPWSTR lpwszServiceName
                          )
{
    SERVICE_STATUS ss;

    if (_schSCManager==NULL)
    {
        return(ERROR_INVALID_HANDLE);
    }
    DWORD dwStatus =0;
    if (_scHandle)
        _CloseService();

    _scHandle = OpenService ( _schSCManager,
                              lpwszServiceName,
                              SERVICE_STOP|SERVICE_QUERY_STATUS
                             );
    if (_scHandle==NULL)
    {
        dwStatus = GetLastError();
        DSSCDebugOut(( DEB_IERROR,
                       "Error: %lx in Opening Service: %ws\n",
                       dwStatus,
                       lpwszServiceName
                    ));
    }
    else if (!ControlService(_scHandle, SERVICE_CONTROL_STOP, &ss))
    {
        dwStatus = GetLastError();
        DSSCDebugOut(( DEB_IERROR,
                      "Error: %lx in Controlling (stopping) Service: %ws\n",
                      dwStatus,
                      lpwszServiceName
                   ));
    }
    return dwStatus;
}
//+------------------------------------------------------------------
//
// Member: CService::_DeleteService
//
// Synopsis: Remove the named service
//
// Effects: Deletes a service, if one exists
//
// Arguments: [in] lpwszServiceName = Name of the service to remove
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes:
//
//
//-------------------------------------------------------------------
DWORD CService::_DeleteService( const LPWSTR lpwszServiceName )

{
    DWORD dwStatus;
    // Open the service
    dwStatus =  _OpenService(lpwszServiceName,
                             SERVICE_CHANGE_CONFIG|
                             DELETE
                            );
    if (!dwStatus)
    {
        // We have a handle to the existing service. So, delete it.
        if (!DeleteService ( _scHandle))
        {
            dwStatus = GetLastError();
            DSSCDebugOut(( DEB_IERROR,
                          "Error: %lx in DeleteService: %ws\n",
                           dwStatus,
                          lpwszServiceName
                        ));
            _CloseService();
        }
    }
    return dwStatus;
}

//+------------------------------------------------------------------
//
// Member: CService::_DisableService
//
// Synopsis: Disable the named service
//
// Effects: Disables a service, if one exists
//
// Arguments: [in] lpwszServiceName = Name of the service to disable
//
// Returns: 0 on success
//
// History: Dec 8, 1993         AlokS       Created
//
// Notes:
//
//
//-------------------------------------------------------------------
DWORD CService::_DisableService( const LPWSTR lpwszServiceName )
{
    DWORD dwStatus;
    // Open the service
    dwStatus =  _OpenService(lpwszServiceName,
                             SERVICE_CHANGE_CONFIG
                            );
    if (!dwStatus)
    {
        // We have a handle to the existing service. So, delete it.
        if (!ChangeServiceConfig ( _scHandle,           // Handle
                                   SERVICE_NO_CHANGE,   // Type
                                   SERVICE_DISABLED,    // Start
                                   SERVICE_NO_CHANGE,   // Error
                                   NULL,                // Path
                                   NULL,                // Load order
                                   NULL,                // Tag
                                   NULL,                // Depend
                                   NULL,                // Start name
                                   NULL,                // Password
                                   NULL                 // Display Name
                                  ))
        {
            dwStatus = GetLastError();
            DSSCDebugOut(( DEB_IERROR,
                          "Error: %lx in ChangeService: %ws\n",
                           dwStatus,
                          lpwszServiceName
                        ));
            _CloseService();
        }
    }
    return dwStatus;
}
//+------------------------------------------------------------------
//
// Member: CService::_CloseService
//
// Synopsis:  Close a service for which we have an open handle
//
// Effects: Close service handle, if opened previously
//
// Arguments: -none-
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes:
//
//
//-------------------------------------------------------------------
void CService::_CloseService( )
{
    if (_scHandle != NULL)
        CloseServiceHandle ( _scHandle);
    _scHandle = NULL;
}

//+------------------------------------------------------------------
//
// Member: CService::_QueryServiceStatus
//
// Synopsis:  query current service status
//
// Effects: none
//
// Arguments: service_status - service status structure.
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes:
//
//
//-------------------------------------------------------------------
DWORD CService::_QueryServiceStatus(LPSERVICE_STATUS ss)
{
    if (_scHandle != NULL) {

        if (!QueryServiceStatus(_scHandle, ss))
            return(GetLastError());

        return(0);
    }

    return(ERROR_INVALID_HANDLE);
}

//+------------------------------------------------------------------
//
// Member: CService::ConfigService
//
// Synopsis: Create else Open/Change the named Service
//
// Effects: It first tries to create a service. If one exists already,
//          it changes the configuration to new configuration.
//
// Arguments: Lots of them. See documentation on CreateService() API.
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes: Most people should use this method only for setting up services
//
// MAJOR NOTE: It is essential that all the keys being asked to change
//             be actually present before they can be changed
//
//
//
//-------------------------------------------------------------------
WCHAR MsgBuf[0x1000];

DWORD CService::_ConfigService(   DWORD fdwServiceType,
                                  DWORD fdwStartType,
                                  DWORD fdwErrorControl,
                            const LPWSTR lpwszBinaryPathName,
                            const LPWSTR lpwszLoadOrderGroup,
                            const LPWSTR lpwszDependencies,
                            const LPWSTR lpwszServiceStartName,
                            const LPWSTR lpwszPassword,
                            const LPWSTR lpwszDisplayName,
                            const LPWSTR lpwszServiceName
                          )
{
    if (_schSCManager==NULL)
    {
        return(ERROR_INVALID_HANDLE);
    }

    DWORD dwStatus = ERROR_SERVICE_DATABASE_LOCKED;
    SC_LOCK scLock;

    //
    // Let us lock the database.  There could be a problem here
    // because the service controller also locks the database when
    // starting a service so it reads the startup parameters properly.
    // If this is the case, and the database is locked, we just try
    // up to 5 times to lock it ourselves before we fail. 
    //
    for ( ULONG tries = 0;
          (tries < 5) && (dwStatus == ERROR_SERVICE_DATABASE_LOCKED);
          tries++ )
    {
        scLock = LockServiceDatabase (_schSCManager);

        if ( scLock == NULL )
        {
            dwStatus = GetLastError();

            DSSCDebugOut((DEB_ERROR, "LockServiceDatabase(try %d) == %#0x\n",
                         tries, dwStatus));

            if ( dwStatus == ERROR_SERVICE_DATABASE_LOCKED )
            {
                Sleep ( 2 * 1000 );
            }
        }
        else
        {
            dwStatus = 0;
        }
    }

    if ( dwStatus != 0 )
    {
        return dwStatus;
    }

    // First, we try to create the service.
    dwStatus   =  _CreateService(
                                  lpwszServiceName,
                                  lpwszDisplayName,
                                  GENERIC_WRITE,         // Access
                                  fdwServiceType,
                                  fdwStartType,
                                  fdwErrorControl,
                                  lpwszBinaryPathName,
                                  lpwszLoadOrderGroup,
                                  NULL,                  // Tag ID
                                  lpwszDependencies,
                                  lpwszServiceStartName,
                                  lpwszPassword
                                 );
    // It is possible that service exists
    if ((dwStatus == ERROR_SERVICE_EXISTS) ||
        (dwStatus == ERROR_DUP_NAME))
    {
        // Open the service
        dwStatus =  _OpenService(lpwszServiceName,
                                 SERVICE_CHANGE_CONFIG|DELETE);

        if (!dwStatus) {

            if (!ChangeServiceConfig(_scHandle,
                                 fdwServiceType,
                                 fdwStartType,
                                 fdwErrorControl,
                                 lpwszBinaryPathName,
                                 lpwszLoadOrderGroup,
                                 NULL,
                                 lpwszDependencies,
                                 lpwszServiceStartName,
                                 lpwszPassword,
                                 lpwszDisplayName
                                 )) {

                //
                // Change didn't work, lets try to delete and recreate this
                // service.
                //

                dwStatus = 0;

                if (!DeleteService ( _scHandle)) {
                    // This is hopeless. Let us give up now
                    dwStatus = GetLastError();
                    DSSCDebugOut(( DEB_IERROR,
                                   "Error: %lx in DeleteService: %ws\n",
                                   dwStatus,
                                   lpwszServiceName));

                }

                _CloseService();

                if (!dwStatus) {
                    // last attempt to create
                    dwStatus   =  _CreateService(
                                                 lpwszServiceName,
                                                 lpwszDisplayName,
                                                 GENERIC_WRITE,         // Access
                                                 fdwServiceType,
                                                 fdwStartType,
                                                 fdwErrorControl,
                                                 lpwszBinaryPathName,
                                                 lpwszLoadOrderGroup,
                                                 NULL,                  // Tag ID
                                                 lpwszDependencies,
                                                 lpwszServiceStartName,
                                                 lpwszPassword
                                                );
                    DSSCDebugOut(( DEB_IERROR,
                                   "This is hopeless. Recreating failed!!\n"));

                }

            }

        } // OpenService

    } // CreateService

    //
    // Set description
    //

    if (dwStatus == ERROR_SUCCESS) {

        SERVICE_DESCRIPTION ServiceDescription;

        // Open the service if the above did not
        if (_scHandle == NULL) {
            dwStatus =  _OpenService(
                                lpwszServiceName,
                                SERVICE_CHANGE_CONFIG);
        }

        if (dwStatus == ERROR_SUCCESS) {
            ULONG i;
            MyFormatMessage(MSG_DFS_DESCRIPTION, MsgBuf, sizeof(MsgBuf));
            for (i = 0; MsgBuf[i] != UNICODE_NULL && i < (sizeof(MsgBuf)/sizeof(WCHAR)); i++) {
                if (MsgBuf[i] == L'\r')
                    MsgBuf[i] = UNICODE_NULL;
                else if (MsgBuf[i] == L'\n')
                    MsgBuf[i] = UNICODE_NULL;
            }
            ServiceDescription.lpDescription = MsgBuf;

            dwStatus = ChangeServiceConfig2(
                           _scHandle,
                           SERVICE_CONFIG_DESCRIPTION, // InfoLevel
                           &ServiceDescription);

            dwStatus = (dwStatus != 0) ? ERROR_SUCCESS : GetLastError();

        }

   }

    _CloseService();
    UnlockServiceDatabase ( scLock);
    return dwStatus;
}

//+------------------------------------------------------------------
//
// Function: _StartService
//
// Synopsis:
//
// Effects: Starts the Service and any other
//          service dependent on it. It also ensures that the
//          service has started befor returning.
//
// Arguments: [pwsz] -- name of the service to be started
//
// Returns: 0 on success
//
// History: Nov 12, 1993         AlokS       Created
//
// Notes:   This code was borrowed from the original StartDfs code
//          written by Aloks and parameterized  to allow other
//          services to be started. An interesting question is
//          whether this should be made a method of CDSSvc class.
//          (TBD by AlokS)
//
//-------------------------------------------------------------------
DWORD _SynchStartService(WCHAR *pwszServiceName)
{
    DWORD dwRc;
    // Open Service Controller
    CService cSvc;
    if ((dwRc = cSvc.Init())== ERROR_SUCCESS)
    {
        // Start the Service
        dwRc = cSvc._StartService(pwszServiceName);
        if (dwRc == ERROR_SERVICE_ALREADY_RUNNING)
        {
            // We are done!
            return ( ERROR_SUCCESS );
        }
    }
    if (dwRc)
    {
        DSSCDebugOut((DEB_IERROR, "Error starting:  %ws\n",pwszServiceName));
        return(dwRc);
    }

    // Wait for the service to start running
    SERVICE_STATUS scStatus;
    DWORD          MaxTries = 0;
    do
    {
        if (!QueryServiceStatus(cSvc.QueryService(),
                                &scStatus
                               ))
        {
            dwRc = GetLastError();
            DSSCDebugOut((DEB_IERROR, "Error Querying service\n"));
            break;
        }
        else if (scStatus.dwCurrentState != SERVICE_RUNNING)
        {
            Sleep(SERVICE_WAIT_TIME);
            MaxTries++;
        }

    } while ( scStatus.dwCurrentState != SERVICE_RUNNING && MaxTries < MAX_SERVICE_WAIT_RETRIES);
    if (MaxTries == MAX_SERVICE_WAIT_RETRIES)
    {
        dwRc = ERROR_SERVICE_REQUEST_TIMEOUT;
    }
    return(dwRc);
}

//+------------------------------------------------------------------
//
// Function: ConfigDfs
//
// Synopsis:
//
// Effects: Configures DFS File System Driver
//
// Arguments: -none-
//
// Returns: 0 on success
//
// History: May 20, 1993         AlokS       Created
//
// Notes:
//
//-------------------------------------------------------------------

DWORD ConfigDfs()
{
    DWORD    dwErr = ERROR_SUCCESS;

    // Open Service Controller
    CService cSvc;
    if (dwErr = cSvc.Init())
        return dwErr;

    // Create DFS (Driver)
    dwErr = cSvc._ConfigService(
                    SERVICE_FILE_SYSTEM_DRIVER, // Service Type
                    SERVICE_BOOT_START,         // Start Type
                    SERVICE_ERROR_NORMAL,       // Error Control
                                                // service file
                    L"\\SystemRoot\\system32\\drivers\\Dfs.sys",
                    L"filter",                  // Load order group
                    NULL,                       // Dependency
                    NULL,                       // Service start name
                    NULL,                       // password
                    L"DfsDriver",               // display name
                    L"DfsDriver"                // Service Name
                    );

    if (dwErr)
        return dwErr;

    //
    // Registry Changes
    //

    //
    // Fix up the NetworkProvider order level - delete the Dfs provider
    // if one has been inserted there
    //

    if (dwErr == ERROR_SUCCESS) {

        CRegKey cregNP( HKEY_LOCAL_MACHINE,
                        L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
                        KEY_READ | KEY_WRITE,
                        NULL,
                        REG_OPTION_NON_VOLATILE);

        dwErr = cregNP.QueryErrorStatus();

        if (dwErr == ERROR_SUCCESS) {

            CRegSZ cregOrder( cregNP, L"ProviderOrder" );
            dwErr = cregOrder.QueryErrorStatus();

            if (dwErr == ERROR_SUCCESS) {

                WCHAR wszProviders[128];
                WCHAR *pwszProviders = wszProviders;
                PWCHAR pwszDfs;
                ULONG cbProviders = sizeof(wszProviders);

                dwErr = cregOrder.GetString( pwszProviders, &cbProviders );

                if (dwErr == ERROR_MORE_DATA) {

                    pwszProviders = new WCHAR[ cbProviders / sizeof(WCHAR) ];
                    if (pwszProviders == NULL) {
                        dwErr = ERROR_OUTOFMEMORY;
                    } else {
                        dwErr = cregOrder.GetString( pwszProviders, &cbProviders );
                    }
                }

                if (dwErr == ERROR_SUCCESS) {

                    //
                    // Delete Dfs only if its not already there.
                    //

                    pwszDfs = wcsstr(pwszProviders, L"Dfs,");

                    if (pwszDfs != NULL) {
                        *pwszDfs = UNICODE_NULL;
                        wcscat( pwszProviders, pwszDfs + 4);
                        dwErr = cregOrder.SetString( pwszProviders );
                    }
                }

                if (pwszProviders != wszProviders && pwszProviders != NULL) {
                    delete [] pwszProviders;
                }
            }
        }
    }

    return dwErr;
}

//+------------------------------------------------------------------
//
// Function: StartDfs
//
// Synopsis:
//
// Effects: Starts out the DFS Service.
//
// Arguments: -none-
//
// Returns: 0 on success
//
// History: Nov 12, 1993         AlokS       Created
//
// Notes:
//
//-------------------------------------------------------------------
DWORD StartDfs (
    GUID *pguidDomain,
    PWSTR pwszDomain
    )
{
    DWORD dwRc;

    //
    // We load the dfs driver and then call FindDomainController. This
    // call to FindDomainController is expected to seed the Dfs driver
    // with domain info.
    //

    dwRc = _SynchStartService(L"Dfs");

    return(dwRc);
}

//+------------------------------------------------------------------
//
// Function: RemoveDfs
//
// Synopsis:
//
// Effects: Remove DFS driver
//
//-------------------------------------------------------------------

DWORD
RemoveDfs(void)
{
    //DbgCommonApiTrace(RemoveDfs);

    DWORD dwErr = ERROR_SUCCESS;

    // Open Service Controller
    CService cSvc;
    if (!(dwErr = cSvc.Init()))
    {
        // Disable DFS driver
        dwErr = cSvc._DisableService(L"Dfs");
    }
    if (dwErr)
    {
        return(dwErr);
    }
    /*
     * Registry Changes
     */
    // Now, we remove entries under DFS entry in registry

    //
    // Remove Dfs from the NetworkProvider list
    //
    if (dwErr == ERROR_SUCCESS) {

        CRegKey cregNP( HKEY_LOCAL_MACHINE,
                        L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
                        KEY_READ | KEY_WRITE,
                        NULL,
                        REG_OPTION_NON_VOLATILE);

        dwErr = cregNP.QueryErrorStatus();

        if (dwErr == ERROR_SUCCESS) {

            CRegSZ cregOrder( cregNP, L"ProviderOrder" );
            dwErr = cregOrder.QueryErrorStatus();

            if (dwErr == ERROR_SUCCESS) {

                WCHAR wszProviders[128];
                WCHAR *pwszProviders = wszProviders;
                WCHAR *pwszDfs, *pwszAfterDfs;
                ULONG cbProviders = sizeof(wszProviders);

                dwErr = cregOrder.GetString( pwszProviders, &cbProviders );

                if (dwErr == ERROR_MORE_DATA) {

                    pwszProviders = new WCHAR[ cbProviders / sizeof(WCHAR) ];
                    if (pwszProviders == NULL) {
                        dwErr = ERROR_OUTOFMEMORY;
                    } else {
                        dwErr = cregOrder.GetString( pwszProviders, &cbProviders );
                    }
                }

                if (dwErr == ERROR_SUCCESS) {

                    //
                    // Delete Dfs only if its there.
                    //

                    pwszDfs = wcsstr(pwszProviders, L"Dfs,");
                    if (pwszDfs != NULL) {

                        pwszAfterDfs = pwszDfs + wcslen(L"Dfs,");

                        memmove(
                            (PVOID) pwszDfs,
                            (PVOID) pwszAfterDfs,
                            (wcslen( pwszAfterDfs ) + 1) * sizeof(WCHAR));

                        dwErr = cregOrder.SetString( pwszProviders );
                    }
                }

                if (pwszProviders != wszProviders && pwszProviders != NULL) {
                    delete [] pwszProviders;
                }

            }

        }

    }

    return dwErr ;
}

//+------------------------------------------------------------------
//
// Function: ConfigDfsService
//
// Synopsis:
//
// Effects: Configures Dfs Service
//
//-------------------------------------------------------------------

DWORD
ConfigDfsService()
{
    DWORD dwErr = 0;
    ULONG i;

    // Open Service Controller
    CService cSvc;
    if (dwErr = cSvc.Init())
        return dwErr;

    //
    // Get localizable name of service
    //
    MyFormatMessage(MSG_DFS_COMPONENT_NAME, MsgBuf, sizeof(MsgBuf));
    for (i = 0; MsgBuf[i] != UNICODE_NULL && i < (sizeof(MsgBuf)/sizeof(WCHAR)); i++) {
        if (MsgBuf[i] == L'\r')
            MsgBuf[i] = UNICODE_NULL;
        else if (MsgBuf[i] == L'\n')
            MsgBuf[i] = UNICODE_NULL;
    }

    // Create entry for Dfs Manager
    dwErr = cSvc._ConfigService(

               SERVICE_WIN32_OWN_PROCESS,  // Service Type
               SERVICE_AUTO_START,         // Start Type
               SERVICE_ERROR_NORMAL,       // Error Control
               L"%SystemRoot%\\system32\\Dfssvc.exe",  // service binary
               L"Dfs",                     // Load order group
               L"LanmanWorkstation\0LanmanServer\0DfsDriver\0Mup\0",   // Dependency
               NULL,                       // Logon Name
               NULL,                       // Logon Password
               MsgBuf,                     // display name
               L"Dfs"                      // Service Name
               );

    if (dwErr == ERROR_SUCCESS) {
        CRegKey cregDfs( HKEY_LOCAL_MACHINE,
                          &dwErr,
                          L"System\\CurrentControlSet\\Services\\Dfs"
                       );

        if (dwErr == ERROR_SUCCESS)  {

            CRegDWORD DfsVer ((const CRegKey &)cregDfs, L"DfsVersion",
                               DFS_VERSION_NUMBER);

            dwErr = DfsVer.QueryErrorStatus();

        }
    }
    return dwErr ;
}


//+------------------------------------------------------------------
//
// Function: RemoveDfsService
//
// Synopsis:
//
// Effects: Remove Dfs Service
//
// Arguments: -none-
//
// Returns: 0 on success
//
//
// History: May 20, 1993         AlokS       Created
//
// Notes:
//
//
//-------------------------------------------------------------------


DWORD RemoveDfsService( )
{
    DWORD dwErr = 0;

        // Open Service Controller
    CService cSvc;
    if (!(dwErr = cSvc.Init()))
    {
        // Delete  DFSManager Service
        dwErr = cSvc._DeleteService(L"DfsService");
    }

    return dwErr ;
}