WindowsXP-SP1/termsrv/setup/dll/hydraoc.cpp
2020-09-30 16:53:49 +02:00

1438 lines
47 KiB
C++

//Copyright (c) 1998 - 1999 Microsoft Corporation
/*--------------------------------------------------------------------------------------------------------
*
* Module Name:
*
* hydraoc.cpp
*
* Abstract:
*
* This file implements the optional component HydraOc for Terminal Server Installations.
*
*
* Author:
*
* Makarand Patwardhan - March 6, 1998
*
* Environment:
*
* User Mode
* -------------------------------------------------------------------------------------------------------*/
#include "stdafx.h"
#include "hydraoc.h"
#include "pages.h"
#include "subtoggle.h"
#include "subcore.h"
#include "ocmanage.h"
#define INITGUID // must be before iadmw.h
#include "iadmw.h" // Interface header
#include "iiscnfg.h" // MD_ & IIS_MD_ defines
#define REASONABLE_TIMEOUT 1000
#define TRANS_ADD 0
#define TRANS_DEL 1
#define TRANS_PRINT_PATH 2
#define STRING_TS_WEBCLIENT_INSTALL _T("TSWebClient.Install")
#define STRING_TS_WEBCLIENT_UNINSTALL _T("TSWebClient.UnInstall")
#define STRING_TS_WEBCLIENT _T("TSWebClient")
#define STRING_TS_WEBCLIENT_DIR _T("\\web\\tsweb")
/*--------------------------------------------------------------------------------------------------------
* declarations.
* -------------------------------------------------------------------------------------------------------*/
//
// component manager message handlers.
//
DWORD OnPreinitialize ();
DWORD OnInitComponent (PSETUP_INIT_COMPONENT psc);
DWORD OnExtraRoutines (PEXTRA_ROUTINES pExtraRoutines);
DWORD OnSetLanguage ();
DWORD OnQueryImage ();
DWORD OnSetupRequestPages (WizardPagesType ePageType, SETUP_REQUEST_PAGES *pRequestPages);
DWORD OnQuerySelStateChange (LPCTSTR SubcomponentId, UINT SelectionState, LONG Flag);
DWORD OnCalcDiskSpace (LPCTSTR SubcomponentId, DWORD addComponent, HDSKSPC dspace);
DWORD OnQueueFileOps (LPCTSTR SubcomponentId, HSPFILEQ queue);
DWORD OnNotificationFromQueue ();
DWORD OnQueryStepCount (LPCTSTR SubComponentId);
DWORD OnCompleteInstallation (LPCTSTR SubcomponentId);
DWORD OnCleanup ();
DWORD OnQueryState (LPCTSTR SubComponentId, UINT whichstate);
DWORD OnNeedMedia ();
DWORD OnAboutToCommitQueue (LPCTSTR SubcomponentId);
DWORD OnQuerySkipPage ();
DWORD OnWizardCreated ();
DWORD_PTR WebClientSetup (LPCTSTR, LPCTSTR, UINT, UINT_PTR, PVOID);
//
// private utility functions.
//
BOOL OpenMetabaseAndDoStuff(WCHAR *wszVDir, WCHAR *wszDir, int iTrans);
BOOL GetVdirPhysicalPath(IMSAdminBase *pIMSAdminBase,WCHAR * wszVDir,WCHAR *wszStringPathToFill);
BOOL AddVirtualDir(IMSAdminBase *pIMSAdminBase, WCHAR *wszVDir, WCHAR *wszDir);
BOOL RemoveVirtualDir(IMSAdminBase *pIMSAdminBase, WCHAR *wszVDir);
INT CheckifServiceExist(LPCTSTR lpServiceName);
/*--------------------------------------------------------------------------------------------------------
* defines
* -------------------------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------------
* constants
-------------------------------------------------------------------------------------------------------*/
//
// global variables and functions to access them.
//
SubCompToggle *gpSubCompToggle = NULL;
SubCompCoreTS *gpSubCompCoreTS = NULL;
COCPageData *gpAppSrvUninstallPageData = NULL;
DefSecPageData *gpSecPageData = NULL;
COCPageData *gpPermPageData = NULL;
COCPageData *gpAppPageData = NULL;
/*--------------------------------------------------------------------------------------------------------
* LPCTSTR GetOCFunctionName(UINT uiFunction)
* utility function for logging the oc messages.
* returns oc manager function name from funciton id.
* returns _T("Unknown Function") if its unknown.
* -------------------------------------------------------------------------------------------------------*/
LPCTSTR GetOCFunctionName(UINT uiFunction)
{
struct
{
UINT msg;
TCHAR *desc;
} gMsgs[] =
{
{OC_PREINITIALIZE, TEXT("OC_PREINITIALIZE")},
{OC_INIT_COMPONENT, TEXT("OC_INIT_COMPONENT")},
{OC_SET_LANGUAGE, TEXT("OC_SET_LANGUAGE")},
{OC_QUERY_IMAGE, TEXT("OC_QUERY_IMAGE")},
{OC_REQUEST_PAGES, TEXT("OC_REQUEST_PAGES")},
{OC_QUERY_CHANGE_SEL_STATE, TEXT("OC_QUERY_CHANGE_SEL_STATE")},
{OC_CALC_DISK_SPACE, TEXT("OC_CALC_DISK_SPACE")},
{OC_QUEUE_FILE_OPS, TEXT("OC_QUEUE_FILE_OPS")},
{OC_NOTIFICATION_FROM_QUEUE,TEXT("OC_NOTIFICATION_FROM_QUEUE")},
{OC_QUERY_STEP_COUNT, TEXT("OC_QUERY_STEP_COUNT")},
{OC_COMPLETE_INSTALLATION, TEXT("OC_COMPLETE_INSTALLATION")},
{OC_CLEANUP, TEXT("OC_CLEANUP")},
{OC_QUERY_STATE, TEXT("OC_QUERY_STATE")},
{OC_NEED_MEDIA, TEXT("OC_NEED_MEDIA")},
{OC_ABOUT_TO_COMMIT_QUEUE, TEXT("OC_ABOUT_TO_COMMIT_QUEUE")},
{OC_QUERY_SKIP_PAGE, TEXT("OC_QUERY_SKIP_PAGE")},
{OC_WIZARD_CREATED, TEXT("OC_WIZARD_CREATED")},
{OC_EXTRA_ROUTINES, TEXT("OC_EXTRA_ROUTINES")}
};
for (int i = 0; i < sizeof(gMsgs) / sizeof(gMsgs[0]); i++)
{
if (gMsgs[i].msg == uiFunction)
return gMsgs[i].desc;
}
return _T("Unknown Function");
}
/*--------------------------------------------------------------------------------------------------------
* called by CRT when _DllMainCRTStartup is the DLL entry point
* -------------------------------------------------------------------------------------------------------*/
BOOL WINAPI DllMain(IN HINSTANCE hinstance, IN DWORD reason, IN LPVOID /*reserved*/ )
{
SetInstance( hinstance );
switch(reason)
{
case DLL_PROCESS_ATTACH:
TCHAR szLogFile[MAX_PATH];
ExpandEnvironmentStrings(LOGFILE, szLogFile, MAX_PATH);
LOGMESSAGEINIT(szLogFile, MODULENAME);
break;
case DLL_THREAD_ATTACH:
case DLL_PROCESS_DETACH:
case DLL_THREAD_DETACH:
break;
}
return(TRUE); // for successful process_attach
}
/*--------------------------------------------------------------------------------------------------------
* This is our export function which will be called by OC Manager
* -------------------------------------------------------------------------------------------------------*/
DWORD_PTR HydraOc(
IN LPCTSTR ComponentId,
IN LPCTSTR SubcomponentId,
IN UINT Function,
IN UINT_PTR Param1,
IN OUT PVOID Param2
)
{
// we use this variable to track if we receive OnCompleteInstallation or not.
// there is a problem with ocm which aborts all the components if any of them
// does something wrong with file queue.
static BOOL sbGotCompleteMessage = FALSE;
LOGMESSAGE1(_T("Entering %s"), GetOCFunctionName(Function));
LOGMESSAGE2(_T("Component=%s, SubComponent=%s"), ComponentId, SubcomponentId);
DWORD_PTR rc;
if (SubcomponentId && _tcsicmp(SubcomponentId, _T("tswebClient")) == 0)
{
rc = WebClientSetup(ComponentId, SubcomponentId, Function, Param1, Param2);
LOGMESSAGE2(_T("%s Done. Returning %lu\r\n\r\n"), GetOCFunctionName(Function), rc);
return rc;
}
// since we are supporting only one component.
ASSERT(_tcsicmp(APPSRV_COMPONENT_NAME, ComponentId) == 0);
switch(Function)
{
case OC_PREINITIALIZE:
rc = OnPreinitialize();
break;
case OC_INIT_COMPONENT:
rc = OnInitComponent((PSETUP_INIT_COMPONENT)Param2);
break;
case OC_EXTRA_ROUTINES:
rc = OnExtraRoutines((PEXTRA_ROUTINES)Param2);
break;
case OC_SET_LANGUAGE:
rc = OnSetLanguage();
break;
case OC_QUERY_IMAGE:
rc = OnQueryImage();
break;
case OC_REQUEST_PAGES:
rc = OnSetupRequestPages(WizardPagesType(Param1), PSETUP_REQUEST_PAGES (Param2));
break;
case OC_QUERY_CHANGE_SEL_STATE:
rc = OnQuerySelStateChange(SubcomponentId, (UINT)Param1, LONG(ULONG_PTR(Param2)));
break;
case OC_CALC_DISK_SPACE:
rc = OnCalcDiskSpace(SubcomponentId, (DWORD)Param1, Param2);
break;
case OC_QUEUE_FILE_OPS:
rc = OnQueueFileOps(SubcomponentId, (HSPFILEQ)Param2);
break;
case OC_NOTIFICATION_FROM_QUEUE:
rc = OnNotificationFromQueue();
break;
case OC_QUERY_STEP_COUNT:
rc = OnQueryStepCount(SubcomponentId);
break;
case OC_COMPLETE_INSTALLATION:
sbGotCompleteMessage = TRUE;
rc = OnCompleteInstallation(SubcomponentId);
break;
case OC_CLEANUP:
rc = OnCleanup();
if (!sbGotCompleteMessage)
{
if (StateObject.IsStandAlone())
{
LOGMESSAGE0(_T("Error:StandAlone:TSOC Did not get OC_COMPLETE_INSTALLATION."));
}
else
{
LOGMESSAGE0(_T("Error:TSOC Did not get OC_COMPLETE_INSTALLATION."));
}
}
break;
case OC_QUERY_STATE:
rc = OnQueryState(SubcomponentId, (UINT)Param1);
break;
case OC_NEED_MEDIA:
rc = OnNeedMedia();
break;
case OC_ABOUT_TO_COMMIT_QUEUE:
rc = OnAboutToCommitQueue(SubcomponentId);
break;
case OC_QUERY_SKIP_PAGE:
rc = OnQuerySkipPage();
break;
case OC_WIZARD_CREATED:
rc = OnWizardCreated();
break;
default:
rc = 0; // it means we do not recognize this command.
break;
}
LOGMESSAGE2(_T("%s Done. Returning %lu\r\n\r\n"), GetOCFunctionName(Function), rc);
return rc;
}
/*--------------------------------------------------------------------------------------------------------
* OC Manager message handlers
* -------------------------------------------------------------------------------------------------------*/
DWORD OnPreinitialize(VOID)
{
#ifdef ANSI
return OCFLAG_ANSI;
#else
return OCFLAG_UNICODE;
#endif
}
/*--------------------------------------------------------------------------------------------------------
* OnInitComponent()
*
* handler for OC_INIT_COMPONENT
* -------------------------------------------------------------------------------------------------------*/
DWORD OnInitComponent(PSETUP_INIT_COMPONENT psc)
{
ASSERT(psc);
//
// let the ocmanager know our version
//
psc->ComponentVersion = COMPONENT_VERSION;
//
// Is this component written for newer version than the oc manager ?
//
if (COMPONENT_VERSION > psc->OCManagerVersion)
{
LOGMESSAGE2(_T("ERROR:OnInitComponent: COMPONENT_VERSION(%x) > psc->OCManagerVersion(%x)"), COMPONENT_VERSION, psc->OCManagerVersion);
return ERROR_CALL_NOT_IMPLEMENTED;
}
if (!StateObject.Initialize(psc))
{
return ERROR_CANCELLED; // due to ERROR_OUTOFMEMORY;
}
// if its standalone (!guimode) setup, We must have Hydra in product suite by now.
// ASSERT( StateObject.IsGuiModeSetup() || DoesHydraKeysExists() );
//
// now create our subcomponents
//
gpSubCompToggle = new SubCompToggle;
gpSubCompCoreTS = new SubCompCoreTS;
if (!gpSubCompToggle || !gpSubCompCoreTS)
return ERROR_CANCELLED;
//
// if initialization of any of the sub component fails
// fail the setup
//
if (!gpSubCompToggle->Initialize() ||
!gpSubCompCoreTS->Initialize())
return ERROR_CANCELLED;
return NO_ERROR;
}
DWORD
OnExtraRoutines(
PEXTRA_ROUTINES pExtraRoutines
)
{
ASSERT(pExtraRoutines);
return(SetExtraRoutines(pExtraRoutines) ? ERROR_SUCCESS : ERROR_CANCELLED);
}
/*--------------------------------------------------------------------------------------------------------
* OnCalcDiskSpace()
*
* handler for OC_ON_CALC_DISK_SPACE
* -------------------------------------------------------------------------------------------------------*/
DWORD OnCalcDiskSpace(
LPCTSTR /* SubcomponentId */,
DWORD addComponent,
HDSKSPC dspace
)
{
return gpSubCompCoreTS->OnCalcDiskSpace(addComponent, dspace);
}
/*--------------------------------------------------------------------------------------------------------
* OnQueueFileOps()
*
* handler for OC_QUEUE_FILE_OPS
* -------------------------------------------------------------------------------------------------------*/
DWORD OnQueueFileOps(LPCTSTR SubcomponentId, HSPFILEQ queue)
{
if (SubcomponentId == NULL)
{
return gpSubCompCoreTS->OnQueueFiles( queue );
}
else if (_tcsicmp(SubcomponentId, APPSRV_COMPONENT_NAME) == 0)
{
return gpSubCompToggle->OnQueueFiles( queue );
}
else
{
ASSERT(FALSE);
LOGMESSAGE1(_T("ERROR, Got a OnQueueFileOps with unknown SubComp(%s)"), SubcomponentId);
return 0;
}
}
/*--------------------------------------------------------------------------------------------------------
* OnCompleteInstallation
*
* handler for OC_COMPLETE_INSTALLATION
* -------------------------------------------------------------------------------------------------------*/
DWORD OnCompleteInstallation(LPCTSTR SubcomponentId)
{
static BOOL sbStateUpdated = FALSE;
if (!sbStateUpdated)
{
StateObject.UpdateState();
sbStateUpdated = TRUE;
}
if (SubcomponentId == NULL)
{
return gpSubCompCoreTS->OnCompleteInstall();
}
else if (_tcsicmp(SubcomponentId, APPSRV_COMPONENT_NAME) == 0)
{
return gpSubCompToggle->OnCompleteInstall();
}
else
{
ASSERT(FALSE);
LOGMESSAGE1(_T("ERROR, Got a Complete Installation with unknown SubComp(%s)"), SubcomponentId);
return 0;
}
}
/*--------------------------------------------------------------------------------------------------------
* OnSetLanguage()
*
* handler for OC_SET_LANGUAGE
* -------------------------------------------------------------------------------------------------------*/
DWORD OnSetLanguage()
{
return false;
}
/*--------------------------------------------------------------------------------------------------------
* OnSetLanguage()
*
* handler for OC_SET_LANGUAGE
* -------------------------------------------------------------------------------------------------------*/
DWORD OnQueryImage()
{
return NULL;
}
/*--------------------------------------------------------------------------------------------------------
* OnSetupRequestPages
*
* Prepares wizard pages and returns them to the OC Manager
* -------------------------------------------------------------------------------------------------------*/
DWORD OnSetupRequestPages (WizardPagesType ePageType, SETUP_REQUEST_PAGES *pRequestPages)
{
if (ePageType == WizPagesEarly)
{
ASSERT(pRequestPages);
const UINT uiPages = 4;
// if we are provided sufficient space for our pages
if (pRequestPages->MaxPages >= uiPages )
{
//
// Pages will be deleted in PSPCB_RELEASE in OCPage::PropSheetPageProc
//
gpAppPageData = new COCPageData;
AppSrvWarningPage *pAppSrvWarnPage = new AppSrvWarningPage(gpAppPageData);
gpSecPageData = new DefSecPageData;
DefaultSecurityPage *pSecPage = new DefaultSecurityPage(gpSecPageData);
gpPermPageData = new COCPageData;
PermPage *pPermPage = new PermPage(gpPermPageData);
gpAppSrvUninstallPageData = new COCPageData;
AppSrvUninstallpage *pAppSrvUninstallPage = new AppSrvUninstallpage(gpAppSrvUninstallPageData);
if (pAppSrvWarnPage && pAppSrvWarnPage->Initialize() &&
pSecPage && pSecPage->Initialize() &&
pPermPage && pPermPage->Initialize() &&
pAppSrvUninstallPage && pAppSrvUninstallPage->Initialize()
)
{
ASSERT(pRequestPages->Pages);
pRequestPages->Pages[0] = CreatePropertySheetPage((PROPSHEETPAGE *) pAppSrvWarnPage);
pRequestPages->Pages[1] = CreatePropertySheetPage((PROPSHEETPAGE *) pSecPage);
pRequestPages->Pages[2] = CreatePropertySheetPage((PROPSHEETPAGE *) pPermPage);
pRequestPages->Pages[3] = CreatePropertySheetPage((PROPSHEETPAGE *) pAppSrvUninstallPage);
ASSERT(pRequestPages->Pages[0]);
ASSERT(pRequestPages->Pages[1]);
ASSERT(pRequestPages->Pages[2]);
ASSERT(pRequestPages->Pages[3]);
}
else
{
//
// failed to allocate memory
//
if (gpAppPageData)
delete gpAppPageData;
gpAppPageData = NULL;
if (pAppSrvWarnPage)
delete pAppSrvWarnPage;
pAppSrvWarnPage = NULL;
if (gpSecPageData)
delete gpSecPageData;
gpSecPageData = NULL;
if (pSecPage)
delete pSecPage;
pSecPage = NULL;
if (gpPermPageData)
delete gpPermPageData;
gpPermPageData = NULL;
if (pPermPage)
delete pPermPage;
pPermPage =NULL;
if (gpAppSrvUninstallPageData)
delete gpAppSrvUninstallPageData;
gpAppSrvUninstallPageData = NULL;
if (pAppSrvUninstallPage)
delete pAppSrvUninstallPage;
pAppSrvUninstallPage = NULL;
SetLastError(ERROR_OUTOFMEMORY);
return DWORD(-1);
}
}
return uiPages;
}
return 0;
}
/*--------------------------------------------------------------------------------------------------------
* OnWizardCreated()
* -------------------------------------------------------------------------------------------------------*/
DWORD OnWizardCreated()
{
return NO_ERROR;
}
/*--------------------------------------------------------------------------------------------------------
* OnQuerySkipPage()
*
* don't let the user deselect the sam component
* -------------------------------------------------------------------------------------------------------*/
DWORD OnQuerySkipPage()
{
return false;
}
/*--------------------------------------------------------------------------------------------------------
* OnQuerySelStateChange(LPCTSTR SubcomponentId, UINT SelectionState, LONG Flag);
*
* informs that user has changed the state of the component/subcomponent and asks approval
* -------------------------------------------------------------------------------------------------------*/
DWORD OnQuerySelStateChange(LPCTSTR SubcomponentId, UINT SelectionState, LONG Flag)
{
BOOL bNewState = SelectionState;
BOOL bDirectSelection = Flag & OCQ_ACTUAL_SELECTION;
LOGMESSAGE3(_T("OnQuerySelStateChange for %s, NewState = %d, DirectSelect = %s"), SubcomponentId, SelectionState, bDirectSelection ? _T("True") : _T("False"));
return gpSubCompToggle->OnQuerySelStateChange(bNewState, bDirectSelection);
}
/*--------------------------------------------------------------------------------------------------------
* OnCleanup()
*
* handler for OC_CLEANUP
* -------------------------------------------------------------------------------------------------------*/
DWORD OnCleanup()
{
if (gpAppPageData)
delete gpAppPageData;
if (gpSecPageData)
delete gpSecPageData;
if (gpPermPageData)
delete gpPermPageData;
if (gpAppSrvUninstallPageData)
delete gpAppSrvUninstallPageData;
if (gpSubCompToggle)
delete gpSubCompToggle;
if (gpSubCompCoreTS)
delete gpSubCompCoreTS;
// DestroySetupData();
DestroyExtraRoutines();
return NO_ERROR;
}
/*--------------------------------------------------------------------------------------------------------
* OnQueryState()
*
* handler for OC_QUERY_STATE
* -------------------------------------------------------------------------------------------------------*/
DWORD OnQueryState(LPCTSTR SubComponentId, UINT whichstate)
{
ASSERT(OCSELSTATETYPE_ORIGINAL == whichstate ||
OCSELSTATETYPE_CURRENT == whichstate ||
OCSELSTATETYPE_FINAL == whichstate);
TCHAR szState[256];
switch (whichstate)
{
case OCSELSTATETYPE_ORIGINAL:
_tcscpy(szState, _T("Original"));
break;
case OCSELSTATETYPE_CURRENT:
_tcscpy(szState, _T("Current"));
break;
case OCSELSTATETYPE_FINAL:
_tcscpy(szState, _T("Final"));
break;
default:
ASSERT(FALSE);
return ERROR_BAD_ARGUMENTS;
}
DWORD dwReturn = gpSubCompToggle->OnQueryState(whichstate);
TCHAR szReturn[] = _T("SubcompUseOcManagerUknownState");
switch (dwReturn)
{
case SubcompOn:
_tcscpy(szReturn, _T("SubcompOn"));
break;
case SubcompUseOcManagerDefault:
_tcscpy(szReturn, _T("SubcompUseOcManagerDefault"));
break;
case SubcompOff:
_tcscpy(szReturn, _T("SubcompOff"));
break;
default:
ASSERT(FALSE);
}
LOGMESSAGE3(_T("Query State Asked For %s, %s. Returning %s"), SubComponentId, szState, szReturn);
return dwReturn;
}
/*--------------------------------------------------------------------------------------------------------
* OnNotificationFromQueue()
*
* handler for OC_NOTIFICATION_FROM_QUEUE
*
* NOTE: although this notification is defined,
* it is currently unimplemented in oc manager
* -------------------------------------------------------------------------------------------------------*/
DWORD OnNotificationFromQueue()
{
return NO_ERROR;
}
/*--------------------------------------------------------------------------------------------------------
* OnQueryStepCount
*
* handler for OC_QUERY_STEP_COUNT
* -------------------------------------------------------------------------------------------------------*/
DWORD OnQueryStepCount(LPCTSTR /* SubcomponentId */)
{
//
// now return the ticks for the component
//
return gpSubCompCoreTS->OnQueryStepCount() + gpSubCompToggle->OnQueryStepCount();
}
/*--------------------------------------------------------------------------------------------------------
* OnNeedMedia()
*
* handler for OC_NEED_MEDIA
* -------------------------------------------------------------------------------------------------------*/
DWORD OnNeedMedia()
{
return false;
}
/*--------------------------------------------------------------------------------------------------------
* OnAboutToCommitQueue()
*
* handler for OC_ABOUT_TO_COMMIT_QUEUE
* -------------------------------------------------------------------------------------------------------*/
DWORD OnAboutToCommitQueue(LPCTSTR /* SubcomponentId */)
{
return NO_ERROR;
}
/*--------------------------------------------------------------------------------------------------------
* BOOL DoesHydraKeysExists()
*
* checks if Teminal server string exists in the product suite key.
* -------------------------------------------------------------------------------------------------------*/
BOOL DoesHydraKeysExists()
{
BOOL bStringExists = FALSE;
DWORD dw = IsStringInMultiString(
HKEY_LOCAL_MACHINE,
PRODUCT_SUITE_KEY,
PRODUCT_SUITE_VALUE,
TS_PRODUCT_SUITE_STRING,
&bStringExists);
return (dw == ERROR_SUCCESS) && bStringExists;
}
/*--------------------------------------------------------------------------------------------------------
* DWORD IsStringInMultiString(HKEY hkey, LPCTSTR szkey, LPCTSTR szvalue, LPCTSTR szCheckForString, BOOL *pbFound)
* checks if parameter string exists in given multistring.
* returns error code.
* -------------------------------------------------------------------------------------------------------*/
DWORD IsStringInMultiString(HKEY hkey, LPCTSTR szkey, LPCTSTR szvalue, LPCTSTR szCheckForString, BOOL *pbFound)
{
ASSERT(szkey && *szkey);
ASSERT(szvalue && *szvalue);
ASSERT(szCheckForString&& *szCheckForString);
ASSERT(*szkey != '\\');
ASSERT(pbFound);
// not yet found.
*pbFound = FALSE;
CRegistry reg;
DWORD dwError = reg.OpenKey(hkey, szkey, KEY_READ); // open up the required key.
if (dwError == NO_ERROR)
{
LPTSTR szSuiteValue;
DWORD dwSize;
dwError = reg.ReadRegMultiString(szvalue, &szSuiteValue, &dwSize);
if (dwError == NO_ERROR)
{
LPCTSTR pTemp = szSuiteValue;
while(_tcslen(pTemp) > 0 )
{
if (_tcscmp(pTemp, szCheckForString) == 0)
{
*pbFound = TRUE;
break;
}
pTemp += _tcslen(pTemp) + 1; // point to the next string within the multistring.
if ( DWORD(pTemp - szSuiteValue) > (dwSize / sizeof(TCHAR)))
break; // temporary pointer passes the size of the szSuiteValue something is wrong with szSuiteValue.
}
}
}
return dwError;
}
/*--------------------------------------------------------------------------------------------------------
* DWORD AppendStringToMultiString(HKEY hkey, LPCTSTR szSuitekey, LPCTSTR szSuitevalue, LPCTSTR szAppend)
* appends given string to the given multi_sz value
* the given key / value must exist.
* returns error code.
* -------------------------------------------------------------------------------------------------------*/
DWORD AppendStringToMultiString(HKEY hkey, LPCTSTR szSuitekey, LPCTSTR szSuitevalue, LPCTSTR szAppend)
{
ASSERT(szSuitekey && *szSuitekey);
ASSERT(szSuitevalue && *szSuitevalue);
ASSERT(szAppend && *szAppend);
ASSERT(*szSuitekey != '\\');
CRegistry reg;
// open the registry key.
DWORD dwResult = reg.OpenKey(hkey, szSuitekey, KEY_READ | KEY_WRITE);
if (dwResult == ERROR_SUCCESS)
{
DWORD dwSize = 0;
LPTSTR strOriginalString = 0;
// read our multi string
dwResult = reg.ReadRegMultiString(szSuitevalue, &strOriginalString, &dwSize);
if (dwResult == ERROR_SUCCESS)
{
// now calculate the Memory required for appending the string.
// as dwOldSize is in bytes and we are using TCHARs
DWORD dwMemReq = dwSize + ((_tcslen(szAppend) + 2) * sizeof(TCHAR) / sizeof(BYTE));
// NOTE: if dwSize is >= 1 we just require
// dwSize + ((_tcslen(szAppend) + 1) * sizeof(TCHAR) / sizeof(BYTE));
// But in case its 0 we provide space for an additional terminating null
LPTSTR szProductSuite = (LPTSTR ) new BYTE [dwMemReq];
if (!szProductSuite)
{
return ERROR_OUTOFMEMORY;
}
CopyMemory(szProductSuite, strOriginalString, dwSize);
// convert the size into TCHARs
dwSize = dwSize * sizeof(BYTE) / sizeof(TCHAR);
if (dwSize <= 2)
{
// there are no strings out there.
_tcscpy(szProductSuite, szAppend);
// new size including terminating null in tchar
dwSize = _tcslen(szAppend) + 2;
}
else
{
// there are strings in its. so append our string before the terminating null.
// for example for this string "A\0B\0\0" dwSize == 5 and we are doing tcscat at "A\0B\0\0" + 4
_tcscpy(szProductSuite + dwSize - 1, szAppend);
// new size including terminating null in tchar
dwSize += _tcslen(szAppend) + 1;
}
// now append a final terminating null character.
*(szProductSuite + dwSize-1) = NULL;
// reconvert size into bytes.
dwSize *= sizeof(TCHAR) / sizeof(BYTE);
// and finally write the final string.
dwResult = reg.WriteRegMultiString(szSuitevalue, szProductSuite, dwSize);
delete [] szProductSuite;
}
}
return dwResult;
}
/*--------------------------------------------------------------------------------------------------------
* BOOL GetStringValue(HINF hinf, LPCTSTR section, LPCTSTR key, LPTSTR outputbuffer, DWORD dwSize)
* returns the given string value under given section.
* returns success
* -------------------------------------------------------------------------------------------------------*/
DWORD GetStringValue(HINF hinf, LPCTSTR section, LPCTSTR key, LPTSTR outputbuffer, DWORD dwSize)
{
INFCONTEXT context;
BOOL rc = SetupFindFirstLine(
hinf,
section,
key,
&context
);
if (rc)
{
rc = SetupGetStringField(
&context,
1,
outputbuffer,
dwSize,
&dwSize
);
}
if (!rc)
return GetLastError();
else
return ERROR_SUCCESS;
}
DWORD_PTR WebClientSetup(LPCTSTR ComponentId,
LPCTSTR SubcomponentId,
UINT Function,
UINT_PTR Param1,
PVOID Param2)
{
DWORD_PTR rc;
BOOL bCurrentState, bOriginalState;
static fTSWebWasActualSelected = FALSE;
LOGMESSAGE1(_T("Entering %s"), _T("WebClient Setup"));
switch(Function)
{
case OC_INIT_COMPONENT:
return NO_ERROR;
case OC_QUERY_STATE:
return SubcompUseOcManagerDefault;
break;
case OC_SET_LANGUAGE:
return FALSE;
case OC_QUERY_IMAGE:
rc = (DWORD_PTR)LoadImage(GetInstance(), MAKEINTRESOURCE(IDB_WEBCLIENT), IMAGE_BITMAP,
0, 0, LR_DEFAULTCOLOR);
LOGMESSAGE1(_T("Bitmap is: %d"), rc);
return rc;
case OC_QUERY_CHANGE_SEL_STATE:
{
BOOL rc = TRUE;
BOOL fActualSelection = (BOOL)((INT_PTR)Param2 & OCQ_ACTUAL_SELECTION);
BOOL fProposedState = (BOOL)Param1;
//
// Allow an direct selection or
// allow indirect selection if it's unselect
//
if (fActualSelection || !fProposedState) {
fTSWebWasActualSelected = fProposedState;
return TRUE;
}
//
// parent was selected: default is do not install subcomponent
//
if (!fTSWebWasActualSelected) {
return FALSE;
}
//
// we can be here if subcomponent was actually selected but
// OCM calls us for such event twice: when the component is actually
// selected and then when it changes state of the parent.
// So, in this case accept changes, but reset the flag.
// We need to reset the flag for the scenario: select some
// subcomponents, return to the parent, unselect the parent and then
// select parent again. In such case we have to put default again.
//
fTSWebWasActualSelected = FALSE;
return rc;
}
break;
case OC_CALC_DISK_SPACE:
//rc = OnCalcDiskSpace(SubcomponentId, (DWORD)Param1, Param2);
//_tcscpy(section, SubcomponentId);
if ((DWORD)Param1)
{
rc = SetupAddInstallSectionToDiskSpaceList((HDSKSPC)Param2, GetComponentInfHandle(), NULL,
STRING_TS_WEBCLIENT_INSTALL, 0, 0);
}
else
{
rc = SetupRemoveInstallSectionFromDiskSpaceList((HDSKSPC)Param2, GetComponentInfHandle(), NULL,
STRING_TS_WEBCLIENT_INSTALL, 0, 0);
}
LOGMESSAGE1(_T("Query Disk Space return: %d"), rc);
if (!rc)
rc = GetLastError();
else
rc = NO_ERROR;
break;
case OC_QUEUE_FILE_OPS:
rc = NO_ERROR;
bOriginalState = GetHelperRoutines().QuerySelectionState(GetHelperRoutines().OcManagerContext,
STRING_TS_WEBCLIENT, OCSELSTATETYPE_ORIGINAL);
bCurrentState = GetHelperRoutines().QuerySelectionState(GetHelperRoutines().OcManagerContext,
STRING_TS_WEBCLIENT, OCSELSTATETYPE_CURRENT);
LOGMESSAGE2(_T("Original=%d, Current=%d"), bOriginalState, bCurrentState);
if(bCurrentState) {
// Only copy files if it's machine upgrade or
// the component is not previously installed
if (!StateObject.IsStandAlone() || !bOriginalState) {
if (!SetupInstallFilesFromInfSection(GetComponentInfHandle(), NULL, (HSPFILEQ)Param2,
STRING_TS_WEBCLIENT_INSTALL, NULL, 0)) {
rc = GetLastError();
LOGMESSAGE2(_T("ERROR:OnQueueFileOps::SetupInstallFilesFromInfSection <%s> failed.GetLastError() = <%ul)"), SubcomponentId, rc);
}
}
LOGMESSAGE1(_T("Copy files return: %d"), rc);
}
else {
if (!bOriginalState) {
// Not installed before, do nothing
return NO_ERROR;
}
if (!SetupInstallFilesFromInfSection(GetComponentInfHandle(), NULL, (HSPFILEQ)Param2,
STRING_TS_WEBCLIENT_UNINSTALL, NULL, 0))
{
rc = GetLastError();
LOGMESSAGE2(_T("ERROR:OnQueueFileOps::SetupInstallFilesFromInfSection <%s> failed.GetLastError() = <%ul)"), SubcomponentId, rc);
}
LOGMESSAGE1(_T("Remove files return: %d"), rc);
}
break;
case OC_COMPLETE_INSTALLATION:
bOriginalState = GetHelperRoutines().QuerySelectionState(GetHelperRoutines().OcManagerContext, _T("TSWebClient"), OCSELSTATETYPE_ORIGINAL);
bCurrentState = GetHelperRoutines().QuerySelectionState(GetHelperRoutines().OcManagerContext, _T("TSWebClient"), OCSELSTATETYPE_CURRENT);
LOGMESSAGE2(_T("Orinal=%d, Current=%d"), bOriginalState, bCurrentState);
if(bOriginalState==bCurrentState) //state does not change
return NO_ERROR;
int iTrans; //mark removing or adding tsweb dir
int nLength;
iTrans = 0;
WCHAR wszVDirName[MAX_PATH];
WCHAR wszDirPath[MAX_PATH];
TCHAR szDirPath[MAX_PATH];
TCHAR szVDirName[MAX_PATH];
if (GetWindowsDirectory(szDirPath, MAX_PATH) == 0) {
rc = GetLastError();
return rc;
}
nLength = _tcsclen(szDirPath);
if(_T('\\')==szDirPath[nLength-1])
szDirPath[nLength-1]=_T('\0');
_tcscat(szDirPath, STRING_TS_WEBCLIENT_DIR);
if (LoadString(GetInstance(), IDS_STRING_TSWEBCLIENT_VIRTUALPATH, szVDirName, MAX_PATH) == 0) {
LOGMESSAGE0(_T("Can't load string IDS_STRING_TSWEBCLIENT_VIRTUALPATH"));
rc = GetLastError();;
}
LOGMESSAGE2(_T("Dir Path is: %s, Virtual Name is: %s"), szDirPath, szVDirName);
if(bCurrentState) //enable IIS directory
iTrans = TRANS_ADD;
else
iTrans = TRANS_DEL;
#ifndef _UNICODE
MultiByteToWideChar(CP_ACP, 0, szDirPath, -1, (LPWSTR) wszDirPath, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, szVDirName, -1, (LPWSTR) wszVDirName, MAX_PATH);
#else
_tcscpy(wszDirPath, szDirPath);
_tcscpy(wszVDirName, szVDirName);
#endif
rc = OpenMetabaseAndDoStuff(wszVDirName, wszDirPath, iTrans)?0:1;
LOGMESSAGE1(_T("Websetup complete, return is: %d"), rc);
return rc;
default:
rc = NO_ERROR; // it means we do not recognize this command.
break;
}
return rc;
}
BOOL
OpenMetabaseAndDoStuff(
WCHAR * wszVDir,
WCHAR * wszDir,
int iTrans)
{
BOOL fRet = FALSE;
HRESULT hr;
IMSAdminBase *pIMSAdminBase = NULL; // Metabase interface pointer
WCHAR wszPrintString[MAX_PATH + MAX_PATH];
// Make sure that IISADMIN service exists
if (CheckifServiceExist(_T("IISADMIN")) != 0)
{
LOGMESSAGE0(_T("IISADMIN service does not exist"));
// We have to return TRUE here if IIS service does not exist
return TRUE;
}
if( FAILED (hr = CoInitializeEx( NULL, COINIT_MULTITHREADED )) ||
FAILED (hr = ::CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&pIMSAdminBase)))
{
LOGMESSAGE1(_T("CoCreateInstance failed with error code %u"), hr);
return FALSE;
}
switch (iTrans) {
case TRANS_DEL:
if(RemoveVirtualDir( pIMSAdminBase, wszVDir)) {
hr = pIMSAdminBase->SaveData();
if( SUCCEEDED( hr )) {
fRet = TRUE;
}
}
break;
case TRANS_ADD:
if(AddVirtualDir( pIMSAdminBase, wszVDir, wszDir)) {
hr = pIMSAdminBase->SaveData();
if( SUCCEEDED( hr )) {
fRet = TRUE;
}
}
break;
default:
break;
}
if (pIMSAdminBase) {
pIMSAdminBase->Release();
pIMSAdminBase = NULL;
}
CoUninitialize();
return fRet;
}
BOOL
GetVdirPhysicalPath(
IMSAdminBase *pIMSAdminBase,
WCHAR * wszVDir,
WCHAR *wszStringPathToFill)
{
HRESULT hr;
BOOL fRet = FALSE;
METADATA_HANDLE hMetabase = NULL; // handle to metabase
METADATA_RECORD mr;
WCHAR szTmpData[MAX_PATH];
DWORD dwMDRequiredDataLen;
// open key to ROOT on website #1 (default)
hr = pIMSAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
L"/LM/W3SVC/1",
METADATA_PERMISSION_READ,
REASONABLE_TIMEOUT,
&hMetabase);
if( FAILED( hr )) {
return FALSE;
}
// Get the physical path for the WWWROOT
mr.dwMDIdentifier = MD_VR_PATH;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = sizeof( szTmpData );
mr.pbMDData = reinterpret_cast<unsigned char *>(szTmpData);
//if nothing specified get the root.
if (_wcsicmp(wszVDir, L"") == 0) {
WCHAR wszTempDir[MAX_PATH];
swprintf(wszTempDir,L"/ROOT/%s", wszVDir);
hr = pIMSAdminBase->GetData( hMetabase, wszTempDir, &mr, &dwMDRequiredDataLen );
} else {
hr = pIMSAdminBase->GetData( hMetabase, L"/ROOT", &mr, &dwMDRequiredDataLen );
}
pIMSAdminBase->CloseKey( hMetabase );
if( SUCCEEDED( hr )) {
wcscpy(wszStringPathToFill,szTmpData);
fRet = TRUE;
}
pIMSAdminBase->CloseKey( hMetabase );
return fRet;
}
BOOL
AddVirtualDir(
IMSAdminBase *pIMSAdminBase,
WCHAR * wszVDir,
WCHAR * wszDir)
{
HRESULT hr;
BOOL fRet = FALSE;
METADATA_HANDLE hMetabase = NULL; // handle to metabase
WCHAR szTempPath[MAX_PATH];
DWORD dwMDRequiredDataLen = 0;
DWORD dwAccessPerm = 0;
METADATA_RECORD mr;
// Attempt to open the virtual dir set on Web server #1 (default server)
hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
L"/LM/W3SVC/1/ROOT",
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
REASONABLE_TIMEOUT,
&hMetabase );
// Create the key if it does not exist.
if( FAILED( hr )) {
return FALSE;
}
fRet = TRUE;
mr.dwMDIdentifier = MD_VR_PATH;
mr.dwMDAttributes = 0;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = sizeof( szTempPath );
mr.pbMDData = reinterpret_cast<unsigned char *>(szTempPath);
// see if MD_VR_PATH exists.
hr = pIMSAdminBase->GetData( hMetabase, wszVDir, &mr, &dwMDRequiredDataLen );
if( FAILED( hr )) {
fRet = FALSE;
if( hr == MD_ERROR_DATA_NOT_FOUND ||
HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND ) {
// Write both the key and the values if GetData() failed with any of the two errors.
pIMSAdminBase->AddKey( hMetabase, wszVDir );
mr.dwMDIdentifier = MD_VR_PATH;
mr.dwMDAttributes = METADATA_INHERIT;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(wszDir) + 1) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(wszDir);
// Write MD_VR_PATH value
hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr );
fRet = SUCCEEDED( hr );
// Set the default authentication method
if( fRet ) {
DWORD dwAuthorization = MD_AUTH_ANONYMOUS; // NTLM only.
mr.dwMDIdentifier = MD_AUTHORIZATION;
mr.dwMDAttributes = METADATA_INHERIT; // need to inherit so that all subdirs are also protected.
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = DWORD_METADATA;
mr.dwMDDataLen = sizeof(DWORD);
mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAuthorization);
// Write MD_AUTHORIZATION value
hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr );
fRet = SUCCEEDED( hr );
}
}
}
// In the following, do the stuff that we always want to do to the virtual dir, regardless of Admin's setting.
if( fRet ) {
dwAccessPerm = MD_ACCESS_READ | MD_ACCESS_SCRIPT;
mr.dwMDIdentifier = MD_ACCESS_PERM;
mr.dwMDAttributes = METADATA_INHERIT; // Make it inheritable so all subdirectories will have the same rights.
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = DWORD_METADATA;
mr.dwMDDataLen = sizeof(DWORD);
mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAccessPerm);
// Write MD_ACCESS_PERM value
hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr );
fRet = SUCCEEDED( hr );
}
if( fRet ) {
PWCHAR szDefLoadFile = L"Default.htm,Default.asp";
mr.dwMDIdentifier = MD_DEFAULT_LOAD_FILE;
mr.dwMDAttributes = 0; // no need for inheritence
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(szDefLoadFile) + 1) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(szDefLoadFile);
// Write MD_DEFAULT_LOAD_FILE value
hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr );
fRet = SUCCEEDED( hr );
}
if( fRet ) {
PWCHAR szKeyType = IIS_CLASS_WEB_VDIR_W;
mr.dwMDIdentifier = MD_KEY_TYPE;
mr.dwMDAttributes = 0; // no need for inheritence
mr.dwMDUserType = IIS_MD_UT_SERVER;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(szKeyType) + 1) * sizeof(WCHAR);
mr.pbMDData = reinterpret_cast<unsigned char *>(szKeyType);
// Write MD_DEFAULT_LOAD_FILE value
hr = pIMSAdminBase->SetData( hMetabase, wszVDir, &mr );
fRet = SUCCEEDED( hr );
}
pIMSAdminBase->CloseKey( hMetabase );
return fRet;
}
BOOL
RemoveVirtualDir(
IMSAdminBase *pIMSAdminBase,
WCHAR * wszVDir)
{
METADATA_HANDLE hMetabase = NULL; // handle to metabase
HRESULT hr;
// Attempt to open the virtual dir set on Web server #1 (default server)
hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
L"/LM/W3SVC/1/ROOT",
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
REASONABLE_TIMEOUT,
&hMetabase );
if( FAILED( hr )) {
return FALSE;
}
// We don't check the return value since the key may already
// not exist and we could get an error for that reason.
pIMSAdminBase->DeleteKey( hMetabase, wszVDir );
pIMSAdminBase->CloseKey( hMetabase );
return TRUE;
}
//Check if the service "lpServiceName" exist or not
// if exist, return 0
// if not, return error code
INT CheckifServiceExist(LPCTSTR lpServiceName)
{
INT err = 0;
SC_HANDLE hScManager = NULL;
SC_HANDLE hService = NULL;
if ((hScManager = OpenSCManager(NULL, NULL, GENERIC_ALL)) == NULL
|| (hService = OpenService(hScManager, lpServiceName, GENERIC_ALL)) == NULL)
{
err = GetLastError();
}
if (hService)
CloseServiceHandle(hService);
if (hScManager)
CloseServiceHandle(hScManager);
return (err);
}
// EOF