2931 lines
84 KiB
C++
2931 lines
84 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997 - 2000.
|
||
|
//
|
||
|
// File: setupqry.cxx
|
||
|
//
|
||
|
// Contents: Indexing Service ocmgr installation routines
|
||
|
//
|
||
|
// Wish-list: Seek and destroy old webhits.exe files
|
||
|
// Migrate all existing catalogs + virtual server catalogs
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
// 7-7-97 mohamedn changed to work with NT setup.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.cxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <xolemem.hxx>
|
||
|
#include "catcnfg.hxx"
|
||
|
|
||
|
DECLARE_INFOLEVEL( is )
|
||
|
|
||
|
#define COPY_FILES_EVEN_IF_INSTALLED
|
||
|
|
||
|
extern "C" ULONG DbgPrint( LPSTR Format, ... );
|
||
|
|
||
|
//
|
||
|
// external exported routines.
|
||
|
//
|
||
|
extern "C"
|
||
|
{
|
||
|
BOOL WINAPI DllMain( IN HANDLE DllHandle,
|
||
|
IN DWORD Reason,
|
||
|
IN LPVOID Reserved );
|
||
|
|
||
|
DWORD IndexSrv( IN LPCWSTR ComponentId,
|
||
|
IN LPCWSTR SubcomponentId,
|
||
|
IN UINT Function,
|
||
|
IN UINT Param1,
|
||
|
IN OUT PVOID Param2 );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// DLL module instance handle
|
||
|
//
|
||
|
HINSTANCE MyModuleHandle;
|
||
|
|
||
|
//
|
||
|
// Utility routines
|
||
|
//
|
||
|
void GetPreviousISSetupVersion(void);
|
||
|
DWORD CompleteInstallation(CError &Err);
|
||
|
DWORD QueueConfigurationParams( HINF hInf,
|
||
|
HSPFILEQ Param2,
|
||
|
WCHAR const * pwszSectionName,
|
||
|
CError &Err );
|
||
|
DWORD SetDefaultCatalog(CError &Err);
|
||
|
void UpgradeIS1toIS3(CError & Err);
|
||
|
|
||
|
DWORD SetFilterRegistryInfo( BOOL fUnRegister,CError &Err );
|
||
|
DWORD SetDLLsToRegister(CError & Err);
|
||
|
void ExcludeSpecialLocations( CCatalogConfig & Cat );
|
||
|
void OcCleanup( CError & Err );
|
||
|
void SetupW3Svc(CError &Err);
|
||
|
void DeleteNTOPStartMenu();
|
||
|
|
||
|
DWORD AddPerfData( CError &Err );
|
||
|
DWORD RemovePerfData(void);
|
||
|
DWORD LoadCounterAndDelete( WCHAR const * pwcINI,
|
||
|
WCHAR const * pwcH,
|
||
|
CError &Err );
|
||
|
|
||
|
void CreateSharedDllRegSubKey(void);
|
||
|
DWORD AddRefSharedDll( WCHAR const * pwszDllName );
|
||
|
WCHAR * AppendMultiSZString(WCHAR * pwcTo, WCHAR const * pwcFrom );
|
||
|
DWORD RegisterDll(WCHAR const * pwcDLL, CError &Err );
|
||
|
|
||
|
BOOL IsSufficientMemory(void);
|
||
|
void AddCiSvc(CError &Err);
|
||
|
DWORD RenameCiSvc( SC_HANDLE hSC, CError &Err );
|
||
|
void StopService( WCHAR const * pwszServiceName );
|
||
|
void StartService( WCHAR const * pwszServiceName );
|
||
|
void MyStartService( CServiceHandle & xSC,
|
||
|
WCHAR const * pwcSVC );
|
||
|
BOOL MyStopService( CServiceHandle & xSC,
|
||
|
WCHAR const * pwcSVC,
|
||
|
BOOL & fStopped );
|
||
|
void DeleteService( WCHAR const * pwszServiceName );
|
||
|
|
||
|
|
||
|
DWORD SetRegBasedOnMachine(CError &Err);
|
||
|
DWORD SetRegBasedOnArchitecture(CError &Err);
|
||
|
void GetMachineInfo(BOOL & fLotsOfMem, DWORD & cCPU );
|
||
|
|
||
|
void DeleteShellLink( WCHAR const * pwcGroup,
|
||
|
WCHAR const * pwcName );
|
||
|
|
||
|
//
|
||
|
// hardcoded globals, obtained from is30.INF file
|
||
|
//
|
||
|
// [indexsrv]
|
||
|
INT g_MajorVersion = 3;
|
||
|
INT g_dwPrevISVersion = 0;
|
||
|
BOOL g_fNT4_To_NT5_Upgrade = FALSE;
|
||
|
BOOL g_fIS1x_To_NT5_Upgrade = FALSE;
|
||
|
BOOL g_fCiSvcWasRunning = FALSE;
|
||
|
BOOL g_fCiSvcIsRequested = FALSE;
|
||
|
WCHAR g_awcSystemDir[MAX_PATH]; // system32 directory
|
||
|
WCHAR g_awcSourcePath[MAX_PATH * 2]; // inf source location.
|
||
|
WCHAR g_awcIS1Path[MAX_PATH+1];
|
||
|
|
||
|
OCMANAGER_ROUTINES g_HelperRoutines;
|
||
|
|
||
|
//
|
||
|
// globals needed for OCM
|
||
|
//
|
||
|
SETUP_INIT_COMPONENT gSetupInitComponent;
|
||
|
BOOL g_fBatchInstall = FALSE;
|
||
|
BOOL g_fInstallCancelled = TRUE; // Similar to aborted, but caused by user cancel, not internal exception
|
||
|
BOOL g_fInstallAborted = FALSE;
|
||
|
BOOL g_fComponentInitialized = FALSE;
|
||
|
BOOL g_fUnattended = FALSE;
|
||
|
BOOL g_fUpgrade = FALSE;
|
||
|
BOOL g_fNtGuiMode = TRUE;
|
||
|
DWORD g_NtType = -1;
|
||
|
BOOL g_fLocallyOpened = FALSE;
|
||
|
|
||
|
WCHAR g_awcProfilePath[MAX_PATH];
|
||
|
|
||
|
//
|
||
|
// keep track if we're selected or not selected
|
||
|
//
|
||
|
BOOL g_fFalseAlready = FALSE;
|
||
|
unsigned g_cChangeSelection = 0;
|
||
|
|
||
|
//
|
||
|
// frequently used constants
|
||
|
//
|
||
|
const WCHAR wcsIndexsrvSystem[] = L"indexsrv_system";
|
||
|
|
||
|
//
|
||
|
// frequently used registry keys.
|
||
|
//
|
||
|
const WCHAR wcsRegAdminSubKey[] =
|
||
|
L"System\\CurrentControlSet\\Control\\ContentIndex";
|
||
|
const WCHAR wcsRegCatalogsSubKey[] =
|
||
|
L"System\\CurrentControlSet\\Control\\ContentIndex\\Catalogs";
|
||
|
const WCHAR wcsRegCatalogsWebSubKey[] =
|
||
|
L"System\\CurrentControlSet\\Control\\ContentIndex\\Catalogs\\web";
|
||
|
const WCHAR wcsRegCatalogsWebPropertiesSubKey[] =
|
||
|
L"System\\CurrentControlSet\\Control\\ContentIndex\\Catalogs\\web\\properties";
|
||
|
const WCHAR wcsAllowedPaths[] =
|
||
|
L"System\\CurrentControlSet\\Control\\SecurePipeServers\\winreg\\AllowedPaths";
|
||
|
const WCHAR wcsPreventCisvcParam[] = L"DonotStartCiSvc";
|
||
|
const WCHAR wcsISDefaultCatalogDirectory[] = L"IsapiDefaultCatalogDirectory";
|
||
|
|
||
|
const WCHAR wszRegProfileKey[] =
|
||
|
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList";
|
||
|
const WCHAR wszRegProfileValue[] = L"ProfilesDirectory";
|
||
|
const WCHAR wszProperties[] = L"properties";
|
||
|
|
||
|
//
|
||
|
// Directory name where system catalog will be placed
|
||
|
//
|
||
|
|
||
|
const WCHAR wszSysVolInfoDirectory[] = L"x:\\System Volume Information";
|
||
|
|
||
|
//
|
||
|
// Array of Dlls to register
|
||
|
//
|
||
|
static WCHAR * apwcDlls[] = {
|
||
|
L"query.dll",
|
||
|
L"ciadmin.dll",
|
||
|
L"ixsso.dll",
|
||
|
L"nlhtml.dll",
|
||
|
L"offfilt.dll",
|
||
|
L"ciodm.dll",
|
||
|
L"infosoft.dll",
|
||
|
L"mimefilt.dll",
|
||
|
L"LangWrbk.dll",
|
||
|
};
|
||
|
const int cDlls = NUMELEM( apwcDlls );
|
||
|
|
||
|
static WCHAR * apwcOldDlls[] = {
|
||
|
L"cifrmwrk.dll",
|
||
|
L"fsci.dll",
|
||
|
};
|
||
|
const int cOldDlls = NUMELEM( apwcOldDlls );
|
||
|
|
||
|
//
|
||
|
// utility routines
|
||
|
//
|
||
|
BOOL OpenInfFile(CError & Err);
|
||
|
|
||
|
CError::CError( )
|
||
|
{
|
||
|
SetupOpenLog(FALSE); /* don't overwrite existing log file */
|
||
|
}
|
||
|
|
||
|
CError::~CError( )
|
||
|
{
|
||
|
SetupCloseLog();
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CError::Report
|
||
|
//
|
||
|
// Synopsis: reports a message to various destinations
|
||
|
//
|
||
|
// Arguments: [LogSeverity] -- message severity
|
||
|
// [dwErr] -- The error code
|
||
|
// [MessageString]-- printf format string for message
|
||
|
// [...] -- variable arguments for message params
|
||
|
//
|
||
|
// Returns: none. don't throw.
|
||
|
//
|
||
|
// History: 2-9-98 mohamedn
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CError::Report(
|
||
|
LogSeverity Severity,
|
||
|
DWORD dwErr,
|
||
|
WCHAR const * MessageString,
|
||
|
...)
|
||
|
{
|
||
|
WCHAR awcMsgTemp[MAX_PATH * 2];
|
||
|
|
||
|
awcMsgTemp[0] = _awcMsg[0] = L'\0';
|
||
|
|
||
|
va_list va;
|
||
|
va_start(va, MessageString);
|
||
|
|
||
|
wvsprintf(awcMsgTemp, MessageString, va);
|
||
|
|
||
|
va_end(va);
|
||
|
|
||
|
// prepend on Our modules information.
|
||
|
wsprintf(_awcMsg, L"setupqry: (%#x) %s\r\n", dwErr, awcMsgTemp);
|
||
|
|
||
|
if ( !SetupLogError(_awcMsg, Severity) )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetupLogError Failed: %d\n", GetLastError() ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllMain
|
||
|
//
|
||
|
// Synopsis: The usual suspect
|
||
|
//
|
||
|
// Return: TRUE - Initialization succeeded
|
||
|
// FALSE - Initialization failed
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL WINAPI DllMain(
|
||
|
IN HANDLE DllHandle,
|
||
|
IN DWORD Reason,
|
||
|
IN LPVOID Reserved )
|
||
|
{
|
||
|
UNREFERENCED_PARAMETER(Reserved);
|
||
|
|
||
|
switch( Reason )
|
||
|
{
|
||
|
WCHAR DllName[MAX_PATH];
|
||
|
|
||
|
case DLL_PROCESS_ATTACH:
|
||
|
|
||
|
MyModuleHandle = (HINSTANCE)DllHandle;
|
||
|
|
||
|
DisableThreadLibraryCalls( MyModuleHandle );
|
||
|
|
||
|
if (!GetModuleFileName(MyModuleHandle, DllName, MAX_PATH) ||
|
||
|
!LoadLibrary( DllName ))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case DLL_PROCESS_DETACH:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
} //DllMain
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IndexSrv
|
||
|
//
|
||
|
// Synopsis: Called by the ocmgr when things happen
|
||
|
//
|
||
|
// Arguments: ComponentId -- "indexsrv_system"
|
||
|
// SubcomponentId -- the .inf section being operated on
|
||
|
// Function -- the operation
|
||
|
// Param1 -- operation paramater
|
||
|
// Param2 -- operation paramater
|
||
|
//
|
||
|
// Returns: Win32 error code (usually), depends on Function
|
||
|
//
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD IndexSrv(
|
||
|
IN LPCWSTR ComponentId,
|
||
|
IN LPCWSTR SubcomponentId,
|
||
|
IN UINT Function,
|
||
|
IN UINT Param1,
|
||
|
IN OUT PVOID Param2 )
|
||
|
{
|
||
|
DWORD dwRetVal = NO_ERROR;
|
||
|
|
||
|
isDebugOut(( "IndexSrv, Function %d\n", Function ));
|
||
|
|
||
|
//
|
||
|
// if we're aborted, do nothing.
|
||
|
//
|
||
|
if ( g_fInstallAborted )
|
||
|
return dwRetVal;
|
||
|
|
||
|
CError Err;
|
||
|
|
||
|
CSmartException xSmartException;
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
|
||
|
switch(Function)
|
||
|
{
|
||
|
|
||
|
case OC_PREINITIALIZE:
|
||
|
isDebugOut(( "OC_PREINITIALIZE\n" ));
|
||
|
|
||
|
GetSystemDirectory( g_awcSystemDir,
|
||
|
sizeof g_awcSystemDir / sizeof WCHAR );
|
||
|
|
||
|
return OCFLAG_UNICODE;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OC_SET_LANGUAGE:
|
||
|
isDebugOut(( "OC_SET_LANGUAGE\n" ));
|
||
|
|
||
|
//
|
||
|
// Param1 = low 16 bits specify Win32 LANG
|
||
|
// Param2 = unused
|
||
|
//
|
||
|
// Return code is a boolean indicating whether we think we
|
||
|
// support the requested language. We remember the language id
|
||
|
// and say we support the language. A more exact check might involve
|
||
|
// looking through our resources via EnumResourcesLnguages() for
|
||
|
// example, or checking our inf to see whether there is a matching
|
||
|
// or closely matching [strings] section. We don't bother with
|
||
|
// any of that here.
|
||
|
//
|
||
|
// Locate the component and remember the language id for later use.
|
||
|
//
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
|
||
|
case OC_INIT_COMPONENT:
|
||
|
isDebugOut(( "OC_INIT_COMPONENT\n" ));
|
||
|
|
||
|
isDebugOut(( DEB_TRACE, "init_component: '%ws'\n", ComponentId ));
|
||
|
|
||
|
if (OCMANAGER_VERSION <= ((PSETUP_INIT_COMPONENT)Param2)->OCManagerVersion)
|
||
|
{
|
||
|
((PSETUP_INIT_COMPONENT)Param2)->ComponentVersion = OCMANAGER_VERSION;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ISError( IS_MSG_INVALID_OCM_VERSION, Err, LogSevFatalError );
|
||
|
|
||
|
isDebugOut(( "wrong ocmgr version!\n" ));
|
||
|
|
||
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
if ( g_fInstallAborted )
|
||
|
{
|
||
|
ISError( IS_MSG_ABORT, Err, LogSevFatalError );
|
||
|
|
||
|
dwRetVal = ERROR_CANCELLED;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Param1 = unused
|
||
|
// Param2 = points to SETUP_INIT_COMPONENT structure
|
||
|
//
|
||
|
// Return code is Win32 error indicating outcome.
|
||
|
// ERROR_CANCELLED means this component's install will be aborted.
|
||
|
//
|
||
|
// Even though this call happens once for each component that this
|
||
|
// dll installs, we really only need to do our thing once. This is
|
||
|
// because the data that OCM passes is the same for all calls.
|
||
|
//
|
||
|
|
||
|
if (!g_fComponentInitialized)
|
||
|
{
|
||
|
PSETUP_INIT_COMPONENT InitComponent = (PSETUP_INIT_COMPONENT)Param2;
|
||
|
g_HelperRoutines = InitComponent->HelperRoutines;
|
||
|
|
||
|
CopyMemory( &gSetupInitComponent, (LPVOID)Param2, sizeof(SETUP_INIT_COMPONENT) );
|
||
|
|
||
|
g_fUnattended = (gSetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) != 0;
|
||
|
g_fUpgrade = (gSetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) != 0;
|
||
|
g_fNtGuiMode = (gSetupInitComponent.SetupData.OperationFlags & SETUPOP_STANDALONE) == 0;
|
||
|
g_NtType = gSetupInitComponent.SetupData.ProductType;
|
||
|
|
||
|
isDebugOut(( DEB_TRACE, "g_fUnattended: %d\n", g_fUnattended ));
|
||
|
isDebugOut(( DEB_TRACE, "g_fUpgrade: %d\n", g_fUpgrade ));
|
||
|
isDebugOut(( DEB_TRACE, "g_fNtGuiMode: %d\n", g_fNtGuiMode ));
|
||
|
isDebugOut(( DEB_TRACE, "g_NtType: %d\n", g_NtType ));
|
||
|
|
||
|
if (gSetupInitComponent.ComponentInfHandle == NULL)
|
||
|
{
|
||
|
if ( !OpenInfFile(Err) )
|
||
|
{
|
||
|
ISError(IS_MSG_INVALID_INF_HANDLE, Err, LogSevFatalError);
|
||
|
dwRetVal = ERROR_CANCELLED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_fComponentInitialized = TRUE;
|
||
|
dwRetVal = NO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// determine if this an NT4-->NT5 upgrade
|
||
|
//
|
||
|
|
||
|
GetPreviousISSetupVersion();
|
||
|
|
||
|
if ( g_dwPrevISVersion > 0 && g_dwPrevISVersion < g_MajorVersion )
|
||
|
{
|
||
|
g_fNT4_To_NT5_Upgrade = TRUE;
|
||
|
|
||
|
// g_dwPrevIsVersion is 0 if the ContentIndex key doesn't exist
|
||
|
|
||
|
if ( 1 == g_dwPrevISVersion )
|
||
|
g_fIS1x_To_NT5_Upgrade = TRUE;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OC_QUERY_STATE:
|
||
|
isDebugOut(( "OC_QUERY_STATE\n" ));
|
||
|
|
||
|
if ( !SubcomponentId || _wcsicmp(SubcomponentId,wcsIndexsrvSystem) )
|
||
|
return NO_ERROR;
|
||
|
|
||
|
//
|
||
|
// We can't return SubcompUseOcManagerDefault if 1.x is installed
|
||
|
// the ocmgr registry key for index server won't be set if 1.x was
|
||
|
// installed using the non-ocmgr installation. In this case, check
|
||
|
// if the ContentIndex key exists and if so return SubcompOn.
|
||
|
//
|
||
|
|
||
|
if ( ( OCSELSTATETYPE_ORIGINAL == Param1 ) && g_fIS1x_To_NT5_Upgrade )
|
||
|
{
|
||
|
isDebugOut(( "Upgrading from 1.x to NT 5, turning on IS by default\n" ));
|
||
|
isDebugOut(( DEB_ITRACE, "Upgrading from 1.x to NT 5, turning on IS by default\n" ));
|
||
|
|
||
|
dwRetVal = SubcompOn;
|
||
|
}
|
||
|
else
|
||
|
dwRetVal = SubcompUseOcManagerDefault;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OC_REQUEST_PAGES:
|
||
|
isDebugOut(( "OC_REQUEST_PAGES\n" ));
|
||
|
|
||
|
return 0; // no pages
|
||
|
// break;
|
||
|
|
||
|
case OC_QUERY_CHANGE_SEL_STATE:
|
||
|
isDebugOut(( "OC_QUERY_CHANGE_SEL_STATE\n" ));
|
||
|
|
||
|
isDebugOut(( "queryChangeSelState %#x, %#x, %#x\n", SubcomponentId, Param1, Param2 ));
|
||
|
|
||
|
if ( !SubcomponentId || _wcsicmp(SubcomponentId,wcsIndexsrvSystem) )
|
||
|
{
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
if ( Param1 == 0 )
|
||
|
{
|
||
|
//
|
||
|
// we're not selected
|
||
|
//
|
||
|
if ( 0 == g_cChangeSelection || !g_fFalseAlready )
|
||
|
{
|
||
|
g_cChangeSelection++;
|
||
|
g_fFalseAlready = TRUE;
|
||
|
}
|
||
|
|
||
|
g_fCiSvcIsRequested = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// we are selected
|
||
|
//
|
||
|
if ( 0 == g_cChangeSelection || g_fFalseAlready )
|
||
|
{
|
||
|
g_cChangeSelection++;
|
||
|
g_fFalseAlready = FALSE;
|
||
|
}
|
||
|
|
||
|
g_fCiSvcIsRequested = TRUE;
|
||
|
}
|
||
|
|
||
|
dwRetVal = TRUE;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
case OC_CALC_DISK_SPACE:
|
||
|
isDebugOut(( "OC_CALC_DISK_SPACE\n" ));
|
||
|
|
||
|
//
|
||
|
// skip, no files are copied.
|
||
|
//
|
||
|
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "Calc Disk Space Failed: %d\n", dwRetVal ));
|
||
|
|
||
|
ISError( IS_MSG_CALC_DISK_SPACE_FAILED, Err, LogSevError );
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OC_QUEUE_FILE_OPS:
|
||
|
isDebugOut(( "OC_QUEUE_FILE_OPS\n" ));
|
||
|
|
||
|
//
|
||
|
// Param1 = unused
|
||
|
// Param2 = HSPFILEQ to operate on
|
||
|
//
|
||
|
// Return value is Win32 error code indicating outcome.
|
||
|
//
|
||
|
// OC Manager calls this routine when it is ready for files to be
|
||
|
// copied to effect the changes the user requested. The component
|
||
|
// DLL must figure out whether it is being installed or uninstalled
|
||
|
// and take appropriate action.
|
||
|
// For this sample, we look in the private data section for this
|
||
|
// component/subcomponent pair, and get the name of an uninstall
|
||
|
// section for the uninstall case.
|
||
|
//
|
||
|
// Note that OC Manager calls us once for the *entire* component
|
||
|
// and then once per subcomponent.
|
||
|
//
|
||
|
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "Queue File Operations Failed: %d\n", dwRetVal ));
|
||
|
|
||
|
ISError( IS_MSG_QUEUE_FILE_OPS_FAILED, Err, LogSevError );
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OC_QUERY_STEP_COUNT:
|
||
|
isDebugOut(( "OC_QUERY_STEP_COUNT\n" ));
|
||
|
|
||
|
//
|
||
|
// Param1 = unused
|
||
|
// Param2 = unused
|
||
|
//
|
||
|
// Return value is an arbitrary 'step' count or -1 if error.
|
||
|
//
|
||
|
// OC Manager calls this routine when it wants to find out how much
|
||
|
// work the component wants to perform for nonfile operations to
|
||
|
// install/uninstall a component/subcomponent.
|
||
|
// It is called once for the *entire* component and then once for
|
||
|
// each subcomponent in the component.
|
||
|
//
|
||
|
// One could get arbitrarily fancy here but we simply return 1 step
|
||
|
// per subcomponent. We ignore the "entire component" case.
|
||
|
//
|
||
|
if ( !SubcomponentId || _wcsicmp( SubcomponentId,wcsIndexsrvSystem ) )
|
||
|
{
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
dwRetVal = 1;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OC_ABOUT_TO_COMMIT_QUEUE:
|
||
|
isDebugOut(( "OC_ABOUT_TO_COMMIT_QUEUE\n" ));
|
||
|
|
||
|
if ( !SubcomponentId || _wcsicmp( wcsIndexsrvSystem,SubcomponentId ) )
|
||
|
{
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
dwRetVal = QueueConfigurationParams( gSetupInitComponent.ComponentInfHandle,
|
||
|
(HSPFILEQ) Param2,
|
||
|
SubcomponentId,
|
||
|
Err );
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut((DEB_ERROR,"QueueConfigurationParams Failed: %d\n",dwRetVal ));
|
||
|
|
||
|
ISError( IS_MSG_QUEUE_CONFIG_PARAMS_FAILED, Err, LogSevError, dwRetVal );
|
||
|
|
||
|
return ERROR_CANCELLED;
|
||
|
}
|
||
|
|
||
|
dwRetVal = SetRegBasedOnMachine(Err);
|
||
|
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetRegBasedOnMachine Failed: %d\n", dwRetVal ));
|
||
|
|
||
|
ISError( IS_MSG_SetRegBasedOnMachine_FAILED, Err, LogSevError, dwRetVal );
|
||
|
}
|
||
|
|
||
|
dwRetVal = SetRegBasedOnArchitecture(Err);
|
||
|
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetRegBasedOnArchitecture Failed: %d\n", dwRetVal ));
|
||
|
|
||
|
Err.Report(LogSevError, dwRetVal, L"SetRegBasedOnArchitecture FAILED");
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OC_COMPLETE_INSTALLATION:
|
||
|
isDebugOut(( "OC_COMPLETE_INSTALLATION\n" ));
|
||
|
|
||
|
if ( !SubcomponentId || _wcsicmp(SubcomponentId,wcsIndexsrvSystem) )
|
||
|
{
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
dwRetVal = CompleteInstallation(Err);
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "CompleteInstallation Failed: %d\n", dwRetVal ));
|
||
|
|
||
|
ISError( IS_MSG_COMPLETE_INSTALLATION_FAILED, Err, LogSevError, dwRetVal );
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( g_fLocallyOpened &&
|
||
|
INVALID_HANDLE_VALUE != gSetupInitComponent.ComponentInfHandle )
|
||
|
{
|
||
|
SetupCloseInfFile(gSetupInitComponent.ComponentInfHandle);
|
||
|
|
||
|
gSetupInitComponent.ComponentInfHandle = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
|
||
|
g_fInstallCancelled = FALSE;
|
||
|
break;
|
||
|
|
||
|
case OC_CLEANUP:
|
||
|
isDebugOut(( "OC_CLEANUP\n" ));
|
||
|
|
||
|
//
|
||
|
// Do last-minute work now that the metabase is installed
|
||
|
//
|
||
|
|
||
|
OcCleanup( Err );
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OC_QUERY_IMAGE:
|
||
|
isDebugOut(( "OC_QUERY_IMAGE\n" ));
|
||
|
//
|
||
|
// not used
|
||
|
//
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
isDebugOut(( "OC_ message ignored\n" ));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
isDebugOut(( "IndexSrv is returning %d\n", dwRetVal ));
|
||
|
|
||
|
return dwRetVal;
|
||
|
|
||
|
}
|
||
|
CATCH (CException, e)
|
||
|
{
|
||
|
isDebugOut(( "install is aborted, error %#x\n", e.GetErrorCode() ));
|
||
|
|
||
|
g_fInstallAborted = TRUE;
|
||
|
|
||
|
if ( g_fLocallyOpened &&
|
||
|
INVALID_HANDLE_VALUE != gSetupInitComponent.ComponentInfHandle )
|
||
|
{
|
||
|
SetupCloseInfFile(gSetupInitComponent.ComponentInfHandle);
|
||
|
|
||
|
gSetupInitComponent.ComponentInfHandle = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
|
||
|
ISError( IS_MSG_EXCEPTION_CAUGHT, Err, LogSevError, e.GetErrorCode() );
|
||
|
|
||
|
dwRetVal = e.GetErrorCode();
|
||
|
}
|
||
|
END_CATCH
|
||
|
|
||
|
return dwRetVal;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OcCleanup
|
||
|
//
|
||
|
// Synopsis: Finish setup work now that everything else is installed. It
|
||
|
// would be better to do this in OC_COMPLETE_INSTALLATION, but
|
||
|
// there is no guarantee IIS is installed by that point.
|
||
|
//
|
||
|
// History: 11-3-98 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void OcCleanup( CError & Err )
|
||
|
{
|
||
|
//
|
||
|
// Add metabase settings if IIS is around
|
||
|
//
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
if ( !g_fInstallCancelled )
|
||
|
SetupW3Svc(Err);
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
// If IIS isn't installed then setting up w3svc will fail. Ignore
|
||
|
isDebugOut(( "caught %#x adding w3svc stuff\n", e.GetErrorCode() ));
|
||
|
}
|
||
|
END_CATCH
|
||
|
|
||
|
//
|
||
|
// Start cisvc service if it was running, we're selected, and not in
|
||
|
// NT setup mode.
|
||
|
//
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
if ( ( g_fCiSvcWasRunning && !g_cChangeSelection ) ||
|
||
|
( g_fCiSvcIsRequested && !g_fNtGuiMode && !g_fInstallCancelled ) )
|
||
|
{
|
||
|
StartService(L"CiSvc");
|
||
|
}
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
// Don't hose the install if we can't start the service
|
||
|
isDebugOut(( "caught %#x starting service\n", e.GetErrorCode() ));
|
||
|
}
|
||
|
END_CATCH
|
||
|
} //OcCleanup
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OpenInfFile
|
||
|
//
|
||
|
// Synopsis: opens a handle to setupqry.inf file
|
||
|
//
|
||
|
// Returns: True upon success, False upon failure.
|
||
|
//
|
||
|
// History: 6-28-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL OpenInfFile(CError & Err)
|
||
|
{
|
||
|
WCHAR InfPath[MAX_PATH];
|
||
|
|
||
|
DWORD dwRetVal = GetModuleFileName( MyModuleHandle, InfPath, NUMELEM(InfPath));
|
||
|
|
||
|
if ( 0 == dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "GetModuleFileName() Failed: %d\n", GetLastError() ));
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
LPWSTR p = wcsrchr( InfPath, L'\\' );
|
||
|
if (p)
|
||
|
{
|
||
|
wcscpy( p+1, L"setupqry.inf" );
|
||
|
|
||
|
gSetupInitComponent.ComponentInfHandle = SetupOpenInfFile( InfPath, NULL, INF_STYLE_WIN4, NULL );
|
||
|
|
||
|
if (gSetupInitComponent.ComponentInfHandle == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetupOpenInfFile(%ws) Failed: %d\n", InfPath, GetLastError() ));
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
g_fLocallyOpened = TRUE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: QueueConfigurationParams
|
||
|
//
|
||
|
// Synopsis: queue-up an inf section to install
|
||
|
//
|
||
|
// Returns: NO_ERROR upon success, win32 error upon failure
|
||
|
//
|
||
|
// History: 6-28-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD QueueConfigurationParams( HINF hInf, HSPFILEQ Param2, WCHAR const * pwszSectionName, CError &Err )
|
||
|
{
|
||
|
|
||
|
BOOL fOk = SetupInstallFromInfSection( 0,
|
||
|
hInf,
|
||
|
pwszSectionName,
|
||
|
SPINST_REGISTRY,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
0 );
|
||
|
if ( !fOk )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetupInstallFromInfSection(%ws) Failed: %d\n",
|
||
|
pwszSectionName, GetLastError() ));
|
||
|
|
||
|
ISError( IS_MSG_SETUP_INSTALL_FROM_INFSECTION_FAILED, Err,
|
||
|
LogSevError, GetLastError() );
|
||
|
}
|
||
|
|
||
|
return ( fOk ? NO_ERROR : GetLastError() );
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetupW3Svc
|
||
|
//
|
||
|
// Synopsis: Setup catalogs and script mappings for IIS
|
||
|
//
|
||
|
// Arguments: [Err] -- Error reporting object
|
||
|
//
|
||
|
// History: 13-May-1998 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void SetupW3Svc(CError &Err)
|
||
|
{
|
||
|
BOOL fCurrentlyChecked = g_HelperRoutines.QuerySelectionState(
|
||
|
g_HelperRoutines.OcManagerContext,
|
||
|
wcsIndexsrvSystem,
|
||
|
OCSELSTATETYPE_CURRENT );
|
||
|
|
||
|
isDebugOut(( "currently checked: %d\n", fCurrentlyChecked ));
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Initialize/Uninitialize COM. Allow any old mode, and allow
|
||
|
// for the fact that some other broken component may have left
|
||
|
// COM initialized.
|
||
|
//
|
||
|
|
||
|
XCom xcom( TRUE );
|
||
|
WCHAR awc[MAX_PATH];
|
||
|
|
||
|
isDebugOut(( "SetupW3Svc\n" ));
|
||
|
isDebugOut(( " g_fCiSvcIsRequested: %d\n", g_fCiSvcIsRequested ));
|
||
|
isDebugOut(( " g_fNtGuiMode: %d\n", g_fNtGuiMode ));
|
||
|
isDebugOut(( " g_cChangeSelection: %d\n", g_cChangeSelection ));
|
||
|
isDebugOut(( " g_dwPrevISVersion: %d \n", g_dwPrevISVersion ));
|
||
|
isDebugOut(( " g_fUpgrade: %d\n", g_fUpgrade ));
|
||
|
|
||
|
{
|
||
|
//
|
||
|
// Is W3Svc even installed?
|
||
|
//
|
||
|
|
||
|
CMetaDataMgr mdMgr( TRUE, W3VRoot );
|
||
|
|
||
|
//
|
||
|
// Guess so. We didn't throw. Now, add the script mappings if
|
||
|
// if appropriate:
|
||
|
//
|
||
|
// If the checkbox is selected, add scriptmaps if
|
||
|
// clean install or
|
||
|
// add/remove and they changed the state of the checkbox
|
||
|
// upgrade and scriptmaps weren't deleted by hand by the user
|
||
|
//
|
||
|
// Delete scriptmaps if
|
||
|
// Checkbox is unchecked and there was a change in the selection state
|
||
|
//
|
||
|
// Note the state of the checked/unchecked variable g_fCiSvcIsRequested
|
||
|
// is only valid in add/remove AND if the user has changed the selection.
|
||
|
// So this code uses fCurrentlyChecked instead.
|
||
|
//
|
||
|
|
||
|
if ( ( fCurrentlyChecked ) &&
|
||
|
( g_fNtGuiMode || ( 0 != g_cChangeSelection ) ) )
|
||
|
{
|
||
|
//
|
||
|
// IDQ and WEBHITS are always in System32
|
||
|
//
|
||
|
|
||
|
if ( (MAX_PATH - wcslen(g_awcSystemDir)) < 30 ) // DLL won't fit
|
||
|
break;
|
||
|
|
||
|
wcscpy( awc, L".idq," );
|
||
|
wcscat( awc, g_awcSystemDir );
|
||
|
|
||
|
//
|
||
|
// Add IDQ if add/remove OR
|
||
|
// clean install OR
|
||
|
// there is already a scriptmap OR
|
||
|
// there already is a (possibly old) scriptmap pointing at the expected dll
|
||
|
//
|
||
|
//
|
||
|
// Note: the "IIS lockdown" tool points our scriptmaps at
|
||
|
// 404.dll; it doesn't delete them. I have no idea why.
|
||
|
//
|
||
|
//
|
||
|
// scriptmap flags -- 0x2 is obsolete (apparently)
|
||
|
//
|
||
|
// #define MD_SCRIPTMAPFLAG_SCRIPT 0x00000001
|
||
|
// #define MD_SCRIPTMAPFLAG_CHECK_PATH_INFO 0x00000004
|
||
|
//
|
||
|
// Can't check path info for .htw due to null.htw support
|
||
|
//
|
||
|
|
||
|
wcscat( awc, L"\\idq.dll,7,GET,HEAD,POST" );
|
||
|
if ( ( !g_fNtGuiMode ) ||
|
||
|
( g_fNtGuiMode && !g_fUpgrade ) ||
|
||
|
( 0 == g_dwPrevISVersion ) ||
|
||
|
( mdMgr.ExtensionHasTargetScriptMap( L".idq", L"idq.dll" ) ) )
|
||
|
mdMgr.AddScriptMap( awc );
|
||
|
|
||
|
//
|
||
|
// Add IDA if add/remove or there is already a valid scriptmap
|
||
|
//
|
||
|
|
||
|
awc[3] = L'a';
|
||
|
if ( ( !g_fNtGuiMode ) ||
|
||
|
( g_fNtGuiMode && !g_fUpgrade ) ||
|
||
|
( 0 == g_dwPrevISVersion ) ||
|
||
|
( mdMgr.ExtensionHasTargetScriptMap( L".ida", L"idq.dll" ) ) )
|
||
|
mdMgr.AddScriptMap( awc );
|
||
|
|
||
|
//
|
||
|
// Add HTW if add/remove or there is already a valid scriptmap
|
||
|
//
|
||
|
|
||
|
wcscpy( awc, L".htw," );
|
||
|
wcscat( awc, g_awcSystemDir );
|
||
|
wcscat( awc, L"\\webhits.dll,3,GET,HEAD,POST" );
|
||
|
|
||
|
if ( ( !g_fNtGuiMode ) ||
|
||
|
( g_fNtGuiMode && !g_fUpgrade ) ||
|
||
|
( 0 == g_dwPrevISVersion ) ||
|
||
|
( mdMgr.ExtensionHasTargetScriptMap( L".htw", L"webhits.dll" ) ) )
|
||
|
mdMgr.AddScriptMap( awc );
|
||
|
|
||
|
//
|
||
|
// Add IS script maps as in-process. Always do this.
|
||
|
//
|
||
|
|
||
|
wcscpy( awc, g_awcSystemDir );
|
||
|
wcscat( awc, L"\\idq.dll" );
|
||
|
mdMgr.AddInProcessIsapiApp( awc );
|
||
|
|
||
|
//
|
||
|
// By default, run this OOP. The user can run in IP if they need to
|
||
|
// webhit files on remote virtual roots.
|
||
|
//
|
||
|
|
||
|
#if 0
|
||
|
wcscpy( awc, g_awcSystemDir );
|
||
|
wcscat( awc, L"\\webhits.dll" );
|
||
|
mdMgr.AddInProcessIsapiApp( awc );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if ( ( !fCurrentlyChecked ) && ( 0 != g_cChangeSelection ) )
|
||
|
{
|
||
|
mdMgr.RemoveScriptMap( L".idq" );
|
||
|
mdMgr.RemoveScriptMap( L".ida" );
|
||
|
mdMgr.RemoveScriptMap( L".htw" );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure it makes it out to disk
|
||
|
//
|
||
|
|
||
|
mdMgr.Flush();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Only create a web catalog if everything looks like a new install...
|
||
|
//
|
||
|
|
||
|
BOOL fNew = FALSE;
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegCatalogsWebSubKey );
|
||
|
|
||
|
if ( reg.Ok() )
|
||
|
{
|
||
|
WCHAR wcsSubKeyName[MAX_PATH+1];
|
||
|
DWORD cwcName = sizeof wcsSubKeyName / sizeof WCHAR;
|
||
|
|
||
|
if ( reg.Enum( wcsSubKeyName, cwcName ) )
|
||
|
{
|
||
|
// There is at least one subkey
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// if there is a subkey other than properties,
|
||
|
// we're not createing a new web catalog
|
||
|
//
|
||
|
if ( 0 != _wcsicmp( wcsSubKeyName, wszProperties ) )
|
||
|
{
|
||
|
fNew = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
fNew = TRUE;
|
||
|
|
||
|
} while ( reg.Enum( wcsSubKeyName, cwcName ) );
|
||
|
}
|
||
|
else
|
||
|
fNew = TRUE;
|
||
|
}
|
||
|
else
|
||
|
fNew = TRUE;
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
fNew = TRUE;
|
||
|
}
|
||
|
END_CATCH
|
||
|
|
||
|
if ( !fNew )
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// Must look like a default install...
|
||
|
//
|
||
|
|
||
|
CMetaDataMgr mdMgrDefaultServer( FALSE, W3VRoot, 1 );
|
||
|
mdMgrDefaultServer.GetVRoot( L"/", awc );
|
||
|
|
||
|
unsigned ccRoot = wcslen(awc) - 8; // <path> - "\wwwroot"
|
||
|
|
||
|
if ( 0 != _wcsicmp( awc + ccRoot, L"\\wwwroot" ) )
|
||
|
break;
|
||
|
|
||
|
awc[ccRoot] = 0;
|
||
|
|
||
|
//
|
||
|
// Add a web catalog.
|
||
|
//
|
||
|
|
||
|
CCatReg CatReg(Err);
|
||
|
CatReg.Init( L"Web", awc );
|
||
|
CatReg.TrackW3Svc();
|
||
|
|
||
|
//
|
||
|
// set ISAPIDefaultCatalogDirectory to Web
|
||
|
//
|
||
|
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey );
|
||
|
|
||
|
if ( !reg.Set( wcsISDefaultCatalogDirectory, L"Web" ) )
|
||
|
{
|
||
|
ISError( IS_MSG_COULD_NOT_MODIFY_REGISTRY, Err,
|
||
|
LogSevWarning, GetLastError() );
|
||
|
return;
|
||
|
}
|
||
|
} while(FALSE);
|
||
|
|
||
|
isDebugOut(( "successfully added w3svc stuff\n" ));
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
isDebugOut(( "caught %x in SetupW3Svc\n", e.GetErrorCode() ));
|
||
|
}
|
||
|
END_CATCH
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CompleteInstallation
|
||
|
//
|
||
|
// Synopsis: called by NT setup to cofigure Index server for operation.
|
||
|
//
|
||
|
// Returns: SCODE, S_OK upon success, other values upon failure
|
||
|
//
|
||
|
// History: 6-28-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CompleteInstallation(CError &Err)
|
||
|
{
|
||
|
SCODE sc = S_OK;
|
||
|
DWORD dwRetVal = 0;
|
||
|
DWORD dwLastError = 0;
|
||
|
|
||
|
//MessageBox(NULL, L"BREAK HERE", NULL, MB_OK);
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Delete the "DonotStartCiSvc" registry parameter
|
||
|
//
|
||
|
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey );
|
||
|
reg.Remove(wcsPreventCisvcParam);
|
||
|
|
||
|
dwRetVal = SetDLLsToRegister (Err);
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetDllsToRegister Failed: %d", dwRetVal ));
|
||
|
|
||
|
ISError( IS_MSG_SetDllsToRegister_FAILED, Err, LogSevError, dwRetVal );
|
||
|
|
||
|
THROW(CException(HRESULT_FROM_WIN32(dwRetVal)) );
|
||
|
}
|
||
|
|
||
|
dwRetVal = SetFilterRegistryInfo(FALSE, Err);
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetFilterRegistryInfo Failed: %d", dwRetVal ));
|
||
|
|
||
|
ISError( IS_MSG_SetFilterRegistryInfo_FAILED, Err, LogSevError, dwRetVal );
|
||
|
|
||
|
THROW(CException(HRESULT_FROM_WIN32(dwRetVal)) );
|
||
|
}
|
||
|
|
||
|
dwRetVal = AddPerfData(Err);
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "AddPerfData Failed: %d\n",dwRetVal));
|
||
|
|
||
|
THROW(CException(HRESULT_FROM_WIN32(dwRetVal)) );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// stop cisvc
|
||
|
//
|
||
|
|
||
|
StopService(L"cisvc");
|
||
|
|
||
|
//
|
||
|
// Upgrade 1.1 to 3.0 if needed. Must happen *before* AddCiSvc().
|
||
|
//
|
||
|
|
||
|
UpgradeIS1toIS3(Err);
|
||
|
|
||
|
//
|
||
|
// Delete the NTOP start menu items IS created
|
||
|
//
|
||
|
|
||
|
DeleteNTOPStartMenu();
|
||
|
|
||
|
//
|
||
|
// configure catalogs
|
||
|
//
|
||
|
|
||
|
dwRetVal = SetDefaultCatalog(Err);
|
||
|
|
||
|
if ( NO_ERROR != dwRetVal )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "SetDefaultCatalog Failed: %d\n",dwRetVal));
|
||
|
|
||
|
ISError( IS_MSG_SetDefaultCatalog_FAILED, Err, LogSevError, dwRetVal );
|
||
|
|
||
|
THROW(CException(HRESULT_FROM_WIN32(dwRetVal)) );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if selection count is odd (user changed the selection),
|
||
|
// delete the service to create a new one. Also delete and
|
||
|
// re-create if we're upgrading IS 1.x.
|
||
|
//
|
||
|
|
||
|
if ( ( !g_fUpgrade && ( g_cChangeSelection & 0x1 ) ) ||
|
||
|
1 == g_dwPrevISVersion )
|
||
|
DeleteService(L"cisvc");
|
||
|
|
||
|
//
|
||
|
// add the service
|
||
|
//
|
||
|
|
||
|
AddCiSvc(Err);
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "Caught Exception in CompleteInstallation: %d\n",e.GetErrorCode() ));
|
||
|
|
||
|
ISError( IS_MSG_EXCEPTION_CAUGHT, Err, LogSevError, e.GetErrorCode() );
|
||
|
|
||
|
sc = e.GetErrorCode();
|
||
|
isDebugOut(( "Caught Exception in CompleteInstallation: %#x\n", sc ));
|
||
|
|
||
|
}
|
||
|
END_CATCH
|
||
|
|
||
|
return sc;
|
||
|
|
||
|
} //CompleteInstallation
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UpgradeIS1toIS3
|
||
|
//
|
||
|
// Synopsis: sets ISapiDefaultCatalogDirectory param if we're upgrading
|
||
|
// from 1.0 or 1.1 to 3.0
|
||
|
//
|
||
|
// Returns: none.
|
||
|
//
|
||
|
// History: 01-May-1998 mohamedn created
|
||
|
// 05-Sep-1998 KyleP Start service on upgrade
|
||
|
//
|
||
|
// Notes: This *must* be called before AddCisvc, since the decision
|
||
|
// about whether to start the service may be changed in
|
||
|
// this function.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void UpgradeIS1toIS3(CError &Err)
|
||
|
{
|
||
|
if ( !g_fNT4_To_NT5_Upgrade || g_dwPrevISVersion >= 2 )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
g_awcIS1Path[0] = L'\0';
|
||
|
|
||
|
{
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey );
|
||
|
|
||
|
reg.Get( wcsISDefaultCatalogDirectory, g_awcIS1Path, NUMELEM( g_awcIS1Path ) );
|
||
|
|
||
|
if ( 0 == wcslen(g_awcIS1Path) || g_awcIS1Path[1] != L':' )
|
||
|
{
|
||
|
//
|
||
|
// nothing to do.
|
||
|
//
|
||
|
g_awcIS1Path[0] = L'\0';
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The 'Catalogs' key needs to be created.
|
||
|
//
|
||
|
|
||
|
{
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey );
|
||
|
BOOL fExisted;
|
||
|
|
||
|
if ( !reg.CreateKey( L"Catalogs", fExisted ) )
|
||
|
{
|
||
|
DWORD dw = GetLastError();
|
||
|
|
||
|
isDebugOut(( DEB_ERROR, "created catalogs subkey Failed: %d\n", dw ));
|
||
|
|
||
|
ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, Err , LogSevFatalError, dw );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// create the web catalog
|
||
|
//
|
||
|
|
||
|
CCatReg CatReg(Err);
|
||
|
|
||
|
CatReg.Init( L"Web", g_awcIS1Path );
|
||
|
CatReg.TrackW3Svc();
|
||
|
|
||
|
//
|
||
|
// set ISAPIDefaultCatalogDirectory to Web
|
||
|
//
|
||
|
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey );
|
||
|
if ( !reg.Set( wcsISDefaultCatalogDirectory, L"Web" ) )
|
||
|
{
|
||
|
ISError(IS_MSG_COULD_NOT_MODIFY_REGISTRY , Err, LogSevWarning, GetLastError() );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// CI was running before the upgrade, so make sure it is running after
|
||
|
// the upgrade as well.
|
||
|
//
|
||
|
|
||
|
g_fCiSvcIsRequested = TRUE;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetPreviousISSetupVersion
|
||
|
//
|
||
|
// Synopsis: gets version of previous installed IS, if any.
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Returns: none
|
||
|
//
|
||
|
// History: 10-16-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void GetPreviousISSetupVersion(void)
|
||
|
{
|
||
|
HKEY hKey = 0;
|
||
|
DWORD dwType = 0;
|
||
|
DWORD dwVal = 0;
|
||
|
DWORD cb = sizeof DWORD;
|
||
|
|
||
|
//
|
||
|
// If it's not an upgrade, don't try to get the previous version as someone is
|
||
|
// now writing contentindex\DoNotStartCisvc to the registry so we would
|
||
|
// otherwise assume it's an upgrade without this check.
|
||
|
//
|
||
|
|
||
|
if ( !g_fUpgrade )
|
||
|
return;
|
||
|
|
||
|
LONG lRetVal = RegOpenKeyEx( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey, 0, KEY_READ, &hKey );
|
||
|
|
||
|
if ( ERROR_SUCCESS == lRetVal )
|
||
|
{
|
||
|
lRetVal = RegQueryValueEx( hKey,
|
||
|
L"MajorVersion",
|
||
|
0,
|
||
|
&dwType,
|
||
|
(BYTE *)&dwVal,
|
||
|
&cb );
|
||
|
if ( ERROR_SUCCESS == lRetVal )
|
||
|
g_dwPrevISVersion = dwVal;
|
||
|
else
|
||
|
g_dwPrevISVersion = 1; // We didn't write this key in V1.
|
||
|
|
||
|
RegCloseKey( hKey );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetDefaultCatalog
|
||
|
//
|
||
|
// Synopsis: Configures IS catalog for indexing local file system based on
|
||
|
// available disk space.
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Returns: ErrorSuccess upon success, error value upon failure.
|
||
|
//
|
||
|
// History: 9-10-97 mohamedn
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD SetDefaultCatalog(CError &Err)
|
||
|
{
|
||
|
BOOL fExisted;
|
||
|
DWORD dwRetVal = NO_ERROR;
|
||
|
|
||
|
if ( !IsSufficientMemory() )
|
||
|
{
|
||
|
ISError( IS_MSG_BAD_MACHINE, Err, LogSevError );
|
||
|
|
||
|
ISError( IS_MSG_NEEDED_HARDWARE, Err, LogSevError );
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey );
|
||
|
|
||
|
if (!reg.CreateKey( L"Catalogs", fExisted ) )
|
||
|
{
|
||
|
DWORD dw = GetLastError();
|
||
|
|
||
|
isDebugOut(( DEB_ERROR, "created catalogs subkey Failed: %d\n", dw ));
|
||
|
|
||
|
ISError( IS_MSG_COULD_NOT_CONFIGURE_CATALOGS, Err , LogSevFatalError, dw );
|
||
|
|
||
|
return dw;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// return if Catalogs key exists, don't overwrite existing configuration
|
||
|
//
|
||
|
if ( fExisted && !g_fNT4_To_NT5_Upgrade )
|
||
|
{
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find the default profile path (Usually %windir%\Profiles)
|
||
|
//
|
||
|
|
||
|
CWin32RegAccess regProfileKey( HKEY_LOCAL_MACHINE, wszRegProfileKey );
|
||
|
|
||
|
g_awcProfilePath[0] = L'\0';
|
||
|
WCHAR wcTemp[MAX_PATH+1];
|
||
|
|
||
|
if ( regProfileKey.Get( wszRegProfileValue, wcTemp, NUMELEM(wcTemp) ) )
|
||
|
{
|
||
|
unsigned ccTemp2 = ExpandEnvironmentStrings( wcTemp,
|
||
|
g_awcProfilePath,
|
||
|
NUMELEM(g_awcProfilePath) );
|
||
|
}
|
||
|
|
||
|
CCatalogConfig Cat(Err);
|
||
|
Cat.SetName( L"System" );
|
||
|
|
||
|
if ( !Cat.InitDriveList() )
|
||
|
{
|
||
|
ISError( IS_MSG_DRIVE_ENUMERATION_FAILED, Err, LogSevError, GetLastError() );
|
||
|
|
||
|
return ERROR_INSTALL_FAILURE;
|
||
|
}
|
||
|
|
||
|
BOOL bRetVal = Cat.ConfigureDefaultCatalog( g_awcProfilePath );
|
||
|
|
||
|
if (bRetVal)
|
||
|
{
|
||
|
//
|
||
|
// add paths to exclude indexing IE temp files.
|
||
|
//
|
||
|
ExcludeSpecialLocations( Cat );
|
||
|
|
||
|
//
|
||
|
// Set the catalog location
|
||
|
wcsncpy(wcTemp, wszSysVolInfoDirectory, sizeof wcTemp / sizeof WCHAR);
|
||
|
wcTemp[ (sizeof wcTemp / sizeof WCHAR) - 1 ] = 0;
|
||
|
wcTemp[0] = *(Cat.GetCatalogDrive());
|
||
|
Cat.SetLocation( wcTemp );
|
||
|
|
||
|
// NOTE: The catalog path will be created when first accessed by
|
||
|
// CClientDocStore.
|
||
|
|
||
|
Cat.SaveState();
|
||
|
}
|
||
|
|
||
|
return ( bRetVal ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE );
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetDLLsToRegister
|
||
|
//
|
||
|
// Synopsis: Sets the "DLLsToRegister" value in the registry
|
||
|
//
|
||
|
// History: 19-Jun-97 t-elainc Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD SetDLLsToRegister(CError &Err)
|
||
|
{
|
||
|
WCHAR * apwc2[cDlls];
|
||
|
unsigned cwcTotal = 1;
|
||
|
|
||
|
// store full pathnames in array 2
|
||
|
|
||
|
for (int i = 0; i < cDlls; i++)
|
||
|
{
|
||
|
unsigned cwc = wcslen( g_awcSystemDir ) + 1 + wcslen( apwcDlls[i] );
|
||
|
|
||
|
if ( cwc >= MAX_PATH )
|
||
|
return 0;
|
||
|
|
||
|
WCHAR filepath[MAX_PATH];
|
||
|
wcscpy(filepath, g_awcSystemDir );
|
||
|
wcscat(filepath, L"\\" );
|
||
|
wcscat(filepath, apwcDlls[i] );
|
||
|
|
||
|
cwcTotal += ( cwc + 1 );
|
||
|
|
||
|
apwc2[i] = new WCHAR[MAX_PATH];
|
||
|
wcscpy(apwc2[i], filepath);
|
||
|
}
|
||
|
|
||
|
WCHAR * apwc2Old[cOldDlls];
|
||
|
|
||
|
// store full old pathnames in array 2
|
||
|
|
||
|
for (i = 0; i < cOldDlls; i++)
|
||
|
{
|
||
|
unsigned cwc = wcslen( g_awcSystemDir ) + 1 + wcslen( apwcOldDlls[i] );
|
||
|
|
||
|
if ( cwc >= MAX_PATH )
|
||
|
return 0;
|
||
|
|
||
|
WCHAR filepath[MAX_PATH];
|
||
|
wcscpy(filepath, g_awcSystemDir );
|
||
|
wcscat(filepath, L"\\" );
|
||
|
wcscat(filepath, apwcOldDlls[i] );
|
||
|
|
||
|
apwc2Old[i] = new WCHAR[MAX_PATH];
|
||
|
wcscpy(apwc2Old[i], filepath);
|
||
|
}
|
||
|
|
||
|
if ( cwcTotal >= 4096 )
|
||
|
return 0;
|
||
|
|
||
|
unsigned cwcRemaining = 4096 - cwcTotal;
|
||
|
|
||
|
WCHAR awc[4096]; //buffer for new list
|
||
|
WCHAR *pwc = awc; //pointer to list
|
||
|
*pwc = 0; //set first slot in array to null
|
||
|
|
||
|
// put our dlls in the beginning
|
||
|
|
||
|
for (int i = 0; i < cDlls; i++)
|
||
|
pwc = AppendMultiSZString(pwc, apwc2[i]);
|
||
|
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE, wcsRegAdminSubKey );
|
||
|
|
||
|
{
|
||
|
WCHAR awcOld[4096]; //the old buffer list of files to register
|
||
|
if ( reg.Get( L"DLLsToRegister",
|
||
|
awcOld,
|
||
|
sizeof awcOld / sizeof WCHAR ) )
|
||
|
{
|
||
|
WCHAR *p = awcOld;
|
||
|
while ( 0 != *p )
|
||
|
{
|
||
|
// Leave dlls not in our list -- 3rd party dlls
|
||
|
|
||
|
BOOL fFound = FALSE;
|
||
|
for ( int i = 0; i < cDlls; i++ )
|
||
|
{
|
||
|
if (!_wcsicmp(p, apwc2[i]) )
|
||
|
{
|
||
|
fFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove old dlls from the list (fsci & cifrmwrk)
|
||
|
|
||
|
if ( !fFound )
|
||
|
{
|
||
|
for ( int i = 0; i < cOldDlls; i++ )
|
||
|
{
|
||
|
if (!_wcsicmp(p, apwc2Old[i]) )
|
||
|
{
|
||
|
fFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fFound)
|
||
|
{
|
||
|
cwcTotal += ( wcslen( p ) + 1 );
|
||
|
|
||
|
if ( cwcTotal >= 4096 )
|
||
|
return 0;
|
||
|
|
||
|
pwc = AppendMultiSZString(pwc, p);
|
||
|
}
|
||
|
|
||
|
p += ( wcslen(p) + 1 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pwc++ = 0;
|
||
|
}
|
||
|
|
||
|
for (int j = 0; j < cDlls; j++)
|
||
|
delete apwc2[j];
|
||
|
|
||
|
for (j = 0; j < cOldDlls; j++)
|
||
|
delete apwc2Old[j];
|
||
|
|
||
|
if ( !reg.SetMultiSZ( L"DLLsToRegister",
|
||
|
awc,
|
||
|
(ULONG)(pwc-awc) * sizeof WCHAR ) )
|
||
|
{
|
||
|
DWORD dw = GetLastError();
|
||
|
ISError( IS_MSG_COULD_NOT_MODIFY_REGISTRY, Err, LogSevFatalError, dw );
|
||
|
return dw;
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
} //SetDLLsToRegister
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AppendMultiSZString
|
||
|
//
|
||
|
// Synopsis: Copies one string to another.
|
||
|
//
|
||
|
// Returns: Pointer to one wchar beyond the end of the copy
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
WCHAR * AppendMultiSZString(
|
||
|
WCHAR * pwcTo,
|
||
|
WCHAR const * pwcFrom )
|
||
|
{
|
||
|
isDebugOut((DEB_TRACE, "language or dll installed: '%ws'\n", pwcFrom ));
|
||
|
|
||
|
unsigned x = wcslen( pwcFrom );
|
||
|
wcscpy( pwcTo, pwcFrom );
|
||
|
return pwcTo + x + 1;
|
||
|
} //AppendMultiSZString
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ExcludeSpecialLocations, private
|
||
|
//
|
||
|
// Synopsis: Writes profile-based exclude scopes into the registry
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// History: 28-Aug-1998 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
WCHAR const wszRegShellSpecialPathsKey[] =
|
||
|
L".DEFAULT\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
|
||
|
|
||
|
WCHAR const * const awszRegShellSpecialPathsValue[] = {
|
||
|
L"AppData",
|
||
|
L"Local Settings"
|
||
|
};
|
||
|
|
||
|
WCHAR const wszUserProfile[] = L"%USERPROFILE%";
|
||
|
|
||
|
void ExcludeSpecialLocations( CCatalogConfig & Cat )
|
||
|
{
|
||
|
//
|
||
|
// First, find the default profile path (Usually %windir%\Profiles)
|
||
|
//
|
||
|
|
||
|
WCHAR wcTemp[MAX_PATH+1];
|
||
|
|
||
|
if ( g_awcProfilePath[0] )
|
||
|
{
|
||
|
WCHAR wcTemp2[MAX_PATH+1];
|
||
|
wcsncpy( wcTemp2, g_awcProfilePath, sizeof wcTemp2 / sizeof WCHAR );
|
||
|
wcTemp2[ (sizeof wcTemp2 / sizeof WCHAR) - 1 ] = 0;
|
||
|
unsigned ccTemp2 = wcslen( wcTemp2 );
|
||
|
|
||
|
//
|
||
|
// Append the wildcard, for user profile directory
|
||
|
//
|
||
|
|
||
|
wcscpy( wcTemp2 + ccTemp2, L"\\*\\" );
|
||
|
ccTemp2 += 3;
|
||
|
|
||
|
//
|
||
|
// Go through and look for special shell paths, which just happen
|
||
|
// to include all our special cases too.
|
||
|
//
|
||
|
|
||
|
CWin32RegAccess regShellSpecialPathsKey( HKEY_USERS, wszRegShellSpecialPathsKey );
|
||
|
|
||
|
for ( unsigned i = 0;
|
||
|
i < NUMELEM(awszRegShellSpecialPathsValue);
|
||
|
i++ )
|
||
|
{
|
||
|
if ( regShellSpecialPathsKey.Get( awszRegShellSpecialPathsValue[i],
|
||
|
wcTemp, NUMELEM(wcTemp), FALSE) )
|
||
|
{
|
||
|
if ( RtlEqualMemory( wszUserProfile, wcTemp,
|
||
|
sizeof(wszUserProfile) - sizeof(WCHAR) ) )
|
||
|
{
|
||
|
wcscpy( wcTemp2 + ccTemp2, wcTemp + NUMELEM(wszUserProfile) );
|
||
|
wcscpy( wcTemp, wcTemp2 );
|
||
|
}
|
||
|
|
||
|
if ( wcschr( wcTemp, L'%' ) != 0 )
|
||
|
{
|
||
|
WCHAR wcTemp3[MAX_PATH+1];
|
||
|
unsigned ccTemp3 = ExpandEnvironmentStrings(
|
||
|
wcTemp,
|
||
|
wcTemp3,
|
||
|
NUMELEM(wcTemp3) );
|
||
|
if ( 0 != ccTemp3 )
|
||
|
wcscpy( wcTemp, wcTemp3 );
|
||
|
}
|
||
|
|
||
|
wcscat( wcTemp, L"\\*" );
|
||
|
isDebugOut(( DEB_TRACE, "Exclude: %ws\n", wcTemp ));
|
||
|
|
||
|
Cat.AddExcludedDirOrPattern( wcTemp );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AddPerfData
|
||
|
//
|
||
|
// Synopsis: Runs unlodctr and lodctr on Index Server perf data
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD AddPerfData(CError &Err)
|
||
|
{
|
||
|
// add counters if installing
|
||
|
|
||
|
DWORD dwError = NO_ERROR;
|
||
|
|
||
|
// remove existing counters (if they exist)
|
||
|
|
||
|
RemovePerfData();
|
||
|
|
||
|
isDebugOut((DEB_TRACE, "Installing perf data\n" ));
|
||
|
|
||
|
dwError = LoadCounterAndDelete( L"perfci.ini", L"perfci.h", Err );
|
||
|
|
||
|
if ( ERROR_SUCCESS == dwError )
|
||
|
{
|
||
|
dwError = LoadCounterAndDelete( L"perffilt.ini", L"perffilt.h", Err );
|
||
|
|
||
|
if ( ERROR_SUCCESS == dwError )
|
||
|
{
|
||
|
dwError = LoadCounterAndDelete( L"perfwci.ini", L"perfwci.h", Err );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NO_ERROR; // Ignore failures return dwError;
|
||
|
} //AddPerfData
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: LoadCounterAndDelete
|
||
|
//
|
||
|
// Synopsis: Loads perf counters for a .ini and a .h, then deletes
|
||
|
// the files. Assumes the files are in system32.
|
||
|
//
|
||
|
// Arguments: [pwcINI] -- Name w/o path of .ini file.
|
||
|
// [pwcH] -- Name w/o path of .h file.
|
||
|
//
|
||
|
// History: 30-Jan-97 dlee Created
|
||
|
// 23-May-97 KyleP Use LoadPerfCounterTextStrings API
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD LoadCounterAndDelete(
|
||
|
WCHAR const * pwcINI,
|
||
|
WCHAR const * pwcH,
|
||
|
CError &Err)
|
||
|
{
|
||
|
unsigned cwc = wcslen( L"lodctr " ) + wcslen( g_awcSystemDir ) + 1 + wcslen( pwcINI );
|
||
|
|
||
|
if ( cwc >= MAX_PATH )
|
||
|
return 0;
|
||
|
|
||
|
WCHAR awc[MAX_PATH];
|
||
|
|
||
|
WCHAR const awcLodctr[] = L"lodctr ";
|
||
|
|
||
|
wcscpy( awc, awcLodctr );
|
||
|
wcscat( awc, g_awcSystemDir );
|
||
|
wcscat( awc, L"\\" );
|
||
|
wcscat( awc, pwcINI );
|
||
|
|
||
|
DWORD dwError = (DWORD)LoadPerfCounterTextStrings( awc, // .INI file
|
||
|
TRUE ); // Quiet mode
|
||
|
|
||
|
if ( ERROR_SUCCESS != dwError )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "Error %d from LoadPerfCounterTextStrings %ws\n", dwError, awc ));
|
||
|
isDebugOut(( "Error %d from LoadPerfCounterTextStrings %ws\n", dwError, awc ));
|
||
|
|
||
|
ISError( IS_MSG_LoadPerfCounterTextStrings_FAILED, Err, LogSevError, dwError );
|
||
|
|
||
|
return dwError;
|
||
|
}
|
||
|
|
||
|
return dwError;
|
||
|
} //LoadCounterAndDelete
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: RemovePerfData
|
||
|
//
|
||
|
// Synopsis: Runs unlodctr and lodctr on Index Server perf data
|
||
|
//
|
||
|
// History: 08-Jan-97 dlee Created
|
||
|
// 23-May-97 KyleP Use UnloadPerfCounterTextStrings API
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD RemovePerfData()
|
||
|
{
|
||
|
// remove existing counters (if they exist )
|
||
|
|
||
|
DWORD dw0 = (DWORD)UnloadPerfCounterTextStrings( L"unlodctr ContentIndex", // Key
|
||
|
TRUE ); // Quiet mode
|
||
|
|
||
|
DWORD dw1 = (DWORD)UnloadPerfCounterTextStrings( L"unlodctr ContentFilter", // Key
|
||
|
TRUE ); // Quiet mode
|
||
|
|
||
|
DWORD dw2 = (DWORD)UnloadPerfCounterTextStrings( L"unlodctr ISAPISearch", // Key
|
||
|
TRUE ); // Quiet mode
|
||
|
|
||
|
if ( NO_ERROR != dw0 )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "RemovePerfData: unlodctr ContentIndex failed with 0x%x\n", dw0));
|
||
|
return dw0;
|
||
|
}
|
||
|
else if ( NO_ERROR != dw1 )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "RemovePerfData: unlodctr ContentFilter failed with 0x%x\n", dw1));
|
||
|
return dw1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( NO_ERROR != dw2 )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "RemovePerfData: unlodctr ISAPISearch failed with 0x%x\n", dw0));
|
||
|
}
|
||
|
return dw2;
|
||
|
}
|
||
|
} //RemovePerfData
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsSufficientMemory
|
||
|
//
|
||
|
// Synopsis: Determines available physical memory
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Returns: TRUE if physical memory > required phys. memory
|
||
|
// FALSE otherwise.
|
||
|
//
|
||
|
// History: 6-27-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL IsSufficientMemory(void)
|
||
|
{
|
||
|
// 32MB RAM.machine, taking into account up to 1M used by the system.
|
||
|
const ULONGLONG MIN_PHYSICAL_MEMORY = 30*ONE_MB;
|
||
|
|
||
|
MEMORYSTATUSEX memoryStatus;
|
||
|
|
||
|
RtlZeroMemory(&memoryStatus, sizeof memoryStatus );
|
||
|
|
||
|
memoryStatus.dwLength = sizeof memoryStatus;
|
||
|
|
||
|
GlobalMemoryStatusEx(&memoryStatus);
|
||
|
|
||
|
return ( MIN_PHYSICAL_MEMORY <= memoryStatus.ullTotalPhys );
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AddCiSvc
|
||
|
//
|
||
|
// Synopsis: Creates the cisvc service
|
||
|
//
|
||
|
// Arguments: [Err] -- The error object to update
|
||
|
//
|
||
|
// Returns: none - throws upon fatal failure
|
||
|
//
|
||
|
// History: 6-29-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void AddCiSvc(CError &Err)
|
||
|
{
|
||
|
DWORD dwLastError = 0;
|
||
|
|
||
|
SC_HANDLE hSC = OpenSCManager( 0, 0, SC_MANAGER_CREATE_SERVICE );
|
||
|
|
||
|
CServiceHandle xhSC(hSC);
|
||
|
|
||
|
if( 0 == hSC )
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
|
||
|
isDebugOut(( DEB_ITRACE, "OpenSCManager() Failed: %x\n", dwLastError ));
|
||
|
|
||
|
THROW( CException(HRESULT_FROM_WIN32(dwLastError)) );
|
||
|
}
|
||
|
|
||
|
WCHAR wszServiceDependencyList[MAX_PATH];
|
||
|
|
||
|
RtlZeroMemory(wszServiceDependencyList, MAX_PATH * sizeof WCHAR );
|
||
|
|
||
|
wcscpy( wszServiceDependencyList, L"RPCSS" );
|
||
|
|
||
|
WCHAR wszServicePath[300];
|
||
|
|
||
|
unsigned cwc = wcslen( g_awcSystemDir ) + wcslen( L"\\cisvc.exe" );
|
||
|
|
||
|
if ( cwc >= ( sizeof wszServicePath / sizeof WCHAR ) )
|
||
|
return;
|
||
|
|
||
|
wcscpy(wszServicePath, g_awcSystemDir );
|
||
|
wcscat(wszServicePath, L"\\cisvc.exe" );
|
||
|
|
||
|
do
|
||
|
{
|
||
|
dwLastError = 0;
|
||
|
|
||
|
CResString strSvcDisplayName(IS_SERVICE_NAME);
|
||
|
|
||
|
SC_HANDLE hNewSC = CreateService( hSC, // handle to SCM database
|
||
|
TEXT("cisvc"), // pointer to name of service to start
|
||
|
strSvcDisplayName.Get(), // pointer to display name
|
||
|
SERVICE_ALL_ACCESS, // type of access to service
|
||
|
SERVICE_WIN32_SHARE_PROCESS, // type of service
|
||
|
g_fCiSvcIsRequested ?
|
||
|
SERVICE_AUTO_START :
|
||
|
SERVICE_DISABLED, // when to start service
|
||
|
SERVICE_ERROR_NORMAL, // severity if service fails to start
|
||
|
wszServicePath,
|
||
|
NULL, // pointer to name of load ordering group
|
||
|
NULL, // pointer to variable to get tag identifier
|
||
|
wszServiceDependencyList, // pointer to array of dependency names
|
||
|
NULL, // pointer to account name of service
|
||
|
NULL // pointer to password for service account
|
||
|
);
|
||
|
|
||
|
CServiceHandle xService( hNewSC );
|
||
|
|
||
|
if ( 0 == hNewSC )
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
|
||
|
if ( ERROR_SERVICE_EXISTS == dwLastError )
|
||
|
dwLastError = RenameCiSvc( hSC, Err );
|
||
|
else if ( ERROR_SERVICE_MARKED_FOR_DELETE != dwLastError )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "CreateService() Failed: %x\n", dwLastError ));
|
||
|
|
||
|
ISError( IS_MSG_CreateService_FAILED, Err, LogSevError, dwLastError );
|
||
|
|
||
|
THROW( CException(HRESULT_FROM_WIN32(dwLastError)) );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xService.Free();
|
||
|
|
||
|
// We added the service, now set the description.
|
||
|
|
||
|
RenameCiSvc( hSC, Err );
|
||
|
}
|
||
|
} while ( ERROR_SERVICE_MARKED_FOR_DELETE == dwLastError );
|
||
|
} //AddCiSvc
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: RenameCiSvc
|
||
|
//
|
||
|
// Synopsis: Renames the cisvc service to "Indexing Service".
|
||
|
//
|
||
|
// History: 05-Sep-1998 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD RenameCiSvc( SC_HANDLE hSC, CError &Err)
|
||
|
{
|
||
|
DWORD dwLastError = 0;
|
||
|
|
||
|
SC_HANDLE hCisvc = OpenService( hSC, L"cisvc", SERVICE_CHANGE_CONFIG );
|
||
|
|
||
|
CServiceHandle xhCisvc( hCisvc );
|
||
|
|
||
|
if( 0 == hCisvc )
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
isDebugOut(( DEB_ERROR, "OpenService(cisvc) Failed: 0x%x\n", dwLastError ));
|
||
|
THROW( CException(HRESULT_FROM_WIN32(dwLastError)) );
|
||
|
}
|
||
|
|
||
|
CResString strSvcDisplayName(IS_SERVICE_NAME);
|
||
|
|
||
|
if ( !ChangeServiceConfig( hCisvc, // handle to service
|
||
|
SERVICE_NO_CHANGE, // type of service
|
||
|
SERVICE_NO_CHANGE, // when to start service
|
||
|
SERVICE_NO_CHANGE, // severity if service fails to start
|
||
|
0, // pointer to service binary file name
|
||
|
0, // pointer to load ordering group name
|
||
|
0, // pointer to variable to get tag identifier
|
||
|
0, // pointer to array of dependency names
|
||
|
0, // pointer to account name of service
|
||
|
0, // pointer to password for service account
|
||
|
strSvcDisplayName.Get() ) ) // pointer to display name);
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
}
|
||
|
|
||
|
SERVICE_DESCRIPTION sd;
|
||
|
CResString strSvcDescription(IS_SERVICE_DESCRIPTION);
|
||
|
sd.lpDescription = (WCHAR *)strSvcDescription.Get();
|
||
|
|
||
|
if ( !ChangeServiceConfig2( hCisvc,
|
||
|
SERVICE_CONFIG_DESCRIPTION,
|
||
|
(LPVOID)&sd
|
||
|
)
|
||
|
)
|
||
|
dwLastError = GetLastError();
|
||
|
|
||
|
return dwLastError;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: StopService
|
||
|
//
|
||
|
// Synopsis: stops service by name
|
||
|
//
|
||
|
// Arguments: pwszServiceName - name of service to stop.
|
||
|
//
|
||
|
// Returns: none - throws upon fatal failure
|
||
|
//
|
||
|
// History: 6-29-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void StopService( WCHAR const * pwszServiceName )
|
||
|
{
|
||
|
DWORD dwLastError = 0;
|
||
|
|
||
|
SC_HANDLE hSC = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
|
||
|
|
||
|
CServiceHandle xhSC(hSC);
|
||
|
|
||
|
if( 0 == hSC )
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
|
||
|
isDebugOut(( DEB_ERROR, "OpenSCManager() Failed: %x\n", dwLastError ));
|
||
|
|
||
|
THROW( CException(HRESULT_FROM_WIN32(dwLastError)) );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// stop cisvc
|
||
|
//
|
||
|
BOOL fStopped = FALSE;
|
||
|
|
||
|
if ( !MyStopService( xhSC, pwszServiceName, fStopped ) && !fStopped )
|
||
|
{
|
||
|
//
|
||
|
// don't throw here
|
||
|
//
|
||
|
isDebugOut(( DEB_ERROR, "Failed to stop cisvc service" ));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: StartService
|
||
|
//
|
||
|
// Synopsis: start service by name
|
||
|
//
|
||
|
// Arguments: pwszServiceName - name of service to stop.
|
||
|
//
|
||
|
// Returns: none
|
||
|
//
|
||
|
// History: 6-29-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void StartService( WCHAR const * pwszServiceName )
|
||
|
{
|
||
|
DWORD dwLastError = 0;
|
||
|
|
||
|
SC_HANDLE hSC = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
|
||
|
|
||
|
CServiceHandle xhSC(hSC);
|
||
|
|
||
|
if( 0 == hSC )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "OpenSCManager() Failed: %x\n", GetLastError() ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// start cisvc
|
||
|
//
|
||
|
MyStartService( xhSC, pwszServiceName );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: MyStartService
|
||
|
//
|
||
|
// Synopsis: Starts a given service
|
||
|
//
|
||
|
// Arguments: xSC -- the service control manager
|
||
|
// pwcService -- name of the service to start
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void MyStartService(
|
||
|
CServiceHandle & xSC,
|
||
|
WCHAR const * pwcService )
|
||
|
{
|
||
|
CServiceHandle xSVC( OpenService( xSC.Get(),
|
||
|
pwcService,
|
||
|
SERVICE_START |
|
||
|
GENERIC_READ | GENERIC_WRITE ) );
|
||
|
if ( 0 != xSVC.Get() )
|
||
|
{
|
||
|
if ( !StartService( xSVC.Get(), 0, 0 ) )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "Failed to start '%ws': %d\n", pwcService, GetLastError() ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} //MyStartService
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsSvcRunning
|
||
|
//
|
||
|
// Synopsis: Determines if a service is running
|
||
|
//
|
||
|
// Arguments: xSC -- the service control manager
|
||
|
//
|
||
|
// Returns: TRUE if the service is running, FALSE otherwise
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL IsSvcRunning( CServiceHandle &x )
|
||
|
{
|
||
|
SERVICE_STATUS svcStatus;
|
||
|
if ( QueryServiceStatus( x.Get(), &svcStatus ) )
|
||
|
return SERVICE_STOP_PENDING == svcStatus.dwCurrentState ||
|
||
|
SERVICE_RUNNING == svcStatus.dwCurrentState ||
|
||
|
SERVICE_PAUSED == svcStatus.dwCurrentState;
|
||
|
|
||
|
return FALSE;
|
||
|
} //IsSvcRunning
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: MyStopService
|
||
|
//
|
||
|
// Synopsis: Stops a given service
|
||
|
//
|
||
|
// Arguments: xSC -- the service control manager
|
||
|
// pwcSVC -- name of the service to stop
|
||
|
//
|
||
|
// Returns: TRUE if the service was stopped
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL MyStopService(
|
||
|
CServiceHandle & xSC,
|
||
|
WCHAR const * pwcSVC,
|
||
|
BOOL & fStopped )
|
||
|
{
|
||
|
fStopped = FALSE;
|
||
|
BOOL fOK = TRUE;
|
||
|
|
||
|
CServiceHandle xSVC( OpenService( xSC.Get(),
|
||
|
pwcSVC,
|
||
|
SERVICE_STOP |
|
||
|
GENERIC_READ | GENERIC_WRITE ) );
|
||
|
if ( 0 != xSVC.Get() )
|
||
|
{
|
||
|
SERVICE_STATUS svcStatus;
|
||
|
if ( IsSvcRunning( xSVC ) )
|
||
|
{
|
||
|
g_fCiSvcWasRunning = TRUE;
|
||
|
|
||
|
if ( ControlService( xSVC.Get(),
|
||
|
SERVICE_CONTROL_STOP,
|
||
|
&svcStatus ) )
|
||
|
{
|
||
|
for ( unsigned i = 0; i < 30 && IsSvcRunning( xSVC ); i++ )
|
||
|
{
|
||
|
isDebugOut(( DEB_ITRACE, "sleeping waiting for service '%ws' to stop\n", pwcSVC ));
|
||
|
Sleep( 1000 );
|
||
|
}
|
||
|
|
||
|
if ( IsSvcRunning( xSVC ) )
|
||
|
{
|
||
|
THROW( CException( E_FAIL ) );
|
||
|
}
|
||
|
|
||
|
isDebugOut(( DEB_TRACE, "stopped service '%ws'\n", pwcSVC ));
|
||
|
fStopped = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD dw = GetLastError();
|
||
|
isDebugOut(( DEB_ERROR, "can't stop service '%ws', error %d\n", pwcSVC, dw ));
|
||
|
|
||
|
// failures other than timeout and out-of-control are ok
|
||
|
|
||
|
if ( ERROR_SERVICE_REQUEST_TIMEOUT == dw ||
|
||
|
ERROR_SERVICE_CANNOT_ACCEPT_CTRL == dw )
|
||
|
fOK = FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fOK;
|
||
|
} //MyStopService
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DeleteService
|
||
|
//
|
||
|
// Synopsis: deletes a service by name
|
||
|
//
|
||
|
// Arguments: pwszServiceName - name of service to delete
|
||
|
//
|
||
|
// Returns: none - throws upon fatal failure
|
||
|
//
|
||
|
// History: 6-29-97 mohamedn created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void DeleteService( WCHAR const * pwszServiceName )
|
||
|
{
|
||
|
DWORD dwLastError = 0;
|
||
|
|
||
|
SC_HANDLE hSC = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
|
||
|
|
||
|
CServiceHandle xhSC(hSC);
|
||
|
|
||
|
if( 0 == hSC )
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
|
||
|
isDebugOut(( DEB_ERROR, "OpenSCManager() Failed: %x\n", dwLastError ));
|
||
|
|
||
|
THROW( CException(HRESULT_FROM_WIN32(dwLastError)) );
|
||
|
}
|
||
|
|
||
|
SC_HANDLE hCiSvc = OpenService( hSC, pwszServiceName, DELETE );
|
||
|
|
||
|
CServiceHandle xhCiSvc( hCiSvc );
|
||
|
|
||
|
if ( 0 == hCiSvc )
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
|
||
|
isDebugOut(( DEB_ERROR, "OpenService(Cisvc for delete) Failed: %x\n", dwLastError ));
|
||
|
|
||
|
}
|
||
|
else if ( !DeleteService(hCiSvc) )
|
||
|
{
|
||
|
dwLastError = GetLastError();
|
||
|
|
||
|
isDebugOut(( DEB_ERROR, "DeleteService(Cisvc) Failed: %x\n", dwLastError ));
|
||
|
|
||
|
THROW( CException(HRESULT_FROM_WIN32(dwLastError)) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ISError
|
||
|
//
|
||
|
// Synopsis: Reports a non-recoverable Index Server Install error
|
||
|
//
|
||
|
// Arguments: id -- resource identifier for the error string
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void ISError( UINT id, CError &Err, LogSeverity Severity, DWORD dwErr )
|
||
|
{
|
||
|
CResString msg( id );
|
||
|
CResString title( IS_MSG_INDEX_SERVER );
|
||
|
|
||
|
Err.Report( Severity, dwErr, msg.Get() );
|
||
|
|
||
|
if ( LogSevFatalError == Severity )
|
||
|
{
|
||
|
isDebugOut(( "ISError, error %#x abort install: '%ws'\n",
|
||
|
dwErr, msg.Get() ));
|
||
|
|
||
|
isDebugOut(( DEB_ERROR, "ISError, error %#x abort install: '%ws'\n",
|
||
|
dwErr, msg.Get() ));
|
||
|
|
||
|
g_fInstallAborted = TRUE;
|
||
|
}
|
||
|
|
||
|
} //ISError
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: Exec
|
||
|
//
|
||
|
// Synopsis: Runs an app and waits for it to complete
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created from cistp.dll code
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void Exec(
|
||
|
WCHAR * pwc )
|
||
|
{
|
||
|
isDebugOut(( "exec: '%ws'\n", pwc ));
|
||
|
|
||
|
STARTUPINFO si;
|
||
|
RtlZeroMemory( &si, sizeof si );
|
||
|
|
||
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
||
|
si.wShowWindow = SW_HIDE;
|
||
|
|
||
|
PROCESS_INFORMATION pi;
|
||
|
|
||
|
if ( CreateProcess( 0, // pointer to name of executable module
|
||
|
pwc, // pointer to command line string
|
||
|
0, // pointer to process security attributes
|
||
|
0, // pointer to thread security attributes
|
||
|
FALSE, // handle inheritance flag
|
||
|
0, // creation flags
|
||
|
0, // pointer to new environment block
|
||
|
0, // pointer to current directory name
|
||
|
&si, // pointer to STARTUPINFO
|
||
|
&pi ) ) // pointer to PROCESS_INFORMATION
|
||
|
{
|
||
|
WaitForSingleObject( pi.hProcess, 0xFFFFFFFF );
|
||
|
}
|
||
|
} //Exec
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: RegisterDll
|
||
|
//
|
||
|
// Synopsis: Calls DllRegisterServer on a given dll
|
||
|
//
|
||
|
// Returns: Win32 error code
|
||
|
//
|
||
|
// History: 21-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD RegisterDll(WCHAR const * pwcDLL, CError &Err )
|
||
|
{
|
||
|
DWORD dwErr = NO_ERROR;
|
||
|
|
||
|
// All Index Server dlls are currently in system32
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
unsigned cwc = wcslen( g_awcSystemDir ) + 1 + wcslen( pwcDLL );
|
||
|
|
||
|
if ( cwc >= MAX_PATH )
|
||
|
return 0;
|
||
|
|
||
|
WCHAR awcPath[ MAX_PATH ];
|
||
|
wcscpy( awcPath, g_awcSystemDir );
|
||
|
wcscat( awcPath, L"\\" );
|
||
|
wcscat( awcPath, pwcDLL );
|
||
|
|
||
|
HINSTANCE hDll = LoadLibraryEx( awcPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
||
|
|
||
|
if( 0 != hDll )
|
||
|
{
|
||
|
SCODE (STDAPICALLTYPE *pfnDllRegisterServer)();
|
||
|
pfnDllRegisterServer = (HRESULT (STDAPICALLTYPE *)())
|
||
|
GetProcAddress(hDll, "DllRegisterServer");
|
||
|
|
||
|
if ( 0 != pfnDllRegisterServer )
|
||
|
{
|
||
|
SCODE sc = (*pfnDllRegisterServer)();
|
||
|
if ( S_OK != sc )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "dllregister server '%ws' failed 0x%x\n",
|
||
|
awcPath, sc));
|
||
|
|
||
|
ISError(IS_MSG_DllRegisterServer_FAILED ,Err, LogSevError, sc );
|
||
|
|
||
|
// no way to map a scode to a win32 error
|
||
|
|
||
|
dwErr = sc; // kylep suggested this would be valuable.
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
dwErr = GetLastError();
|
||
|
|
||
|
FreeLibrary( hDll );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErr = GetLastError();
|
||
|
}
|
||
|
|
||
|
isDebugOut((DEB_TRACE, "result of registering '%ws': %d\n", awcPath, dwErr ));
|
||
|
|
||
|
#ifdef _WIN64
|
||
|
|
||
|
//
|
||
|
// Register the 32 bit version of the DLL
|
||
|
//
|
||
|
|
||
|
WCHAR awcSysWow64[ MAX_PATH ];
|
||
|
|
||
|
cwc = GetSystemWow64Directory( awcSysWow64, sizeof awcSysWow64 / sizeof WCHAR );
|
||
|
|
||
|
if ( 0 == cwc )
|
||
|
return GetLastError();
|
||
|
|
||
|
if ( L'\\' != awcSysWow64[ cwc - 1 ] )
|
||
|
{
|
||
|
awcSysWow64[ cwc++ ] = '\\';
|
||
|
awcSysWow64[ cwc ] = 0;
|
||
|
}
|
||
|
|
||
|
WCHAR awcCmd[ MAX_PATH * 2 ];
|
||
|
|
||
|
wcscpy( awcCmd, awcSysWow64 );
|
||
|
wcscat( awcCmd, L"regsvr32 /s " );
|
||
|
|
||
|
wcscat( awcCmd, awcSysWow64 );
|
||
|
wcscat( awcCmd, pwcDLL );
|
||
|
|
||
|
Exec( awcCmd );
|
||
|
|
||
|
#endif //_WIN64
|
||
|
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
// ignore, since it's probably the new html filter
|
||
|
|
||
|
isDebugOut(( "caught %#x registering '%ws'\n",
|
||
|
e.GetErrorCode(),
|
||
|
pwcDLL ));
|
||
|
}
|
||
|
END_CATCH
|
||
|
|
||
|
return dwErr; // used to return 0 to avoid returning error!
|
||
|
} //RegisterDll
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UnregisterDll
|
||
|
//
|
||
|
// Synopsis: Calls DllUnregisterServer on a given dll
|
||
|
//
|
||
|
// Returns: Win32 error code
|
||
|
//
|
||
|
// History: 21-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD UnregisterDll(
|
||
|
WCHAR const * pwcDLL )
|
||
|
{
|
||
|
UINT uiOld = SetErrorMode( SEM_NOOPENFILEERRORBOX |
|
||
|
SEM_FAILCRITICALERRORS );
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
// All Index Server dlls are currently in system32
|
||
|
|
||
|
unsigned cwc = wcslen( g_awcSystemDir ) + 1 + wcslen( pwcDLL );
|
||
|
|
||
|
if ( cwc >= MAX_PATH )
|
||
|
return 0;
|
||
|
|
||
|
WCHAR awcPath[ MAX_PATH ];
|
||
|
|
||
|
wcscpy( awcPath, g_awcSystemDir );
|
||
|
wcscat( awcPath, L"\\" );
|
||
|
wcscat( awcPath, pwcDLL );
|
||
|
|
||
|
// don't display popups if a dll can't be loaded when trying to
|
||
|
// unregister.
|
||
|
|
||
|
DWORD dwErr = NO_ERROR;
|
||
|
|
||
|
HINSTANCE hDll = LoadLibraryEx( awcPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
||
|
|
||
|
if( 0 != hDll )
|
||
|
{
|
||
|
SCODE (STDAPICALLTYPE *pfnDllUnregisterServer)();
|
||
|
pfnDllUnregisterServer = (HRESULT (STDAPICALLTYPE *)())
|
||
|
GetProcAddress(hDll, "DllUnregisterServer");
|
||
|
|
||
|
if ( 0 != pfnDllUnregisterServer )
|
||
|
{
|
||
|
SCODE sc = (*pfnDllUnregisterServer)();
|
||
|
if ( S_OK != sc )
|
||
|
dwErr = ERROR_INVALID_FUNCTION;
|
||
|
}
|
||
|
else
|
||
|
dwErr = GetLastError();
|
||
|
|
||
|
FreeLibrary( hDll );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErr = GetLastError();
|
||
|
}
|
||
|
|
||
|
isDebugOut((DEB_TRACE, "result of unregistering '%ws': %d\n", awcPath, dwErr ));
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
// ignore, since it's probably the new html filter
|
||
|
}
|
||
|
END_CATCH
|
||
|
|
||
|
SetErrorMode( uiOld );
|
||
|
|
||
|
return 0; // explicitly ignore unregister errors
|
||
|
} //UnregisterDll
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetFilterRegistryInfo
|
||
|
//
|
||
|
// Synopsis: Installs registry info for Index Server filters
|
||
|
//
|
||
|
// Returns: Win32 error code
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
// 7-01-97 mohamedn cleanedup for IS3.0 with NT5.0 setup.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD SetFilterRegistryInfo( BOOL fUnRegister, CError &Err )
|
||
|
{
|
||
|
if ( fUnRegister )
|
||
|
{
|
||
|
// try to unregister old dlls
|
||
|
|
||
|
UnregisterDll( L"query.dll" );
|
||
|
UnregisterDll( L"htmlfilt.dll" );
|
||
|
UnregisterDll( L"nlfilt.dll" );
|
||
|
UnregisterDll( L"sccifilt.dll" );
|
||
|
UnregisterDll( L"ciadmin.dll" );
|
||
|
|
||
|
UnregisterDll( L"cifrmwrk.dll" );
|
||
|
UnregisterDll( L"fsci.dll" );
|
||
|
UnregisterDll( L"OffFilt.dll" );
|
||
|
|
||
|
UnregisterDll( L"ixsso.dll" );
|
||
|
UnregisterDll( L"ciodm.dll" );
|
||
|
UnregisterDll( L"infosoft.dll" );
|
||
|
UnregisterDll( L"mimefilt.dll" );
|
||
|
UnregisterDll( L"LangWrBk.dll" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// call the .dlls to have them registered
|
||
|
|
||
|
for ( unsigned i = 0; i < cDlls; i++ )
|
||
|
{
|
||
|
DWORD dwErr = RegisterDll( apwcDlls[i], Err );
|
||
|
if ( NO_ERROR != dwErr )
|
||
|
{
|
||
|
isDebugOut(( DEB_ERROR, "Failed to register(%ws): error code: %d\n",
|
||
|
apwcDlls[i], dwErr ));
|
||
|
|
||
|
ISError(IS_MSG_DLL_REGISTRATION_FAILED , Err, LogSevError, dwErr );
|
||
|
|
||
|
return dwErr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
} //SetFilterregistryInfo
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetRegBasedOnMachine
|
||
|
//
|
||
|
// Synopsis: Sets Index Server registry tuning paramaters based on the
|
||
|
// capabilities of the machine. Uninstall is .inf-based.
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD SetRegBasedOnMachine(CError &Err)
|
||
|
{
|
||
|
if ( 0 == gSetupInitComponent.ComponentInfHandle )
|
||
|
{
|
||
|
ISError( IS_MSG_INVALID_INF_HANDLE, Err, LogSevError );
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
WCHAR * pwcInf = 0;
|
||
|
BOOL fServer = FALSE;
|
||
|
|
||
|
switch(g_NtType)
|
||
|
{
|
||
|
case PRODUCT_SERVER_STANDALONE:
|
||
|
case PRODUCT_SERVER_PRIMARY:
|
||
|
case PRODUCT_SERVER_SECONDARY:
|
||
|
{
|
||
|
BOOL fLotsOfMem;
|
||
|
DWORD cCpu;
|
||
|
GetMachineInfo( fLotsOfMem, cCpu );
|
||
|
|
||
|
if ( fLotsOfMem )
|
||
|
{
|
||
|
if ( 1 == cCpu )
|
||
|
pwcInf = L"IndexSrv_Large";
|
||
|
else if ( 2 == cCpu )
|
||
|
pwcInf = L"IndexSrv_LargeMP2";
|
||
|
else
|
||
|
pwcInf = L"IndexSrv_LargeMPMany";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( 1 == cCpu )
|
||
|
pwcInf = L"IndexSrv_Small";
|
||
|
else
|
||
|
pwcInf = L"IndexSrv_SmallMP2";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fServer = TRUE;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case PRODUCT_WORKSTATION:
|
||
|
default:
|
||
|
pwcInf = L"IndexSrv_Workstation";
|
||
|
}
|
||
|
|
||
|
if ( !SetupInstallFromInfSection( 0,
|
||
|
gSetupInitComponent.ComponentInfHandle,
|
||
|
pwcInf,
|
||
|
SPINST_REGISTRY,
|
||
|
0, 0, 0, 0, 0, 0, 0 ) )
|
||
|
return GetLastError();
|
||
|
|
||
|
// If a server, allow catalogs key to be read-only visible
|
||
|
// to the world. See KB Q155363
|
||
|
|
||
|
// Note: In Win2k, the professional version requires this as well,
|
||
|
// so I commented out the fServer check.
|
||
|
|
||
|
// if ( fServer )
|
||
|
|
||
|
{
|
||
|
CWin32RegAccess regAllowed( HKEY_LOCAL_MACHINE, wcsAllowedPaths );
|
||
|
WCHAR awcValue[ 8192 ];
|
||
|
|
||
|
if ( regAllowed.Get( L"Machine",
|
||
|
awcValue,
|
||
|
sizeof awcValue / sizeof WCHAR ) )
|
||
|
{
|
||
|
// don't re-add it if it already exists
|
||
|
|
||
|
BOOL fFound = FALSE;
|
||
|
WCHAR *p = awcValue;
|
||
|
while ( 0 != *p )
|
||
|
{
|
||
|
if ( !_wcsicmp( p, wcsRegAdminSubKey ) )
|
||
|
{
|
||
|
fFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
while ( 0 != *p )
|
||
|
p++;
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
if ( !fFound )
|
||
|
{
|
||
|
wcscpy( p, wcsRegAdminSubKey );
|
||
|
p += ( 1 + wcslen( wcsRegAdminSubKey ) );
|
||
|
*p++ = 0;
|
||
|
|
||
|
if ( !regAllowed.SetMultiSZ( L"Machine",
|
||
|
awcValue,
|
||
|
(ULONG)(p-awcValue) * sizeof WCHAR ) )
|
||
|
{
|
||
|
DWORD dw = GetLastError();
|
||
|
ISError( IS_MSG_COULD_NOT_MODIFY_REGISTRY, Err, LogSevFatalError, dw );
|
||
|
return dw;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
} //SetRegBasedOnMachine
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetRegBasedOnArchitecture
|
||
|
//
|
||
|
// Synopsis: Sets Index Server registry tuning paramaters based on the
|
||
|
// architecture. Uninstall is .inf-based.
|
||
|
//
|
||
|
// History: 24-Feb-98 KrishnaN Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DWORD SetRegBasedOnArchitecture(CError &Err)
|
||
|
{
|
||
|
if ( 0 == gSetupInitComponent.ComponentInfHandle )
|
||
|
{
|
||
|
Err.Report(LogSevError,0,L"Couldn't set registry based on architecture, Invalid Inf Handle");
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
WCHAR * pwcInf = 0;
|
||
|
|
||
|
#if defined (_X86_)
|
||
|
pwcInf = L"IndexSrv_X86";
|
||
|
#else
|
||
|
pwcInf = L"IndexSrv_RISC";
|
||
|
#endif
|
||
|
|
||
|
if ( !SetupInstallFromInfSection( 0,
|
||
|
gSetupInitComponent.ComponentInfHandle,
|
||
|
pwcInf,
|
||
|
SPINST_REGISTRY,
|
||
|
0, 0, 0, 0, 0, 0, 0 ) )
|
||
|
return GetLastError();
|
||
|
|
||
|
return NO_ERROR;
|
||
|
} //SetRegBasedOnArchitecture
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetMachineInfo
|
||
|
//
|
||
|
// Synopsis: Retrieves stats about the machine
|
||
|
//
|
||
|
// Arguments: fLotsOfMem -- returns TRUE if the machine has "lots" of mem
|
||
|
// cCPU -- returns a count of CPUs
|
||
|
//
|
||
|
// History: 8-Jan-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void GetMachineInfo(
|
||
|
BOOL & fLotsOfMem,
|
||
|
DWORD & cCPU )
|
||
|
{
|
||
|
SYSTEM_INFO si;
|
||
|
GetSystemInfo( &si );
|
||
|
cCPU = si.dwNumberOfProcessors;
|
||
|
|
||
|
MEMORYSTATUSEX memStatus;
|
||
|
memStatus.dwLength = sizeof( memStatus );
|
||
|
GlobalMemoryStatusEx( &memStatus );
|
||
|
fLotsOfMem = ( memStatus.ullTotalPhys >= 64000000 );
|
||
|
} //GetMachineInfo
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: isLogString
|
||
|
//
|
||
|
// Synopsis: Logs the string to %windir%\setupqry.log
|
||
|
//
|
||
|
// Arguments: pc -- ansi string
|
||
|
//
|
||
|
// History: 11-Nov-98 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL g_fCalledYet = FALSE;
|
||
|
|
||
|
void isLogString( const char * pc )
|
||
|
{
|
||
|
WCHAR awc[ MAX_PATH ];
|
||
|
UINT ui = GetWindowsDirectory( awc, sizeof awc / sizeof WCHAR );
|
||
|
|
||
|
if ( 0 == ui )
|
||
|
return;
|
||
|
|
||
|
wcscat( awc, L"\\setupqry.log" );
|
||
|
|
||
|
WCHAR const * pwcOpen = L"a";
|
||
|
|
||
|
if ( !g_fCalledYet )
|
||
|
{
|
||
|
g_fCalledYet = TRUE;
|
||
|
pwcOpen = L"w";
|
||
|
}
|
||
|
|
||
|
FILE *fp = _wfopen( awc, pwcOpen );
|
||
|
|
||
|
if ( 0 != fp )
|
||
|
{
|
||
|
fprintf( fp, "%s", pc );
|
||
|
fclose( fp );
|
||
|
}
|
||
|
} //isLogString
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SystemExceptionTranslator
|
||
|
//
|
||
|
// Synopsis: Translates system exceptions into C++ exceptions
|
||
|
//
|
||
|
// History: 1-Dec-98 dlee Copied from query.dll's version
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void _cdecl SystemExceptionTranslator(
|
||
|
unsigned int uiWhat,
|
||
|
struct _EXCEPTION_POINTERS * pexcept )
|
||
|
{
|
||
|
throw CException( uiWhat );
|
||
|
} //SystemExceptionTranslator
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DeleteNTOPStartMenu
|
||
|
//
|
||
|
// Synopsis: Deletes start menu items created by IS in the NTOP
|
||
|
//
|
||
|
// History: 6-Jan-99 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void DeleteNTOPStartMenu()
|
||
|
{
|
||
|
//
|
||
|
// Ignore all failures here -- it's ok if the link don't exist
|
||
|
//
|
||
|
|
||
|
CWin32RegAccess reg( HKEY_LOCAL_MACHINE,
|
||
|
L"software\\microsoft\\windows\\currentversion\\explorer\\shell folders" );
|
||
|
|
||
|
WCHAR awc[MAX_PATH];
|
||
|
|
||
|
if ( reg.Get( L"common programs",
|
||
|
awc,
|
||
|
MAX_PATH ) )
|
||
|
{
|
||
|
//
|
||
|
// Build the directory where the links are located
|
||
|
//
|
||
|
|
||
|
wcscat( awc, L"\\" );
|
||
|
|
||
|
CResString strNTOP( IS_MSG_NTOP );
|
||
|
wcscat( awc, strNTOP.Get() );
|
||
|
|
||
|
wcscat( awc, L"\\" );
|
||
|
|
||
|
CResString strMIS( IS_MSG_START_MENU_NAME );
|
||
|
wcscat( awc, strMIS.Get() );
|
||
|
|
||
|
isDebugOut(( "NTOP start menu location: '%ws'\n", awc ));
|
||
|
|
||
|
//
|
||
|
// Delete the links
|
||
|
//
|
||
|
|
||
|
CResString strSample( IS_MSG_LINK_SAMPLE_NAME );
|
||
|
DeleteShellLink( awc, strSample.Get() );
|
||
|
isDebugOut(( "deleting NTOP item '%ws'\n", strSample.Get() ));
|
||
|
|
||
|
CResString strAdmin( IS_MSG_LINK_ADMIN_NAME );
|
||
|
DeleteShellLink( awc, strAdmin.Get() );
|
||
|
isDebugOut(( "deleting NTOP item '%ws'\n", strAdmin.Get() ));
|
||
|
|
||
|
CResString strMMC( IS_MSG_LINK_MMC_NAME );
|
||
|
DeleteShellLink( awc, strMMC.Get() );
|
||
|
isDebugOut(( "deleting NTOP item '%ws'\n", strMMC.Get() ));
|
||
|
|
||
|
//
|
||
|
// Note: when the last item is deleted, DeleteShellLink deletes
|
||
|
// the directory
|
||
|
//
|
||
|
}
|
||
|
} //DeleteNTOPStartMenu
|
||
|
|