/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name : inetprop.cpp Abstract: Internet Properties base classes Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ // // Include Files // #include "stdafx.h" #include "comprop.h" #include "inetprop.h" #include "idlg.h" #include "mmc.h" extern "C" { #include } #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif // // Period to sleep while waiting for service to attain desired state // #define SLEEP_INTERVAL (500L) // // Maximum time to wait for service to attain desired state // #define MAX_SLEEP (180000) // For a service #define MAX_SLEEP_INST ( 30000) // For an instance // // Instance numbers // #define FIRST_INSTANCE (1) #define LAST_INSTANCE (0xffffffff) #define MAX_INSTANCE_LEN (32) // // Calling instance // HINSTANCE hDLLInstance; // // Utility Functions // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // // Base registry key definition // #define SZ_REG_KEY_BASE _T("Software\\Microsoft\\%s") const LPCTSTR g_cszTemplates = SZ_MBN_INFO SZ_MBN_SEP_STR SZ_MBN_TEMPLATES; const LPCTSTR g_cszCompression = SZ_MBN_FILTERS SZ_MBN_SEP_STR SZ_MBN_COMPRESSION SZ_MBN_SEP_STR SZ_MBN_PARAMETERS; const LPCTSTR g_cszMachine = SZ_MBN_MACHINE; const LPCTSTR g_cszMimeMap = SZ_MBN_MIMEMAP; const LPCTSTR g_cszRoot = SZ_MBN_ROOT; const LPCTSTR g_cszSep = SZ_MBN_SEP_STR; const LPCTSTR g_cszInfo = SZ_MBN_INFO; const TCHAR g_chSep = SZ_MBN_SEP_CHAR; LPCTSTR GenerateRegistryKey( OUT CString & strBuffer, IN LPCTSTR lpszSubKey OPTIONAL ) /*++ Routine Description: Generate a registry key name based on the current app, and a provided subkey (optional) Arguments: CString & strBuffer : Buffer to create registry key name into. LPCTSTR lpszSubKey : Subkey name or NULL Return Value: Pointer to the registry key value --*/ { try { // // Use the app name as the primary registry name // CWinApp * pApp = ::AfxGetApp(); if (!pApp) { TRACEEOLID("No app object -- can't generate registry key name"); ASSERT(FALSE); return NULL; } strBuffer.Format(SZ_REG_KEY_BASE, pApp->m_pszAppName); if (lpszSubKey) { strBuffer += _T("\\"); strBuffer += lpszSubKey; } TRACEEOLID("Registry key is " << strBuffer); } catch(CMemoryException * e) { TRACEEOLID("!!!exception building regkey"); e->ReportError(); e->Delete(); return NULL; } return strBuffer; } NET_API_STATUS QueryInetServiceStatus( IN LPCTSTR lpszServer, IN LPCTSTR lpszService, OUT int * pnState ) /*++ Routine Description: Determine the status of the given service on the given machine. Arguments: LPCTSTR lpszServer : Server name LPCTSTR lpszService : Service name int * pnState : Returns the service state Return Value: Error return code --*/ { #ifdef NO_SERVICE_CONTROLLER *pnState = INetServiceUnknown; return ERROR_SUCCESS; #else SC_HANDLE hScManager; NET_API_STATUS err = ERROR_SUCCESS; hScManager = ::OpenSCManager(lpszServer, NULL, SC_MANAGER_ENUMERATE_SERVICE); if (hScManager == NULL) { return ::GetLastError(); } SC_HANDLE hService = ::OpenService(hScManager, lpszService, SERVICE_QUERY_STATUS); if (hService == NULL) { err = ::GetLastError(); } else { SERVICE_STATUS ss; VERIFY(::QueryServiceStatus(hService, &ss)); VERIFY(::QueryServiceStatus(hService, &ss)); switch(ss.dwCurrentState) { case SERVICE_STOPPED: case SERVICE_STOP_PENDING: *pnState = INetServiceStopped; break; case SERVICE_RUNNING: case SERVICE_START_PENDING: case SERVICE_CONTINUE_PENDING: *pnState = INetServiceRunning; break; case SERVICE_PAUSE_PENDING: case SERVICE_PAUSED: *pnState = INetServicePaused; break; default: *pnState = INetServiceUnknown; } // // Make sure this is a controllable service // if ( (*pnState == INetServiceRunning || *pnState == INetServicePaused) && !(ss.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN)) { TRACEEOLID("Service not controllable -- ignored"); ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return ERROR_SERVICE_START_HANG; } ::CloseServiceHandle(hService); } ::CloseServiceHandle(hScManager); return err; #endif // NO_SERVICE_CONTROLLER } NET_API_STATUS ChangeInetServiceState( IN LPCTSTR lpszServer, IN LPCTSTR lpszService, IN int nNewState, OUT int * pnCurrentState ) /*++ Routine Description: Start/stop/pause or continue a _service_ Arguments: LPCTSTR lpszServer : Server name LPCTSTR lpszService : Service name int nNewState : INetService* definition. int * pnCurrentState : Ptr to current state (will be changed) Return Value: Error return code --*/ { #ifdef NO_SERVICE_CONTROLLER *pnCurrentState = INetServiceUnknown; return ERROR_SERVICE_REQUEST_TIMEOUT; #else SC_HANDLE hService = NULL; SC_HANDLE hScManager = NULL; NET_API_STATUS err = ERROR_SUCCESS; do { hScManager = ::OpenSCManager(lpszServer, NULL, SC_MANAGER_ALL_ACCESS); if (hScManager == NULL) { err = ::GetLastError(); break; } hService = ::OpenService(hScManager, lpszService, SERVICE_ALL_ACCESS); if (hService == NULL) { err = ::GetLastError(); break; } BOOL fSuccess = FALSE; DWORD dwTargetState; DWORD dwPendingState = 0; SERVICE_STATUS ss; switch(nNewState) { case INetServiceStopped: dwTargetState = SERVICE_STOPPED; dwPendingState = SERVICE_STOP_PENDING; fSuccess = ::ControlService(hService, SERVICE_CONTROL_STOP, &ss); break; case INetServiceRunning: dwTargetState = SERVICE_RUNNING; if (*pnCurrentState == INetServicePaused) { dwPendingState = SERVICE_CONTINUE_PENDING; fSuccess = ::ControlService(hService, SERVICE_CONTROL_CONTINUE, &ss); } else { dwPendingState = SERVICE_START_PENDING; fSuccess = ::StartService(hService, 0, NULL); } break; case INetServicePaused: dwTargetState = SERVICE_PAUSED; dwPendingState = SERVICE_PAUSE_PENDING; fSuccess = ::ControlService(hService, SERVICE_CONTROL_PAUSE, &ss); break; default: ASSERT(FALSE && "Invalid service state requested"); err = ERROR_INVALID_PARAMETER; } if (!fSuccess && err == ERROR_SUCCESS) { err = ::GetLastError(); } if (err != ERROR_SUCCESS) { break; } // // Wait for the service to attain desired state, timeout // after 3 minutes. // DWORD dwSleepTotal = 0L; while (dwSleepTotal < MAX_SLEEP) { if (!::QueryServiceStatus(hService, &ss)) { err = ::GetLastError(); break; } if (ss.dwCurrentState != dwPendingState) { // // Done one way or another // if (ss.dwCurrentState != dwTargetState) { // // Did not achieve desired result. Something went // wrong. // if (ss.dwWin32ExitCode) { err = ss.dwWin32ExitCode; } } break; } // // Still pending... // ::Sleep(SLEEP_INTERVAL); dwSleepTotal += SLEEP_INTERVAL; } if (dwSleepTotal >= MAX_SLEEP) { err = ERROR_SERVICE_REQUEST_TIMEOUT; } // // Update state information // switch(ss.dwCurrentState) { case SERVICE_STOPPED: case SERVICE_STOP_PENDING: *pnCurrentState = INetServiceStopped; break; case SERVICE_RUNNING: case SERVICE_START_PENDING: case SERVICE_CONTINUE_PENDING: *pnCurrentState = INetServiceRunning; break; case SERVICE_PAUSE_PENDING: case SERVICE_PAUSED: *pnCurrentState = INetServicePaused; break; default: *pnCurrentState = INetServiceUnknown; } } while(FALSE); if (hService) { ::CloseServiceHandle(hService); } if (hScManager) { ::CloseServiceHandle(hScManager); } return err; #endif // NO_SERVICE_CONTROLLER } BOOL IsServerLocal( IN LPCTSTR lpszServer ) /*++ Routine Description: Check to see if the given name refers to the local machine Arguments: LPCTSTR lpszServer : Server name Return Value: TRUE if the given name refers to the local computer, FALSE otherwise Note: Doesn't work if the server is an ip address --*/ { TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwSize = sizeof(szComputerName); if (GetComputerName(szComputerName, &dwSize) && !lstrcmpi(szComputerName, PURE_COMPUTER_NAME(lpszServer))) { return TRUE; } return FALSE; } BOOL DoesServerExist( IN LPCTSTR lpszServer ) /*++ Routine Description: Check to make sure the machine exists Arguments: LPCTSTR lpszServer : machine name Return Value: TRUE if the server exists, FALSE otherwise. --*/ { #ifdef NO_SERVICE_CONTROLLER // // Assume it exists // return TRUE; #else // // CODEWORK: This is not the best way to do this, especially // not across proxies and what not. // SC_HANDLE hScManager; NET_API_STATUS err = ERROR_SUCCESS; hScManager = ::OpenSCManager(lpszServer, NULL, SC_MANAGER_CONNECT); if (hScManager == NULL) { err = ::GetLastError(); } ::CloseServiceHandle(hScManager); return err != RPC_S_SERVER_UNAVAILABLE; #endif // NO_SERVICE_CONTROLLER } BOOL GetVolumeInformationSystemFlags( IN LPCTSTR lpszPath, OUT DWORD * pdwSystemFlags ) /*++ Routine Description: Get the system flags for the path in question Arguments: LPCTSTR lpszPath : Path DWORD * pdwSystemFlags : Returns system flags Return Value: TRUE for success, FALSE for failure. --*/ { ASSERT(pdwSystemFlags != NULL); TRACEEOLID("Getting system flags for " << lpszPath); DWORD dwMaxComponentLength; TCHAR szRoot[MAX_PATH + 1]; TCHAR szFileSystem[MAX_PATH + 1]; // // Generating root path // if (IsUNCName(lpszPath)) { // // Root path of a UNC path is \\foo\bar\ // ASSERT(lstrlen(lpszPath) < MAX_PATH); int cSlashes = 0; LPCTSTR lpszSrc = lpszPath; LPTSTR lpszDst = szRoot; while (cSlashes < 4 && *lpszSrc) { if ((*lpszDst++ = *lpszSrc++) == '\\') { ++cSlashes; } } if (!*lpszSrc) { *lpszDst++ = '\\'; } *lpszDst = '\0'; } else { ::wsprintf(szRoot, _T("%c:\\"), *lpszPath); } TRACEEOLID("Root path is " << szRoot); return ::GetVolumeInformation( szRoot, NULL, 0, NULL, &dwMaxComponentLength, pdwSystemFlags, szFileSystem, STRSIZE(szFileSystem) ); } LPTSTR ISMAllocString( IN CString & str ) /*++ Routine Description: Allocate and copy string using ISM allocator Arguments: CString & str : string Return Value: Pointer to the allocated string --*/ { LPTSTR lp = (LPTSTR)ISMAllocMem((str.GetLength() + 1)* sizeof(TCHAR)); if (lp != NULL) { lstrcpy(lp, str); } return lp; } // // Utility classes // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CBlob::CBlob() /*++ Routine Description: NULL constructor Arguments: None Return Value: N/A --*/ : m_pbItem(NULL), m_dwSize(0L) { } CBlob::CBlob( IN DWORD dwSize, IN PBYTE pbItem, IN BOOL fMakeCopy ) /*++ Routine Description: Constructor Arguments: DWORD dwSize : Size of memory block PBYTE pbItem : Pointer to memory block BOOL fMakeCopy : If TRUE, makes a copy of the memory block. If FALSE, takes ownership of the pointer. Return Value: N/A --*/ : m_pbItem(NULL), m_dwSize(0L) { SetValue(dwSize, pbItem, fMakeCopy); } CBlob::CBlob( IN const CBlob & blob ) /*++ Routine Description: Copy constructor Arguments: const CBlob & blob : Source blob Return Value: N/A Notes: This contructor makes a copy of the memory block in question. --*/ : m_pbItem(NULL), m_dwSize(0L) { SetValue(blob.GetSize(), blob.m_pbItem, TRUE); } void CBlob::SetValue( IN DWORD dwSize, IN PBYTE pbItem, IN BOOL fMakeCopy OPTIONAL ) /*++ Routine Description: Assign the value to this binary object. If fMakeCopy is FALSE, the blob will take ownership of the pointer, otherwise a copy will be made. Arguments: DWORD dwSize : Size in bytes PBYTE pbItem : Byte streadm BOOL fMakeCopy : If true, make a copy, else assign pointer Return Value: None --*/ { if (!IsEmpty()) { TRACEEOLID("Assigning value to non-empty blob. Cleaning up"); CleanUp(); } if (dwSize > 0L) { // // Make private copy // m_dwSize = dwSize; if (fMakeCopy) { m_pbItem = (PBYTE)AllocMem(m_dwSize); if (m_pbItem != NULL) CopyMemory(m_pbItem, pbItem, dwSize); } else { m_pbItem = pbItem; } } } void CBlob::CleanUp() /*++ Routine Description: Delete data pointer, and reset pointer and size. Arguments: None Return Value: None --*/ { if (m_pbItem) { FreeMem(m_pbItem); } m_pbItem = NULL; m_dwSize = 0L; } CBlob & CBlob::operator =( IN const CBlob & blob ) /*++ Routine Description: Assign values from another CBlob. Arguments: const CBlob & blob : Source blob Return Value: Reference to this object --*/ { // // Make copy of data // SetValue(blob.GetSize(), blob.m_pbItem, TRUE); return *this; } BOOL CBlob::operator ==( IN const CBlob & blob ) const /*++ Routine Description: Compare two binary large objects. In order to match, the objects must be the same size, and byte identical. Arguments: const CBlob & blob : Blob to compare against. Return Value: TRUE if the objects match, FALSE otherwise. --*/ { if (GetSize() != blob.GetSize()) { return FALSE; } return memcmp(m_pbItem, blob.m_pbItem, GetSize()) == 0; } CMetaProperties::CMetaProperties( IN LPCTSTR lpszServerName, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParentPath, OPTIONAL IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Constructor -- creates the interface Arguments: LPCTSTR lpszServerName : Server name LPCTSTR lpszService : Service name or NULL DWORD dwInstance : Instance number or 0 LPCTSTR lpszParentPath : Parent path or NULL LPCTSTR lpszAlias : Alias name or NULL Return Value: N/A --*/ : m_hResult(S_OK), m_dwNumEntries(0), m_dwMDUserType(ALL_METADATA), m_dwMDDataType(ALL_METADATA), m_dwMDDataLen(0), m_pbMDData(NULL), m_fInherit(TRUE), CMetaKey(lpszServerName) { // // Build the metabase path (prior to GetAllData) // BuildMetaPath( m_strMetaRoot, lpszService, dwInstance, lpszParentPath, lpszAlias ); } CMetaProperties::CMetaProperties( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParentPath, OPTIONAL IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Constructor -- attach to an existing interface. Arguments: CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Service name or NULL DWORD dwInstance : Instance number or 0 LPCTSTR lpszParentPath : Parent path or NULL LPCTSTR lpszAlias : Alias name or NULL Return Value: N/A --*/ : m_hResult(S_OK), m_dwNumEntries(0), m_dwMDUserType(ALL_METADATA), m_dwMDDataType(ALL_METADATA), m_dwMDDataLen(0), m_pbMDData(NULL), m_fInherit(TRUE), CMetaKey(pInterface) { // // Build the metabase path // BuildMetaPath( m_strMetaRoot, lpszService, dwInstance, lpszParentPath, lpszAlias ); } CMetaProperties::CMetaProperties( IN const CMetaKey * pKey, IN LPCTSTR lpszMDPath ) /*++ Routine Description: Construct from open key Arguments: const CMetaKey * pKey : Open key LPCTSTR lpszMDPath : Path Return Value: N/A --*/ : m_hResult(S_OK), m_dwNumEntries(0), m_dwMDUserType(ALL_METADATA), m_dwMDDataType(ALL_METADATA), m_dwMDDataLen(0), m_pbMDData(NULL), m_strMetaRoot(lpszMDPath), m_fInherit(TRUE), CMetaKey(FALSE, pKey) { } CMetaProperties::CMetaProperties( IN const CMetaKey * pKey, IN DWORD dwPath ) /*++ Routine Description: Construct from open key Arguments: const CMetaKey * pKey : Open key DWORD dwPath : Path (instance number probably) Return Value: N/A --*/ : m_hResult(S_OK), m_dwNumEntries(0), m_dwMDUserType(ALL_METADATA), m_dwMDDataType(ALL_METADATA), m_dwMDDataLen(0), m_pbMDData(NULL), m_fInherit(TRUE), CMetaKey(FALSE, pKey) { _ltot(dwPath, m_strMetaRoot.GetBuffer(32), 10); m_strMetaRoot.ReleaseBuffer(); } CMetaProperties::~CMetaProperties() /*++ Routine Description: Destructor -- clean up Arguments: N/A Return Value: N/A --*/ { Cleanup(); } /* virtual */ HRESULT CMetaProperties::LoadData() /*++ Routine Description: Fetch all data with or without inheritance, and call the derived class to parse the data into fields. Arguments: None Return Value: HRESULT --*/ { // // Get all data off the master root // DWORD dwMDAttributes = METADATA_NO_ATTRIBUTES; if (m_fInherit) { dwMDAttributes = METADATA_INHERIT | METADATA_PARTIAL_PATH | METADATA_ISINHERITED; } m_hResult = GetAllData( dwMDAttributes, m_dwMDUserType, m_dwMDDataType, &m_dwNumEntries, &m_dwMDDataLen, &m_pbMDData, m_strMetaRoot ); if (SUCCEEDED(m_hResult)) { // // Call the derived class to break up data into fields // ParseFields(); } Cleanup(); return m_hResult; } void CMetaProperties::Cleanup() /*++ Routine Description: Free data Arguments: None Return Value: None --*/ { SAFE_FREEMEM(m_pbMDData); m_dwNumEntries = 0; m_dwMDDataLen = 0; } /* virtual */ HRESULT CMetaProperties::QueryResult() const /*++ Routine Description: Determine the construction return code Arguments: None Return Value: HRESULT --*/ { HRESULT hr = CMetaKey::QueryResult(); return SUCCEEDED(hr) ? m_hResult : hr; } HRESULT CMetaProperties::OpenForWriting( IN BOOL fCreate OPTIONAL ) /*++ Routine Description: Attempt to open the path for writing. If fCreate is TRUE (default), then create the path if it doesn't yet exist Arguments: BOOL fCreate : If TRUE, create the path if it doesn't exist. Return Value: HRESULT Notes: If the key is already open, this will fire an ASSERT and close it. --*/ { CError err; if (IsOpen()) { TRACEEOLID("Key already open -- closing"); ASSERT(FALSE); Close(); } BOOL fNewPath; do { fNewPath = FALSE; err = Open( METADATA_PERMISSION_WRITE, METADATA_MASTER_ROOT_HANDLE, m_strMetaRoot ); if (err.Win32Error() == ERROR_PATH_NOT_FOUND && fCreate) { TRACEEOLID("Metabase path doesn't exist -- creating it"); err = CreatePathFromFailedOpen(); fNewPath = err.Succeeded(); } } while(fNewPath); return err; } // // Machine properties // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CMachineProps::CMachineProps( IN LPCTSTR lpszServerName ) /*++ Routine Description: Constructor for machine properties object Arguments: LPCTSTR lpszServerName : Server name Return Value: N/A --*/ : CMetaProperties( lpszServerName, NULL, MASTER_INSTANCE ), // // Default properties // m_nMaxNetworkUse(DEF_BANDWIDTH) { } CMachineProps::CMachineProps( IN const CMetaInterface * pInterface ) /*++ Routine Description: Constructor for machine properties object Arguments: CMetaInterface * pInterface : Existing interface Return Value: N/A --*/ : CMetaProperties( pInterface, NULL, MASTER_INSTANCE ), // // Default properties // m_nMaxNetworkUse(DEF_BANDWIDTH) { } /* virtual */ void CMachineProps::ParseFields() /*++ Routine Description: Parse the fetched data into fields Arguments: None Return Value: None --*/ { BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData) HANDLE_META_RECORD(MD_MAX_BANDWIDTH, m_nMaxNetworkUse) END_PARSE_META_RECORDS } HRESULT CMachineProps::WriteDirtyProps() /*++ Routine Description: Write dirty properties Arguments: None Return Value: HRESULT --*/ { CError err; BEGIN_META_WRITE() META_WRITE(MD_MAX_BANDWIDTH, m_nMaxNetworkUse) END_META_WRITE(err); return err; } // // Compression Properties // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CIISCompressionProps::CIISCompressionProps( IN LPCTSTR lpszServerName, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParent, OPTIONAL IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Constructor for compression properties object Arguments: LPCTSTR lpszServerName : Server name LPCTSTR lpszService : Service name (must be w3svc) DWORD dwInstance : Instance (must be master) LPCTSTR lpszParent : Parent path (must be NULL) LPCTSTR lpszAlias : Alias name (must be NULL) Return Value: N/A --*/ : CMetaProperties( lpszServerName, lpszService, dwInstance, lpszParent, g_cszCompression ), // // Default properties // m_fEnableStaticCompression(FALSE), m_fEnableDynamicCompression(FALSE), m_fLimitDirectorySize(FALSE), m_fPathDoesNotExist(FALSE), m_dwDirectorySize(0xffffffff), m_strDirectory() { // // Override base parameters // m_fInherit = FALSE; } /* virtual */ HRESULT CIISCompressionProps::LoadData() /*++ Routine Description: Fetch all data with or without inheritance, and call the derived class to parse the data into fields. Arguments: None Return Value: HRESULT --*/ { CError err(CMetaProperties::LoadData()); m_fPathDoesNotExist = (err.Win32Error() == ERROR_PATH_NOT_FOUND); return err; } /* virtual */ void CIISCompressionProps::ParseFields() /*++ Routine Description: Parse the fetched data into fields Arguments: None Return Value: None --*/ { BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData) HANDLE_META_RECORD(MD_HC_DO_STATIC_COMPRESSION, m_fEnableStaticCompression) HANDLE_META_RECORD(MD_HC_DO_DYNAMIC_COMPRESSION, m_fEnableDynamicCompression) HANDLE_META_RECORD(MD_HC_DO_DISK_SPACE_LIMITING, m_fLimitDirectorySize) HANDLE_META_RECORD(MD_HC_MAX_DISK_SPACE_USAGE, m_dwDirectorySize) HANDLE_META_RECORD(MD_HC_COMPRESSION_DIRECTORY, m_strDirectory) END_PARSE_META_RECORDS } /* virtual */ HRESULT CIISCompressionProps::WriteDirtyProps() /*++ Routine Description: Write dirty properties Arguments: None Return Value: HRESULT --*/ { CError err; BEGIN_META_WRITE() META_WRITE(MD_HC_DO_STATIC_COMPRESSION, m_fEnableStaticCompression) META_WRITE(MD_HC_DO_DYNAMIC_COMPRESSION, m_fEnableDynamicCompression) META_WRITE(MD_HC_DO_DISK_SPACE_LIMITING, m_fLimitDirectorySize) META_WRITE(MD_HC_MAX_DISK_SPACE_USAGE, m_dwDirectorySize) META_WRITE(MD_HC_COMPRESSION_DIRECTORY, m_strDirectory) END_META_WRITE(err); return err; } // // Mime Types Properties // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CMimeTypes::CMimeTypes( IN LPCTSTR lpszServerName, IN LPCTSTR lpszService OPTIONAL, IN DWORD dwInstance OPTIONAL, IN LPCTSTR lpszParent OPTIONAL, IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Mime types list constructor Arguments: LPCTSTR lpszServerName : Name of the server containing the metabase LPCTSTR lpszService : Service name (e.g. "w3svc" or NULL) DWORD dwInstance : Instance number (could be MASTER_INSTANCE) LPCTSTR lpszParent : Parent path LPCTSTR lpszAlias : Alias name Return Value: N/A --*/ : CMetaProperties( lpszServerName, lpszService, dwInstance, lpszParent, dwInstance == MASTER_INSTANCE && lpszService == NULL ? g_cszMimeMap : lpszAlias ), // // Default properties // m_strlMimeTypes() { } CMimeTypes::CMimeTypes( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService OPTIONAL, IN DWORD dwInstance OPTIONAL, IN LPCTSTR lpszParent OPTIONAL, IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Mime types list constructor Arguments: CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Service name (e.g. "w3svc" or NULL) DWORD dwInstance : Instance number (could be MASTER_INSTANCE) LPCTSTR lpszParent : Parent path LPCTSTR lpszAlias : Alias name Return Value: N/A --*/ : CMetaProperties( pInterface, lpszService, dwInstance, lpszParent, dwInstance == MASTER_INSTANCE && lpszService == NULL ? g_cszMimeMap : lpszAlias ), // // Default properties // m_strlMimeTypes() { } void CMimeTypes::ParseFields() /*++ Routine Description: Parse the fetched data into fields Arguments: None Return Value: None --*/ { BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData) HANDLE_META_RECORD(MD_MIME_MAP, m_strlMimeTypes) END_PARSE_META_RECORDS } /* virtual */ HRESULT CMimeTypes::WriteDirtyProps() /*++ Routine Description: Write the dirty properties to the metabase Arguments: None Return Value: HRESULT --*/ { CError err; BEGIN_META_WRITE() META_WRITE(MD_MIME_MAP, m_strlMimeTypes); END_META_WRITE(err); return err; } // // Server Capabilities // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CServerCapabilities::CServerCapabilities( IN LPCTSTR lpszServerName, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance OPTIONAL ) /*++ Routine Description: Constructor for server capabilities object Arguments: LPCTSTR lpszServerName : Server name LPCTSTR lpszService : Service name (optional) DWORD dwInstance : Instance number -- ignored (will be removed) Return Value: N/A --*/ : CMetaProperties( lpszServerName, lpszService, MASTER_INSTANCE, g_cszInfo ), // // Default properties // m_dwPlatform(), m_dwVersionMajor(), m_dwVersionMinor(), m_dwCapabilities((DWORD)~IIS_CAP1_10_CONNECTION_LIMIT), m_dwConfiguration(0L) { m_dwMDUserType = IIS_MD_UT_SERVER; m_dwMDDataType = DWORD_METADATA; } /* virtual */ void CServerCapabilities::ParseFields() /*++ Routine Description: Parse the fetched data into fields Arguments: None Return Value: None --*/ { // // Only reading UT_SERVER, DWORD_METADATA. // BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData) HANDLE_META_RECORD(MD_SERVER_PLATFORM, m_dwPlatform) HANDLE_META_RECORD(MD_SERVER_VERSION_MAJOR, m_dwVersionMajor) HANDLE_META_RECORD(MD_SERVER_VERSION_MINOR, m_dwVersionMinor) HANDLE_META_RECORD(MD_SERVER_CAPABILITIES, m_dwCapabilities) HANDLE_META_RECORD(MD_SERVER_CONFIGURATION_INFO, m_dwConfiguration) END_PARSE_META_RECORDS } // // Instance Properties // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* static */ LPCTSTR CInstanceProps::GetDisplayText( OUT CString & strName, IN LPCTSTR szComment, IN LPCTSTR szHostHeaderName, IN LPCTSTR szServiceName, IN CIPAddress & ia, IN UINT uPort, IN DWORD dwID ) /*++ Routine Description: Build display text from instance information Arguments: CString & strName LPCTSTR szComment LPCTSTR szHostHeaderName LPCTSTR szServiceName CIPAddress & ia UINT uPort DWORD dwID Return Value: Pointer to the name buffer. --*/ { // // Generate display name // // First use the comment, // if that's not available, use the host header name, // if that's not available, use the IP address:port. // If that's not available, use the instance number. // // CString strFmt; if (szComment && *szComment) { strName = szComment; } else if (szHostHeaderName && *szHostHeaderName) { strName = szHostHeaderName; } else { #ifndef _COMSTATIC HINSTANCE hOld = AfxGetResourceHandle(); AfxSetResourceHandle(GetModuleHandle(COMPROP_DLL_NAME)); #endif // _COMSTATIC if(!ia.IsZeroValue() && uPort != 0) { VERIFY(strFmt.LoadString(IDS_INSTANCE_PORT_FMT)); strName.Format(strFmt,(LPCTSTR)ia, uPort); } else { // VERIFY(strFmt.LoadString(IDS_INSTANCE_DEF_FMT)); // strName.Format(strFmt, szServiceName, dwID); if (0 == _tcscmp(szServiceName, _T("FTP"))) { VERIFY(strFmt.LoadString(IDS_INSTANCE_DEF_FMT_FTP)); } else if (0 == _tcscmp(szServiceName, _T("Web"))) { VERIFY(strFmt.LoadString(IDS_INSTANCE_DEF_FMT_WEB)); } strName.Format(strFmt, dwID); } #ifndef _COMSTATIC AfxSetResourceHandle(hOld); #endif // _COMSTATIC } return strName; } /* static */ void CInstanceProps::CrackBinding( IN CString strBinding, OUT CIPAddress & iaIpAddress, OUT UINT & nTCPPort, OUT CString & strDomainName ) /*++ Routine Description: Helper function to crack a binding string Arguments: CString strBinding : Binding string to be parsed CIPAddress & iaIpAddress : IP Address output UINT & nTCPPort : TCP Port CString & strDomainName : Domain (host) header name Return Value: None --*/ { // // Zero initialize // iaIpAddress.SetZeroValue(); nTCPPort = 0; strDomainName.Empty(); int iColonPos = strBinding.Find(_TCHAR(':')); if(iColonPos != -1) { // // Get the IP address // iaIpAddress = strBinding.Left(iColonPos); // // Look for the second colon // strBinding = strBinding.Mid(iColonPos + 1); iColonPos = strBinding.Find(_TCHAR(':')); } if(iColonPos != -1) { // // Get the port number // nTCPPort = ::_ttol(strBinding.Left(iColonPos)); // // Look for the NULL termination // strBinding = strBinding.Mid(iColonPos + 1); iColonPos = strBinding.Find(_TCHAR('\0')); } if(iColonPos != -1) { strDomainName = strBinding.Left(iColonPos); } } /* static */ void CInstanceProps::CrackSecureBinding( IN CString strBinding, OUT CIPAddress & iaIpAddress, OUT UINT & nSSLPort ) /*++ Routine Description: Helper function to crack a secure binding string Arguments: CString strBinding : Binding string to be parsed CIPAddress & iaIpAddress : IP Address output UINT & nSSLPort : SSL Port Return Value: None --*/ { // // Same as regular binding without domain name // CString strDomainName; CrackBinding(strBinding, iaIpAddress, nSSLPort, strDomainName); ASSERT(strDomainName.IsEmpty()); } /* static */ int CInstanceProps::FindMatchingSecurePort( IN CStringList & strlSecureBindings, IN CIPAddress & iaIPAddress, OUT UINT & nSSLPort ) /*++ Routine Description: Find the SSL port applicable to the given IP Address. Arguments: CStringList & strlSecureBindings : Input stringlist of secure bindings CIPAddress & iaIPAddress : IP Address to target UINT & nSSLPort : Returns the SSL Port Return Value: The index of the binding string, or -1 if not found. Notes: The SSL port will be set to 0, if the IP address does not exist. A 0.0.0.0 ip address translates to "All Unassigned". --*/ { nSSLPort = 0; int cItems = 0; POSITION pos = strlSecureBindings.GetHeadPosition(); while(pos) { CString & strBinding = strlSecureBindings.GetNext(pos); CIPAddress ia; UINT nPort; CrackSecureBinding(strBinding, ia, nPort); if (ia == iaIPAddress) { // // Found it! // nSSLPort = nPort; return cItems; } ++cItems; } // // Not found // return -1; } /* static */ BOOL CInstanceProps::IsPortInUse( IN CStringList & strlBindings, IN CIPAddress & iaIPAddress, IN UINT nPort ) /*++ Routine Description: Check to see if the give ip address/port combination is in use. Arguments: CStringList & strlBindings : Input stringlist of bindings CIPAddress & iaIpAddress : IP Address target UINT nPort : Port Return Value: TRUE if the given ip address/port combo is in use Notes: Host header name is ignored --*/ { POSITION pos = strlBindings.GetHeadPosition(); while(pos) { CString & strBinding = strlBindings.GetNext(pos); CIPAddress ia; UINT n; CString str; CrackBinding(strBinding, ia, n, str); if (ia == iaIPAddress && n == nPort) { // // Found it! // return TRUE; } } // // Not found // return FALSE; } /* static */ void CInstanceProps::BuildBinding( OUT CString & strBinding, IN CIPAddress & iaIpAddress, IN UINT & nTCPPort, IN CString & strDomainName ) /*++ Routine Description: Build up a binding string from its component parts Arguments: CString & strBinding : Output binding string CIPAddress & iaIpAddress : ip address (could be 0.0.0.0) UINT & nTCPPort : TCP Port CString & strDomainName : Domain name (host header) Return Value: None. --*/ { if (!iaIpAddress.IsZeroValue()) { strBinding.Format( _T("%s:%d:%s"), (LPCTSTR)iaIpAddress, nTCPPort, (LPCTSTR)strDomainName ); } else { // // Leave the ip address field blank // strBinding.Format(_T(":%d:%s"), nTCPPort, (LPCTSTR)strDomainName); } } /* static */ void CInstanceProps::BuildSecureBinding( OUT CString & strBinding, IN CIPAddress & iaIpAddress, IN UINT & nSSLPort ) /*++ Routine Description: Build up a binding string from its component parts Arguments: CString & strBinding : Output binding string CIPAddress & iaIpAddress : ip address (could be 0.0.0.0) UINT & nSSLPort : SSL Port Return Value: None. --*/ { CString strDomainName; BuildBinding(strBinding, iaIpAddress, nSSLPort, strDomainName); } CInstanceProps::CInstanceProps( IN LPCTSTR lpszServerName, IN LPCTSTR lpszService, // e.g. "W3SVC" IN DWORD dwInstance OPTIONAL, IN UINT nDefPort OPTIONAL ) /*++ Routine Description: Constructor for instance properties Arguments: LPCTSTR lpszServerName : Name of server LPCTSTR lpszService : Name of service (e.g. "W3SVC") DWORD dwInstance : Instance number (or MASTER_INSTANCE) Return Value: N/A --*/ : CMetaProperties(lpszServerName, lpszService, dwInstance), m_dwInstance(dwInstance), m_dwWin32Error(ERROR_SUCCESS), // // Default Instance Values // m_strlBindings(), m_strComment(), m_fNotDeletable(FALSE), m_fCluster(FALSE), m_nTCPPort(nDefPort), m_iaIpAddress(NULL_IP_ADDRESS), m_strDomainName(), m_dwState(MD_SERVER_STATE_STOPPED), m_nISMState(INetServiceUnknown) { // // Fetch just enough info for the enumeration // m_dwMDUserType = IIS_MD_UT_SERVER; } CInstanceProps::CInstanceProps( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, // e.g. "W3SVC" IN DWORD dwInstance OPTIONAL, IN UINT nDefPort OPTIONAL ) /*++ Routine Description: Constructor that uses an existing interface Arguments: CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Name of service (e.g. "W3SVC") DWORD dwInstance : Instance number (or MASTER_INSTANCE) Return Value: N/A --*/ : CMetaProperties(pInterface, lpszService, dwInstance), m_dwInstance(dwInstance), m_dwWin32Error(ERROR_SUCCESS), // // Default Instance Values // m_strlBindings(), m_strComment(), m_fNotDeletable(FALSE), m_fCluster(FALSE), m_nTCPPort(nDefPort), m_iaIpAddress((LONG)0), m_strDomainName(), m_dwState(MD_SERVER_STATE_STOPPED), m_nISMState(INetServiceUnknown) { // // Fetch enough for enumeration only // m_dwMDUserType = IIS_MD_UT_SERVER; } CInstanceProps::CInstanceProps( IN CMetaKey * pKey, IN DWORD dwInstance, IN UINT nDefPort OPTIONAL ) /*++ Routine Description: Read instance properties off an open key Arguments: CMetaKey * pKey : Open key DWORD dwInstance : Instance number UINT nDefPort : Default port number Return Value: N/A --*/ : CMetaProperties(pKey, dwInstance), m_dwInstance(dwInstance), m_dwWin32Error(ERROR_SUCCESS), // // Default Instance Values // m_strlBindings(), m_strComment(), m_fNotDeletable(FALSE), m_fCluster(FALSE), m_nTCPPort(nDefPort), m_iaIpAddress((LONG)0), m_strDomainName(), m_dwState(MD_SERVER_STATE_STOPPED), m_nISMState(INetServiceUnknown) { // // Fetch enough for enumeration only // m_dwMDUserType = IIS_MD_UT_SERVER; } void CInstanceProps::SetISMStateFromServerState() /*++ Routine Description: Translate server state to ISM state value Arguments: None. Return Value: None. --*/ { // // Derive Values // switch(m_dwState) { case MD_SERVER_STATE_STARTED: m_nISMState = INetServiceRunning; break; case MD_SERVER_STATE_STOPPED: m_nISMState = INetServiceStopped; break; case MD_SERVER_STATE_PAUSED: m_nISMState = INetServicePaused; break; case MD_SERVER_STATE_CONTINUING: default: m_nISMState = INetServiceUnknown; break; } } /* virtual */ void CInstanceProps::ParseFields() /*++ Routine Description: Break into fields. Arguments: None. Return Value: None. --*/ { BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData) HANDLE_META_RECORD(MD_SERVER_BINDINGS, m_strlBindings) HANDLE_META_RECORD(MD_SERVER_COMMENT, m_strComment) HANDLE_META_RECORD(MD_SERVER_STATE, m_dwState) HANDLE_META_RECORD(MD_WIN32_ERROR, m_dwWin32Error); HANDLE_META_RECORD(MD_NOT_DELETABLE, m_fNotDeletable); HANDLE_META_RECORD(MD_CLUSTER_ENABLED, m_fCluster); END_PARSE_META_RECORDS // // Crack the primary binding // if (MP_V(m_strlBindings).GetCount() > 0) { CString & strBinding = MP_V(m_strlBindings).GetHead(); CrackBinding(strBinding, m_iaIpAddress, m_nTCPPort, m_strDomainName); } SetISMStateFromServerState(); } /* virtual */ HRESULT CInstanceProps::WriteDirtyProps() /*++ Routine Description: Write the dirty properties to the metabase Arguments: None Return Value: HRESULT --*/ { CError err; BEGIN_META_WRITE() META_WRITE(MD_SERVER_BINDINGS, m_strlBindings) META_WRITE(MD_SERVER_COMMENT, m_strComment) META_WRITE(MD_SERVER_STATE, m_dwState) END_META_WRITE(err); return err; } HRESULT CInstanceProps::ChangeState( IN int nNewState ) /*++ Routine Description: Change the state of the instance Arguments: int nNewState : ISM service state value Return Value: HRESULT --*/ { DWORD dwTargetState; DWORD dwPendingState; DWORD dwCommand; CError err; switch(nNewState) { case INetServiceStopped: dwTargetState = MD_SERVER_STATE_STOPPED; dwPendingState = MD_SERVER_STATE_STOPPING; dwCommand = MD_SERVER_COMMAND_STOP; break; case INetServiceRunning: dwTargetState = MD_SERVER_STATE_STARTED; if (m_nISMState == INetServicePaused) { dwPendingState = MD_SERVER_STATE_CONTINUING; dwCommand = MD_SERVER_COMMAND_CONTINUE; } else { dwPendingState = MD_SERVER_STATE_STARTING; dwCommand = MD_SERVER_COMMAND_START; } break; case INetServicePaused: dwTargetState = MD_SERVER_STATE_PAUSED; dwPendingState = MD_SERVER_STATE_PAUSING; dwCommand = MD_SERVER_COMMAND_PAUSE; break; default: ASSERT(FALSE && "Invalid service state requested"); err = ERROR_INVALID_PARAMETER; } err = OpenForWriting(FALSE); if (err.Succeeded()) { err = SetValue(MD_SERVER_COMMAND, dwCommand); Close(); } if (err.Succeeded()) { // // Wait for the service to attain desired state, timeout // after specified interval // DWORD dwSleepTotal = 0L; DWORD dwOldState = m_dwState; if (dwOldState == dwTargetState) { // // Current state matches desired // state already. ISM must be behind // the times. // return err; } // // CODEWORK: Write a 0 win32error to the instance properties // prior to attempting to start the instance. // m_dwWin32Error = 0; while (dwSleepTotal < MAX_SLEEP_INST) { err = LoadData(); if (err.Failed()) { break; } if ((m_dwState != dwPendingState && m_dwState != dwOldState) || m_dwWin32Error != ERROR_SUCCESS ) { // // Done one way or another // if (m_dwState != dwTargetState) { // // Did not achieve desired result. Something went // wrong. // if (m_dwWin32Error) { err = m_dwWin32Error; } } break; } // // Still pending... // ::Sleep(SLEEP_INTERVAL); dwSleepTotal += SLEEP_INTERVAL; } if (dwSleepTotal >= MAX_SLEEP_INST) { // // Timed out. If there is a real error in the metabase // use it, otherwise use a generic timeout error // err = m_dwWin32Error; if (err.Succeeded()) { err = ERROR_SERVICE_REQUEST_TIMEOUT; } } // // Update state information // SetISMStateFromServerState(); } return err; } /* static */ HRESULT CInstanceProps::Add( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, IN LPCTSTR lpszHomePath, IN LPCTSTR lpszUserName, OPTIONAL IN LPCTSTR lpszPassword, OPTIONAL IN LPCTSTR lpszDescription, OPTIONAL IN LPCTSTR lpszBinding, OPTIONAL IN LPCTSTR lpszSecureBinding, OPTIONAL IN DWORD * pdwPermissions, OPTIONAL IN DWORD * pdwDirBrowsing, OPTIONAL IN DWORD * pwdAuthFlags, OPTIONAL OUT DWORD * pdwInstance OPTIONAL ) /*++ Routine Description: Create a new instance. Find a free instance number, and attempt to create it. Optionally return the new instance number. Arguments: const CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Service name LPCTSTR lpszHomePath : physical path for the new home directory LPCTSTR lpszUserName : User name LPCTSTR lpszPassword : Password LPCTSTR lpszDescription : Optional instance description. LPCTSTR lpszBinding : Binding string LPCTSTR lpszSecureBinding : Secure binding string DWORD * pdwPermission : Permission bits DWORD * pdwDirBrowsing : Directory browsing DWORD * pwdAuthFlags : Authorization flags DWORD * pdwInstance : Buffer to the new instance number Return Value: HRESULT --*/ { CMetaKey mk(pInterface, METADATA_PERMISSION_WRITE, lpszService); CError err(mk.QueryResult()); if (err.Failed()) { // // The service key MUST exist! // ASSERT(err.Win32Error() != ERROR_PATH_NOT_FOUND); return err; } // // Loop through until we find a free instance number. This // is not ideal, but the only way to do this for now. // CString strPath; LPTSTR lp = strPath.GetBuffer(MAX_INSTANCE_LEN); for (DWORD dw = FIRST_INSTANCE; dw <= LAST_INSTANCE; ++dw) { ::_ultot(dw, lp, 10); err = mk.DoesPathExist(lp); if (err.Failed()) { if (err.Win32Error() != ERROR_PATH_NOT_FOUND) { // // Unexpected error // return err; } // // Ok, now create it // strPath.ReleaseBuffer(); err = mk.AddKey(strPath); if (err.Succeeded()) { if (pdwInstance) { // // Store instance number // *pdwInstance = dw; } // // Write the key name (hack for beta 2) // CString strKeyName; CString strKeyDirName; if (!::lstrcmpi(lpszService, _T("w3svc"))) { strKeyName = _T("IIsWebServer"); strKeyDirName = _T("IIsWebVirtualDir"); } else if (!::lstrcmpi(lpszService, _T("msftpsvc"))) { strKeyName = _T("IIsFtpServer"); strKeyDirName = _T("IIsFtpVirtualDir"); } else { ASSERT(FALSE && "unrecognize service name"); } err = mk.SetValue( MD_KEY_TYPE, strKeyName, NULL, strPath ); // // Optionally write the description field // if (lpszDescription) { CString strDescription(lpszDescription); err = mk.SetValue( MD_SERVER_COMMENT, strDescription, NULL, strPath ); } // // The service binding // if (lpszBinding) { CString strBinding(lpszBinding); CStringListEx strlBindings; strlBindings.AddTail(strBinding); err = mk.SetValue( MD_SERVER_BINDINGS, strlBindings, NULL, strPath ); } // // The secure binding // if (lpszSecureBinding) { CString strBinding(lpszSecureBinding); CStringListEx strlBindings; strlBindings.AddTail(strBinding); err = mk.SetValue( MD_SECURE_BINDINGS, strlBindings, NULL, strPath ); } strPath += g_cszSep; strPath += g_cszRoot; // // Now add the home directory for it // err = mk.AddKey(strPath); if(err.Succeeded()) { CString strHomePath(lpszHomePath); err = mk.SetValue(MD_VR_PATH, strHomePath, NULL, strPath); err = mk.SetValue(MD_KEY_TYPE, strKeyDirName, NULL, strPath); if (pwdAuthFlags) { err = mk.SetValue( MD_AUTHORIZATION, *pwdAuthFlags, NULL, strPath ); } if (lpszUserName != NULL) { ASSERT(lpszPassword != NULL); CString strUserName(lpszUserName); err = mk.SetValue( MD_VR_USERNAME, strUserName, NULL, strPath ); } if (lpszPassword != NULL) { ASSERT(lpszUserName != NULL); CString strPassword(lpszPassword); err = mk.SetValue( MD_VR_PASSWORD, strPassword, NULL, strPath ); } if (pdwPermissions != NULL) { err = mk.SetValue( MD_ACCESS_PERM, *pdwPermissions, NULL, strPath ); } if (pdwDirBrowsing != NULL) { // // WWW only // err = mk.SetValue( MD_DIRECTORY_BROWSING, *pdwDirBrowsing, NULL, strPath ); } } } return err; } } // // 4 billion instances???!!!!! This error message // may not be ideal, but it will have to do for now. // return CError::HResult(ERROR_SHARING_BUFFER_EXCEEDED); } /* static */ HRESULT CInstanceProps::Delete( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, IN DWORD dwInstance ) /*++ Routine Description: Delete the given instance number Arguments: LPCTSTR lpszServer : Server name LPCTSTR lpszService : Service name (e.g. W3SVC) DWORD dwInstance : Instance number to be deleted Return Value: HRESULT --*/ { CMetaKey mk(pInterface, METADATA_PERMISSION_WRITE, lpszService); CError err(mk.QueryResult()); if (err.Failed()) { return err; } CString strPath; LPTSTR lp = strPath.GetBuffer(MAX_INSTANCE_LEN); ::_ltot(dwInstance, lp, 10); strPath.ReleaseBuffer(); err = mk.DeleteKey(strPath); return err; } // // Child node properties // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // // Redirect tags // const TCHAR CChildNodeProps::s_chTagSep = _T(','); const LPCTSTR CChildNodeProps::s_cszExactDestination = _T("EXACT_DESTINATION"); const LPCTSTR CChildNodeProps::s_cszChildOnly = _T("CHILD_ONLY"); const LPCTSTR CChildNodeProps::s_cszPermanent = _T("PERMANENT"); CChildNodeProps::CChildNodeProps( IN LPCTSTR lpszServerName, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParent, OPTIONAL IN LPCTSTR lpszAlias, OPTIONAL IN BOOL fInherit, OPTIONAL IN BOOL fPathOnly OPTIONAL ) /*++ Routine Description: Child node properties (Can be file, dir, or vdir) Arguments: LPCTSTR lpszServerName : Server name LPCTSTR lpszService : Service name DWORD dwInstance : Instance number (or MASTER INSTANCE) LPCTSTR lpszParent : Parent path (can be NULL or blank) LPCTSTR lpszAlias : Alias name (can be NULL or blank) BOOL fInherit : TRUE to inherit values, FALSE otherwise BOOL fPathOnly : TRUE to only fetch the path Return Value: N/A --*/ : CMetaProperties( lpszServerName, lpszService, dwInstance, lpszParent, lpszAlias ), m_strAlias(lpszAlias), m_strRedirectStatement(), m_strRedirectPath(), m_fExact(FALSE), m_fChild(FALSE), m_fPermanent(FALSE), m_dwAccessPerms(0L), m_dwDirBrowsing(0L), m_dwWin32Error(ERROR_SUCCESS), m_fIsAppRoot(FALSE), m_fAppIsolated(FALSE), // // Default properties // m_fPathInherited(FALSE), m_strPath() { if (fPathOnly) { // // Fetch only the homeroot physical path // m_dwMDUserType = IIS_MD_UT_FILE; m_dwMDDataType = STRING_METADATA; } m_strFullMetaPath = m_strMetaRoot; // // Override base parameters // m_fInherit = fInherit; } CChildNodeProps::CChildNodeProps( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParent, OPTIONAL IN LPCTSTR lpszAlias, OPTIONAL IN BOOL fInherit, OPTIONAL IN BOOL fPathOnly OPTIONAL ) /*++ Routine Description: Child node properties (Can be file, dir, or vdir) Arguments: CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Service name DWORD dwInstance : Instance number (or MASTER INSTANCE) LPCTSTR lpszParent : Parent path (can be NULL or blank) LPCTSTR lpszAlias : Alias name (can be NULL or blank) BOOL fInherit : TRUE to inherit values, FALSE otherwise BOOL fPathOnly : TRUE to only fetch the path Return Value: N/A --*/ : CMetaProperties( pInterface, lpszService, dwInstance, lpszParent, lpszAlias ), m_strAlias(lpszAlias), m_strRedirectStatement(), m_strRedirectPath(), m_fExact(FALSE), m_fChild(FALSE), m_fPermanent(FALSE), m_dwAccessPerms(0L), m_dwDirBrowsing(0L), m_dwWin32Error(ERROR_SUCCESS), m_fIsAppRoot(FALSE), m_fAppIsolated(FALSE), // // Default properties // m_fPathInherited(FALSE), m_strPath() { if (fPathOnly) { // // Fetch only the homeroot physical path // m_dwMDUserType = IIS_MD_UT_FILE; m_dwMDDataType = STRING_METADATA; } m_strFullMetaPath = m_strMetaRoot; // // Override base parameters // m_fInherit = fInherit; } CChildNodeProps::CChildNodeProps( IN const CMetaKey * pKey, IN LPCTSTR lpszPath, OPTIONAL IN BOOL fInherit, OPTIONAL IN BOOL fPathOnly OPTIONAL ) /*++ Routine Description: Construct from open key Arguments: const CMetaKey * pKey Open key LPCTSTR lpszPath Path BOOL fInherit TRUE to inherit properties BOOL fPathOnly TRUE to only fetch the path Return Value: N/A --*/ : CMetaProperties(pKey, lpszPath), m_strAlias(lpszPath), // ISSUE: Could be more than a node name m_strRedirectStatement(), m_strRedirectPath(), m_fExact(FALSE), m_fChild(FALSE), m_fPermanent(FALSE), m_dwAccessPerms(0L), m_dwDirBrowsing(0L), m_dwWin32Error(ERROR_SUCCESS), m_fIsAppRoot(FALSE), m_fAppIsolated(FALSE), // // Default properties // m_fPathInherited(FALSE), m_strPath() { if (fPathOnly) { m_dwMDUserType = IIS_MD_UT_FILE; m_dwMDDataType = STRING_METADATA; } else { // // Build full metabase path, because we need to compare it // against the app root path // m_strFullMetaPath = pKey->QueryMetaPath(); if (lpszPath && *lpszPath) { m_strFullMetaPath += SZ_MBN_SEP_STR; m_strFullMetaPath += lpszPath; } } // // Override base parameters // m_fInherit = fInherit; } void CChildNodeProps::ParseRedirectStatement() /*++ Routine Description: Break down the redirect statement into its component parts (path plus directives) Arguments: None Return Value: None --*/ { m_fExact = FALSE; m_fChild = FALSE; m_fPermanent = FALSE; m_strRedirectPath = m_strRedirectStatement; int nComma = m_strRedirectPath.Find(s_chTagSep); if (nComma >= 0) { // // Check past the separator for these tags // LPCTSTR lpstr = m_strRedirectPath; lpstr += (nComma + 1); m_fExact = _tcsstr(lpstr, s_cszExactDestination) != NULL; m_fChild = _tcsstr(lpstr, s_cszChildOnly) != NULL; m_fPermanent = _tcsstr(lpstr, s_cszPermanent) != NULL; m_strRedirectPath.ReleaseBuffer(nComma); } } void CChildNodeProps::BuildRedirectStatement() /*++ Routine Description: Assemble the redirect statement from its component parts (path plus directives) Arguments: None Return Value: None --*/ { CString strStatement = m_strRedirectPath; ASSERT(strStatement.Find(s_chTagSep) < 0); if (m_fExact) { strStatement += s_chTagSep; strStatement += _T(' '); strStatement += s_cszExactDestination; } if (m_fChild) { strStatement += s_chTagSep; strStatement += _T(' '); strStatement += s_cszChildOnly; } if (m_fPermanent) { strStatement += s_chTagSep; strStatement += _T(' '); strStatement += s_cszPermanent; } m_strRedirectStatement = strStatement; } /* virtual */ void CChildNodeProps::ParseFields() /*++ Routine Description: Break into fields. Arguments: None. Return Value: None. --*/ { BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData) HANDLE_INHERITED_META_RECORD(MD_VR_PATH, m_strPath, m_fPathInherited) HANDLE_META_RECORD(MD_HTTP_REDIRECT, m_strRedirectStatement) HANDLE_META_RECORD(MD_WIN32_ERROR, m_dwWin32Error) HANDLE_META_RECORD(MD_ACCESS_PERM, m_dwAccessPerms) HANDLE_META_RECORD(MD_DIRECTORY_BROWSING, m_dwDirBrowsing) HANDLE_META_RECORD(MD_APP_ROOT, m_strAppRoot) HANDLE_META_RECORD(MD_APP_ISOLATED, m_fAppIsolated) END_PARSE_META_RECORDS // // Check to see if this is an application root // if (!MP_V(m_strAppRoot).IsEmpty()) { TRACEEOLID("App root: " << m_strAppRoot); // // CODEWORK: It's faster to set our app root to the path // that WAM expects than to strip off each instance. // // // Clean App root // if (MP_V(m_strAppRoot)[MP_V(m_strAppRoot).GetLength() - 1] == _T('/')) { MP_V(m_strAppRoot).ReleaseBuffer( MP_V(m_strAppRoot).GetLength() - 1 ); } if (MP_V(m_strAppRoot)[0] == _T('/')) { MP_V(m_strAppRoot) = MP_V(m_strAppRoot).Right( MP_V(m_strAppRoot).GetLength() - 1 ); } m_fIsAppRoot = m_strFullMetaPath.CompareNoCase(m_strAppRoot) == 0; } // // Break down redirect statement into component parts // ParseRedirectStatement(); } /* virtual */ HRESULT CChildNodeProps::WriteDirtyProps() /*++ Routine Description: Write the dirty properties to the metabase Arguments: None Return Value: HRESULT --*/ { CError err; BEGIN_META_WRITE() META_WRITE(MD_VR_PATH, m_strPath) META_WRITE(MD_ACCESS_PERM, m_dwAccessPerms) META_WRITE(MD_DIRECTORY_BROWSING, m_dwDirBrowsing) if (IsRedirected()) { // // (Re-)Assemble the redirect statement from its component parts // BuildRedirectStatement(); META_WRITE_INHERITANCE(MD_HTTP_REDIRECT, m_strRedirectStatement, m_fInheritRedirect) } else { META_DELETE(MD_HTTP_REDIRECT) } END_META_WRITE(err); return err; } /* static */ HRESULT CChildNodeProps::Add( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParentPath, OPTIONAL IN LPCTSTR lpszAlias, OUT CString & strAliasCreated, IN DWORD * pdwPermissions, OPTIONAL IN DWORD * pdwDirBrowsing, OPTIONAL IN LPCTSTR lpszVrPath, OPTIONAL IN LPCTSTR lpszUserName, OPTIONAL IN LPCTSTR lpszPassword, OPTIONAL IN BOOL fExactName ) /*++ Routine Description: Create new child node. Optionally, this will append a number to the alias name to ensure uniqueness Arguments: const CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Service name DWORD dwInstance : Instance number (could be MASTER_INSTANCE) LPCTSTR lpszParentPath : Parent path (could be NULL) LPCTSTR lpszAlias : Desired alias name CString & strAliasCreated : Alias created (may differ) DWORD * pdwPermissions : Permissions DWORD * pdwDirBrowsing : Directory browsing LPCTSTR lpszVrPath : VrPath property LPCTSTR lpszUserName : User name LPCTSTR lpszPassword : Password BOOL fExactName : If TRUE, do not change the name to enforce uniqueness. Return Value: HRESULT --*/ { CMetaKey mk(pInterface); CError err(mk.QueryResult()); if (err.Failed()) { // // Hopeless... // return err; } BOOL fNewPath; do { fNewPath = FALSE; err = mk.Open( METADATA_PERMISSION_WRITE, lpszService, dwInstance, lpszParentPath ); if (err.Win32Error() == ERROR_PATH_NOT_FOUND) { // // This could happen -- creating a virtual // server underneath a physical directory // which does not exist in the metabase // err = mk.Open( METADATA_PERMISSION_WRITE, lpszService, dwInstance ); if (err.Failed()) { // // This really should never fail, because we're opening // the path at the instance. // TRACEEOLID("Instance path does not exist"); ASSERT(FALSE); break; } err = mk.AddKey(lpszParentPath); fNewPath = err.Succeeded(); mk.Close(); } } while(fNewPath); if (err.Failed()) { return err; } strAliasCreated = lpszAlias; DWORD dw = 2; FOREVER { // // Append a number if the name is not unique. // err = mk.DoesPathExist(strAliasCreated); if (err.Failed()) { if (err.Win32Error() != ERROR_PATH_NOT_FOUND) { // // Unexpected error // return err; } // // Ok, now create it // err = mk.AddKey(strAliasCreated); if (err.Succeeded()) { // // Write the ADSI key name (hack for beta 2) // CString strKeyName; if (!::lstrcmpi(lpszService, _T("w3svc"))) { strKeyName = _T("IIsWebVirtualDir"); } else if (!::lstrcmpi(lpszService, _T("msftpsvc"))) { strKeyName = _T("IIsFtpVirtualDir"); } else { ASSERT(FALSE && "unrecognize service name"); } err = mk.SetValue( MD_KEY_TYPE, strKeyName, NULL, strAliasCreated ); if (lpszVrPath != NULL) { CString strVrPath(lpszVrPath); err = mk.SetValue( MD_VR_PATH, strVrPath, NULL, strAliasCreated ); } if (lpszUserName != NULL) { ASSERT(lpszPassword != NULL); CString strUserName(lpszUserName); err = mk.SetValue( MD_VR_USERNAME, strUserName, NULL, strAliasCreated ); } if (lpszPassword != NULL) { ASSERT(lpszUserName != NULL); CString strPassword(lpszPassword); err = mk.SetValue( MD_VR_PASSWORD, strPassword, NULL, strAliasCreated ); } if (pdwPermissions != NULL) { err = mk.SetValue( MD_ACCESS_PERM, *pdwPermissions, NULL, strAliasCreated ); } if (pdwDirBrowsing != NULL) { // // WWW only // err = mk.SetValue( MD_DIRECTORY_BROWSING, *pdwDirBrowsing, NULL, strAliasCreated ); } } return err; } // // Name is not unique, increase the number and try // again if permitted to so. Otherwise return the // 'path exists' error. // if (fExactName) { err = ERROR_ALREADY_EXISTS; return err; } TCHAR szNumber[32]; ::_ultot(dw++, szNumber, 10); strAliasCreated = lpszAlias; strAliasCreated += szNumber; // // Continue on... // } } /* static */ HRESULT CChildNodeProps::Delete( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParentPath, OPTIONAL IN LPCTSTR lpszNode ) /*++ Routine Description: Delete child node off the given parent path Arguments: const CMetaInterface * pInterface, Existing interface LPCTSTR lpszService : Service name DWORD dwInstance : Instance number (could be MASTER_INSTANCE) LPCTSTR lpszParentPath : Parent path (could be NULL) LPCTSTR lpszNode : Name of node to be deleted Return Value: HRESULT --*/ { CMetaKey mk( pInterface, METADATA_PERMISSION_WRITE, lpszService, dwInstance, lpszParentPath ); CError err(mk.QueryResult()); if (err.Failed()) { return err; } err = mk.DeleteKey(lpszNode); return err; } /* static */ HRESULT CChildNodeProps::Rename( IN const CMetaInterface * pInterface, IN LPCTSTR lpszService, IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParentPath, OPTIONAL IN LPCTSTR lpszOldName, IN LPCTSTR lpszNewName ) /*++ Routine Description: Rename a child node off the given path Arguments: IN const CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Service name DWORD dwInstance : Instance number (could be MASTER_INSTANCE) LPCTSTR lpszParentPath : Parent path (could be NULL) LPCTSTR lpszOldName : Old node name LPCTSTR lpszNewName : New node name Return Value: HRESULT --*/ { CMetaKey mk( pInterface, METADATA_PERMISSION_WRITE, lpszService, dwInstance, lpszParentPath ); CError err(mk.QueryResult()); if (err.Failed()) { return err; } err = mk.RenameKey(lpszOldName, lpszNewName); return err; } // // ISM Helpers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HRESULT COMDLL_RebindInterface( OUT IN CMetaInterface * pInterface, OUT BOOL * pfContinue, IN DWORD dwCancelError ) /*++ Routine Description: Rebind the interface Arguments: CMetaInterface * pInterface : Interface to rebind BOOL * pfContinue : Returns TRUE to continue. DWORD dwCancelError : Return code on cancel Return Value: HRESULT --*/ { CError err; CString str, strFmt; ASSERT(pInterface != NULL); ASSERT(pfContinue != NULL); VERIFY(strFmt.LoadString(IDS_RECONNECT_WARNING)); str.Format(strFmt, (LPCTSTR)pInterface->QueryServerName()); if (*pfContinue = (YesNoMessageBox(str))) { // // Attempt to rebind the handle // err = pInterface->Regenerate(); } else { // // Do not return an error in this case. // err = dwCancelError; } return err; } HRESULT COMDLL_ISMEnumerateInstances( IN CMetaInterface * pInterface, OUT ISMINSTANCEINFO * pii, OUT IN HANDLE * phEnum, IN LPCTSTR lpszService ) /*++ Routine Description: Enumerate Instances. First call with *phEnum == NULL. Arguments: CMetaInterface * pInterface : Existing interface ISMINSTANCEINFO * pii : Buffer HANDLE * phEnum : Enumeration handle. LPCTSTR lpszService : Service name Return Value: HRESULT --*/ { ASSERT(pii != NULL); ASSERT(phEnum != NULL); ASSERT(pii->dwSize == ISMINSTANCEINFO_SIZE); ASSERT(pInterface != NULL); CMetaEnumerator * pme = (CMetaEnumerator *)*phEnum; if (pme == NULL) { // // Starting enumeration // pme = new CMetaEnumerator(pInterface, lpszService); } if (pme == NULL) { return CError::HResult(ERROR_NOT_ENOUGH_MEMORY); } CError err(pme->QueryResult()); if (err.Win32Error() == ERROR_PATH_NOT_FOUND) { // // Base path didn't exist // err = ERROR_NO_MORE_ITEMS; } CString strHome; if (err.Succeeded()) { DWORD dwInstance; err = pme->Next(dwInstance); if (err.Succeeded()) { // // Read off the open key // CInstanceProps inst(pme, dwInstance); err = inst.LoadData(); DWORD dwWin32Error = err; if (err.Win32Error() == ERROR_ACCESS_DENIED) { err.Reset(); } if (err.Succeeded()) { inst.FillInstanceInfo(pii, dwWin32Error); inst.GetHomePath(strHome); TRACEEOLID(strHome); // // Get home directory path // CChildNodeProps home( pme, strHome, WITHOUT_INHERITANCE, TRUE // Path only ); err = home.LoadData(); if (err.Win32Error() == ERROR_ACCESS_DENIED) { err.Reset(); } if (err.Succeeded()) { home.FillInstanceInfo(pii); } } } } if (err.Win32Error() == ERROR_NO_MORE_ITEMS || err.Win32Error() == RPC_S_SERVER_UNAVAILABLE) { // // Finished the enumerator // delete pme; pme = NULL; } *phEnum = (HANDLE)pme; return err; } HRESULT COMDLL_ISMEnumerateChildren( IN CMetaInterface * pInterface, OUT ISMCHILDINFO * pii, OUT IN HANDLE * phEnum, IN LPCTSTR lpszService, IN DWORD dwInstance, IN LPCTSTR lpszParent ) /*++ Routine Description: Enumerate children. First call with *phEnum == NULL. Arguments: CMetaInterface * pInterface : Existing interface ISMCHILDINFO * pii : Buffer HANDLE * phEnum : Enumeration handle. LPCTSTR lpszService : Service name DWORD dwInstance : Instance number LPCTSTR lpszParent : Parent path Return Value: HRESULT --*/ { ASSERT(pii != NULL); ASSERT(phEnum != NULL); ASSERT(pii->dwSize == ISMCHILDINFO_SIZE); ASSERT(pInterface != NULL); BOOL fDone = FALSE; CMetaEnumerator * pme = (CMetaEnumerator *)*phEnum; if (pme == NULL) { // // Starting enumeration // pme = new CMetaEnumerator( pInterface, lpszService, dwInstance, lpszParent ); } if (pme == NULL) { return CError::HResult(ERROR_NOT_ENOUGH_MEMORY); } CError err(pme->QueryResult()); if (err.Win32Error() == ERROR_PATH_NOT_FOUND) { err = ERROR_NO_MORE_ITEMS; } if (err.Succeeded()) { do { CString strAlias; err = pme->Next(strAlias); if (err.Succeeded()) { CChildNodeProps child(pme, strAlias, WITH_INHERITANCE, FALSE); err = child.LoadData(); DWORD dwWin32Error = err.Win32Error(); if (err.Failed()) { // // Filter out the non-fatal errors // switch(err.Win32Error()) { case ERROR_ACCESS_DENIED: case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: err.Reset(); break; default: TRACEEOLID("Fatal error occurred " << err); } } if (err.Succeeded()) { // // Skip non-virtual directories (that is, those with // inherited vrpaths) // if (!child.IsPathInherited()) { // // Fetch error overrides stored error value // child.FillChildInfo(pii); fDone = TRUE; } } } } while (err.Succeeded() && !fDone); } if (err.Win32Error() == ERROR_NO_MORE_ITEMS || err.Win32Error() == RPC_S_SERVER_UNAVAILABLE) { // // Finished the enumerator // delete pme; pme = NULL; } *phEnum = (HANDLE)pme; return err; } DWORD DetermineIfAdministrator( IN CMetaInterface * pInterface, IN LPCTSTR lpszService, IN DWORD dwInstance, OUT BOOL* pfAdministrator ) /*++ Routine Description: Attempt to actually resolve whether or not the current user has administrator or merely "operator" access. Until this method is called by the derived class, the user is assumed to have full administrator access, and may therefore get "access denied" errors in inconvenient places. The method to determine admin access is rather poor at the moment. There's a dummy metabase property that only allows admins to write to it, so we try to write to it to see if we're an admin. Arguments: LPCTSTR lpszService : Service name. e.g. "w3svc" DWORD dwInstance : Instance number Return Value: Error return code. This will also set the m_fHasAdminAccess member --*/ { *pfAdministrator = FALSE; // // Reuse existing interface we have lying around. // CMetaKey mk(pInterface); CError err(mk.QueryResult()); if (err.Succeeded()) { err = mk.Open( METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, lpszService, dwInstance ); if (err.Succeeded()) { // // Write some nonsense // DWORD dwDummy = 0x1234; err = mk.SetValue(MD_ISM_ACCESS_CHECK, dwDummy); mk.Close(); } } ASSERT(err.Succeeded() || err.Win32Error() == ERROR_ACCESS_DENIED); *pfAdministrator = (err.Succeeded()); #ifdef _DEBUG if (*pfAdministrator) { TRACEEOLID("You are a full admin."); } else { TRACEEOLID("You're just a lowly operator at best. Error code is " << err); } #endif // _DEBUG if (err.Win32Error() == ERROR_ACCESS_DENIED) { // // Expected result // err.Reset(); } return err.Win32Error(); } IMPLEMENT_DYNAMIC(CInetPropertySheet, CPropertySheet) CInetPropertySheet::CInetPropertySheet( IN UINT nIDCaption, IN LPCTSTR lpszServer, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParent, OPTIONAL IN LPCTSTR lpszAlias, OPTIONAL IN CWnd * pParentWnd, OPTIONAL IN LPARAM lParam, OPTIONAL IN LONG_PTR handle, OPTIONAL IN UINT iSelectPage OPTIONAL ) /*++ Routine Description: IIS Property Sheet constructor Arguments: UINT nIDCaption : Caption resource string LPCTSTR lpszServer : Server name LPCTSTR lpszService : Service name DWORD dwInstance : Instance number LPCTSTR lpszParent : Parent path LPCTSTR lpszAlias : Alias name CWnd * pParentWnd : Optional parent window LPARAM lParam : MMC Console parameter LONG_PTR handle : MMC Console handle UINT iSelectPage : Initial page to be selected Return Value: N/A --*/ : CPropertySheet(nIDCaption, pParentWnd, iSelectPage), m_cap(lpszServer, lpszService, dwInstance), m_strServer(lpszServer), m_strService(lpszService), m_dwInstance(dwInstance), m_strParent(lpszParent), m_strAlias(lpszAlias), m_bModeless(FALSE), m_hConsole(handle), m_lParam(lParam), m_fHasAdminAccess(TRUE), // assumed by default m_refcount(0) { m_cap.LoadData(); Initialize(); } CInetPropertySheet::CInetPropertySheet( IN LPCTSTR lpszCaption, IN LPCTSTR lpszServer, IN LPCTSTR lpszService, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParent, OPTIONAL IN LPCTSTR lpszAlias, OPTIONAL IN CWnd * pParentWnd, OPTIONAL IN LPARAM lParam, OPTIONAL IN LONG_PTR handle, OPTIONAL IN UINT iSelectPage OPTIONAL ) /*++ Routine Description: IIS Property Sheet constructor Arguments: UINT nIDCaption : Caption resource string LPCTSTR lpszServer : Server name LPCTSTR lpszService : Service name DWORD dwInstance : Instance number LPCTSTR lpszParent : Parent path LPCTSTR lpszAlias : Alias name CWnd * pParentWnd : Optional parent window LPARAM lParam : MMC Console parameter LONG_PTR handle : MMC Console handle UINT iSelectPage : Initial page to be selected Return Value: N/A --*/ : CPropertySheet(lpszCaption, pParentWnd, iSelectPage), m_cap(lpszServer, lpszService, dwInstance), m_strServer(lpszServer), m_strService(lpszService), m_dwInstance(dwInstance), m_strParent(lpszParent), m_strAlias(lpszAlias), m_bModeless(FALSE), m_hConsole(handle), m_lParam(lParam), m_fHasAdminAccess(TRUE), // assumed by default m_refcount(0) { m_cap.LoadData(); Initialize(); } void CInetPropertySheet::NotifyMMC() /*++ Routine Description: Notify MMC that changes have been made, so that the changes are reflected. Arguments: None Return Value: None --*/ { // // Notify MMC to update changes. // if (m_hConsole != NULL) { ASSERT(m_lParam != 0L); MMCPropertyChangeNotify(m_hConsole, m_lParam); } } CInetPropertySheet::~CInetPropertySheet() /*++ Routine Description: IIS Property Sheet destructor Arguments: N/A Return Value: N/A --*/ { NotifyMMC(); if (m_hConsole != NULL) { MMCFreeNotifyHandle(m_hConsole); } } void CInetPropertySheet::Initialize() /*++ Routine Description: Initialize the sheet information by finding out information about the computer being administered. Arguments: None Return Value: None --*/ { m_fLocal = ::IsServerLocal(m_strServer); DWORD dwError = DetermineAdminAccess(m_strService, m_dwInstance); ASSERT(dwError == ERROR_SUCCESS); } void CInetPropertySheet::AddRef() /*++ Routine Description: Increase the refcount Arguments: None Return Value: None --*/ { ++m_refcount; } void CInetPropertySheet::Release() /*++ Routine Description: Decrease the ref count, and if 0, delete the object Arguments: None Return Value: None --*/ { if (--m_refcount <= 0) { delete this; } } void CInetPropertySheet::WinHelp( IN DWORD dwData, IN UINT nCmd ) /*++ Routine Description: WinHelp override. We can't use the base class, because our 'sheet' doesn't have a window handle Arguments: DWORD dwData : Help data UINT nCmd : Help command Return Value: None --*/ { if (m_hWnd == NULL) { // // Special case // CWnd * pWnd = ::AfxGetMainWnd(); if (pWnd != NULL) { pWnd->WinHelp(dwData, nCmd); } return; } CPropertySheet::WinHelp(dwData, nCmd); } // // Message Map // BEGIN_MESSAGE_MAP(CInetPropertySheet, CPropertySheet) //{{AFX_MSG_MAP(CInetPropertySheet) //}}AFX_MSG_MAP END_MESSAGE_MAP() // // CInetPropertyPage property page // IMPLEMENT_DYNAMIC(CInetPropertyPage, CPropertyPage) /* static */ UINT CALLBACK CInetPropertyPage::PropSheetPageProc( IN HWND hWnd, IN UINT uMsg, IN LPPROPSHEETPAGE ppsp ) /*++ Routine Description: Property page callback procedure. The page is allocated on the heap, and deletes itself when it's destroyed. Arguments: HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp Return Value: Message dependent. --*/ { CInetPropertyPage * pThis = (CInetPropertyPage *)ppsp->lParam; switch(uMsg) { case PSPCB_RELEASE: if (--(pThis->m_refcount) <= 0) { // // Save callback on the stack, since 'this' will be deleted. // LPFNPSPCALLBACK pfn = pThis->m_pfnOriginalPropSheetPageProc; delete pThis; return (pfn)(hWnd, uMsg, ppsp); } break; case PSPCB_CREATE: // // Don't increase refcount. // default: break; } return (pThis->m_pfnOriginalPropSheetPageProc)(hWnd, uMsg, ppsp); } #ifdef _DEBUG /* virtual */ void CInetPropertyPage::AssertValid() const { } /* virtual */ void CInetPropertyPage::Dump(CDumpContext& dc) const { } #endif // _DEBUG CInetPropertyPage::CInetPropertyPage( IN UINT nIDTemplate, IN CInetPropertySheet * pSheet, IN UINT nIDCaption, IN BOOL fEnableEnhancedFonts OPTIONAL ) /*++ Routine Description: IIS Property Page Constructor Arguments: UINT nIDTemplate : Resource template CInetPropertySheet * pSheet : Associated property sheet UINT nIDCaption : Caption ID BOOL fEnableEnhancedFonts : Enable enhanced fonts Return Value: N/A --*/ : CPropertyPage(nIDTemplate, nIDCaption), m_nHelpContext(nIDTemplate + 0x20000), m_fEnableEnhancedFonts(fEnableEnhancedFonts), m_refcount(1), m_bChanged(FALSE), m_pSheet(pSheet) { //{{AFX_DATA_INIT(CInetPropertyPage) //}}AFX_DATA_INIT m_pfnOriginalPropSheetPageProc = m_psp.pfnCallback; m_psp.lParam = (LPARAM)this; m_psp.pfnCallback = CInetPropertyPage::PropSheetPageProc; m_psp.dwFlags |= (PSP_HASHELP | PSP_USECALLBACK); m_pSheet->AddRef(); ASSERT(m_pSheet != NULL); } CInetPropertyPage::~CInetPropertyPage() /*++ Routine Description: IIS Property Page Destructor Arguments: N/A Return Value: N/A --*/ { m_pSheet->Release(); } void CInetPropertyPage::DoDataExchange( IN CDataExchange * pDX ) /*++ Routine Description: Initialise/Store control data Arguments: CDataExchange * pDX - DDX/DDV control structure Return Value: None --*/ { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CInetPropertyPage) //}}AFX_DATA_MAP } // // Message Map // BEGIN_MESSAGE_MAP(CInetPropertyPage, CPropertyPage) //{{AFX_MSG_MAP(CInetPropertyPage) ON_COMMAND(ID_HELP, OnHelp) ON_WM_HELPINFO() //}}AFX_MSG_MAP END_MESSAGE_MAP() // // Message Handlers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* virtual */ BOOL CInetPropertyPage::OnInitDialog() /*++ Routine Description: WM_INITDIALOG handler. Initialize the dialog. Reset changed status (sometimes gets set by e.g. spinboxes when the dialog is constructed), so make sure the dialog is considered clean. Arguments: None Return Value: TRUE if no focus is to be set automatically, FALSE if the focus is already set. --*/ { m_bChanged = FALSE; // // Tell derived class to load its configuration parameters // CError err(LoadConfigurationParameters()); if (err.Succeeded()) { err = FetchLoadedValues(); } BOOL bResult = CPropertyPage::OnInitDialog(); err.MessageBoxOnFailure(); if (m_fEnableEnhancedFonts) { CFont * pFont = &m_fontBold; if (CreateSpecialDialogFont(this, pFont)) { ApplyFontToControls(this, pFont, IDC_ED_BOLD1, IDC_ED_BOLD5); } } return bResult; } void CInetPropertyPage::OnHelp() /*++ Routine Description: 'Help' button handler Arguments: None Return Value: None --*/ { m_pSheet->WinHelp(m_nHelpContext); } BOOL CInetPropertyPage::OnHelpInfo( IN HELPINFO * pHelpInfo ) /*++ Routine Description: Eat "help info" command Arguments: None Return Value: None --*/ { OnHelp(); return TRUE; } BOOL CInetPropertyPage::OnApply() /*++ Routine Description: Handle "OK" or "APPLY". Call the derived class to save its stuff, and set the dirty state depending on whether saving succeeded or failed. Arguments: None Return Value: None --*/ { BOOL bSuccess = TRUE; if (IsDirty()) { CError err(SaveInfo()); if (err.MessageBoxOnFailure()) { // // Failed, sheet will not be dismissed. // // CODEWORK: This page should be activated. // bSuccess = FALSE; } SetModified(!bSuccess); } return bSuccess; } void CInetPropertyPage::SetModified( IN BOOL bChanged ) /*++ Routine Description: Keep private check on dirty state of the property page. Arguments: BOOL bChanged : Dirty flag Return Value: None --*/ { CPropertyPage::SetModified(bChanged); m_bChanged = bChanged; } #ifndef _COMSTATIC static AFX_EXTENSION_MODULE extensionDLL = {NULL, NULL}; extern "C" int APIENTRY DllMain( IN HINSTANCE hInstance, IN DWORD dwReason, IN LPVOID lpReserved ) /*++ Routine Description: DLL Main entry point Arguments: HINSTANCE hInstance : Instance handle DWORD dwReason : DLL_PROCESS_ATTACH, etc LPVOID lpReserved : Reserved value Return Value: 1 for succesful initialisation, 0 for failed initialisation --*/ { switch (dwReason) { case DLL_PROCESS_ATTACH: ASSERT(hInstance != NULL); hDLLInstance = hInstance; if (!::AfxInitExtensionModule(extensionDLL, hInstance) || !InitIntlSettings() || !InitErrorFunctionality() ) { return 0; } break ; case DLL_PROCESS_DETACH: // // termination // TerminateIntlSettings(); TerminateErrorFunctionality(); ::AfxTermExtensionModule(extensionDLL); break; } // // Succes loading the DLL // return 1; } extern "C" void WINAPI InitIISUIDll() /*++ Routine Description: Initialize the DLL Arguments: None Return Value: None --*/ { new CDynLinkLibrary(extensionDLL); hDLLInstance = extensionDLL.hResource; } #endif // _COMSTATIC