#include "stdafx.h" #include "userenv.h" #include "userenvp.h" #include "shlobj.h" #include "utils.h" #include "mddefw.h" #include "mdkey.h" #include "wizpages.h" #include "ocmanage.h" #include "setupapi.h" #include "k2suite.h" extern OCMANAGER_ROUTINES gHelperRoutines; DWORD GetUnattendedMode(HANDLE hUnattended, LPCTSTR szSubcomponent) { BOOL b = FALSE; TCHAR szLine[1024]; DWORD dwMode = SubcompUseOcManagerDefault; CString csMsg; csMsg = _T("GetUnattendedMode "); csMsg += szSubcomponent; csMsg += _T("\n"); DebugOutput((LPCTSTR)csMsg); // Try to get the line of interest if (hUnattended && (hUnattended != INVALID_HANDLE_VALUE)) { b = SetupGetLineText(NULL, hUnattended, _T("Components"), szSubcomponent, szLine, sizeof(szLine)/sizeof(szLine[0]), NULL); if (b) { csMsg = szSubcomponent; csMsg += _T(" = "); csMsg += szLine; csMsg += _T("\n"); DebugOutput((LPCTSTR)csMsg); // Parse the line if (!lstrcmpi(szLine, _T("on"))) { dwMode = SubcompOn; } else if (!lstrcmpi(szLine, _T("off"))) { dwMode = SubcompOff; } else if (!lstrcmpi(szLine, _T("default"))) { dwMode = SubcompUseOcManagerDefault; } } else DebugOutput(_T("SetupGetLineText failed.")); } return(dwMode); } DWORD GetUnattendedModeFromSetupMode( HANDLE hUnattended, DWORD dwComponent, LPCTSTR szSubcomponent) { BOOL b = FALSE; TCHAR szProperty[64]; TCHAR szLine[1024]; DWORD dwMode = SubcompUseOcManagerDefault; DWORD dwSetupMode; DebugOutput(_T("GetUnattendedModeFromSetupMode %s"), szSubcomponent); // Try to get the line of interest if (hUnattended && (hUnattended != INVALID_HANDLE_VALUE)) { dwSetupMode = GetIMSSetupMode(); switch (dwSetupMode) { case IIS_SETUPMODE_MINIMUM: case IIS_SETUPMODE_TYPICAL: case IIS_SETUPMODE_CUSTOM: // One of the fresh modes lstrcpy(szProperty, _T("FreshMode")); break; case IIS_SETUPMODE_UPGRADEONLY: case IIS_SETUPMODE_ADDEXTRACOMPS: // One of the upgrade modes lstrcpy(szProperty, _T("UpgradeMode")); break; case IIS_SETUPMODE_ADDREMOVE: case IIS_SETUPMODE_REINSTALL: case IIS_SETUPMODE_REMOVEALL: // One of the maintenance modes lstrcpy(szProperty, _T("MaintenanceMode")); break; default: // Error! Use defaults return(SubcompUseOcManagerDefault); } // Get the specified line b = SetupGetLineText( NULL, hUnattended, _T("Global"), szProperty, szLine, sizeof(szLine)/sizeof(szLine[0]), NULL); if (b) { DWORD dwOriginalMode; DebugOutput(_T("%s = %s"), szProperty, szLine); // See which setup mode we will end up with if (!lstrcmpi(szLine, _T("Minimal"))) dwSetupMode = IIS_SETUPMODE_MINIMUM; else if (!lstrcmpi(szLine, _T("Typical"))) dwSetupMode = IIS_SETUPMODE_TYPICAL; else if (!lstrcmpi(szLine, _T("Custom"))) dwSetupMode = IIS_SETUPMODE_CUSTOM; else if (!lstrcmpi(szLine, _T("AddRemove"))) dwSetupMode = IIS_SETUPMODE_ADDREMOVE; else if (!lstrcmpi(szLine, _T("RemoveAll"))) dwSetupMode = IIS_SETUPMODE_REMOVEALL; else if (!lstrcmpi(szLine, _T("UpgradeOnly"))) dwSetupMode = IIS_SETUPMODE_UPGRADEONLY; else if (!lstrcmpi(szLine, _T("AddExtraComps"))) dwSetupMode = IIS_SETUPMODE_ADDEXTRACOMPS; else return(SubcompUseOcManagerDefault); // Get the custom unattended setting dwMode = GetUnattendedMode(hUnattended, szSubcomponent); // Do the right thing based on the setup mode SetIMSSetupMode(dwSetupMode); switch (dwSetupMode) { case IIS_SETUPMODE_MINIMUM: case IIS_SETUPMODE_TYPICAL: // Minimum & typical means the same: // Install all for SMTP, none for NNTP DebugOutput(_T("Unattended mode is MINIMUM/TYPICAL")); if (dwComponent == MC_IMS) dwMode = SubcompOn; else dwMode = SubcompOff; break; case IIS_SETUPMODE_CUSTOM: // For custom we use the custom setting DebugOutput(_T("Unattended mode is CUSTOM")); break; case IIS_SETUPMODE_UPGRADEONLY: // Return the original state DebugOutput(_T("Unattended mode is UPGRADEONLY")); dwMode = gHelperRoutines.QuerySelectionState( gHelperRoutines.OcManagerContext, szSubcomponent, OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff; break; case IIS_SETUPMODE_ADDEXTRACOMPS: // Turn it on only if the old state is off and the // custom state is on DebugOutput(_T("Unattended mode is ADDEXTRACOMPS")); dwOriginalMode = gHelperRoutines.QuerySelectionState( gHelperRoutines.OcManagerContext, szSubcomponent, OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff; if (dwOriginalMode == SubcompOff && dwMode == SubcompOn) dwMode = SubcompOn; else dwMode = dwOriginalMode; break; case IIS_SETUPMODE_ADDREMOVE: // Return the custom setting DebugOutput(_T("Unattended mode is ADDREMOVE")); break; case IIS_SETUPMODE_REMOVEALL: // Kill everything DebugOutput(_T("Unattended mode is REMOVEALL")); dwMode = SubcompOff; break; } DebugOutput(_T("Unattended state for %s is %s"), szSubcomponent, (dwMode == SubcompOn)?_T("ON"):_T("OFF")); } else { if (GetLastError() != ERROR_LINE_NOT_FOUND) DebugOutput(_T("SetupGetLineText failed (%x)."), GetLastError()); } } return(dwMode); } BOOL DetectExistingSmtpServers() { // Detect other mail servers CRegKey regMachine = HKEY_LOCAL_MACHINE; // System\CurrentControlSet\Services\MsExchangeIMC\Parameters CRegKey regSMTPParam( regMachine, REG_EXCHANGEIMCPARAMETERS, KEY_READ ); if ((HKEY) regSMTPParam ) { CString csCaption; DebugOutput(_T("IMC detected, suppressing SMTP")); if (!theApp.m_fIsUnattended && !theApp.m_fNTGuiMode) { MyLoadString(IDS_MESSAGEBOX_TEXT, csCaption); PopupOkMessageBox(IDS_SUPPRESS_SMTP, csCaption); } return(TRUE); } DebugOutput(_T("No other SMTP servers detected, installing IMS.")); return(FALSE); } BOOL DetectExistingIISADMIN() { // // Detect is IISADMIN service exists // // This is to make sure we don't do any metabase operation if // IISADMIN doesn't exists, especially in the uninstall cases. // DWORD dwStatus = 0; dwStatus = InetQueryServiceStatus(SZ_MD_SERVICENAME); if (0 == dwStatus) { // some kind of error occur during InetQueryServiceStatus. DebugOutput(_T("DetectExistingIISADMIN() return FALSE")); return (FALSE); } return(TRUE); } BOOL InsertSetupString( LPCSTR REG_PARAMETERS ) { // set up registry values CRegKey regMachine = HKEY_LOCAL_MACHINE; // System\CurrentControlSet\Services\NNTPSVC\Parameters CRegKey regParam( (LPCTSTR) REG_PARAMETERS, regMachine ); if ((HKEY) regParam) { regParam.SetValue( _T("MajorVersion"), (DWORD)STAXNT5MAJORVERSION ); regParam.SetValue( _T("MinorVersion"), (DWORD)STAXNT5MINORVERSION ); regParam.SetValue( _T("InstallPath"), theApp.m_csPathInetsrv ); switch (theApp.m_eNTOSType) { case OT_NTW: regParam.SetValue( _T("SetupString"), REG_SETUP_STRING_NT5WKSB3 ); break; default: _ASSERT(!"Unknown OS type"); // Fall through case OT_NTS: case OT_PDC_OR_BDC: case OT_PDC: case OT_BDC: regParam.SetValue( _T("SetupString"), REG_SETUP_STRING_NT5SRVB3 ); break; } } return TRUE; } // Scans a multi-sz and finds the first occurrence of the // specified string LPTSTR ScanMultiSzForSz(LPTSTR szMultiSz, LPTSTR szSz) { LPTSTR lpTemp = szMultiSz; do { if (!lstrcmpi(lpTemp, szSz)) return(lpTemp); lpTemp += lstrlen(lpTemp); lpTemp++; } while (*lpTemp != _T('\0')); return(NULL); } // Removes the said string from a MultiSz // This places a lot of faith in the caller! void RemoveSzFromMultiSz(LPTSTR szSz) { LPTSTR lpScan = szSz; TCHAR tcLastChar; lpScan += lstrlen(szSz); lpScan++; tcLastChar = _T('x'); while ((tcLastChar != _T('\0')) || (*lpScan != _T('\0'))) { tcLastChar = *lpScan; *szSz++ = *lpScan++; } *szSz++ = _T('\0'); // Properly terminate it if it's the last one if (*lpScan == _T('\0')) *szSz = _T('\0'); } // This walks the multi-sz and returns a pointer between // the last string of a multi-sz and the second terminating // NULL LPTSTR GetEndOfMultiSz(LPTSTR szMultiSz) { LPTSTR lpTemp = szMultiSz; do { lpTemp += lstrlen(lpTemp); lpTemp++; } while (*lpTemp != _T('\0')); return(lpTemp); } // This appends a string to the end of a multi-sz // The buffer must be long enough BOOL AppendSzToMultiSz(LPTSTR szMultiSz, LPTSTR szSz, DWORD dwMaxSize) { LPTSTR szTemp = szMultiSz; DWORD dwLength = lstrlen(szSz); // If the string is empty, do not append! if (*szMultiSz == _T('\0') && *(szMultiSz + 1) == _T('\0')) szTemp = szMultiSz; else { szTemp = GetEndOfMultiSz(szMultiSz); dwLength += (DWORD)(szTemp - szMultiSz); } if (dwLength >= dwMaxSize) return(FALSE); lstrcpy(szTemp, szSz); szMultiSz += dwLength; *szMultiSz = _T('\0'); *(szMultiSz + 1) = _T('\0'); return(TRUE); } BOOL AddServiceToDispatchList(LPTSTR szServiceName) { TCHAR szMultiSz[4096]; DWORD dwSize = 4096; CRegKey RegInetInfo(REG_INETINFOPARAMETERS, HKEY_LOCAL_MACHINE); if ((HKEY)RegInetInfo) { // Default to empty string if not exists szMultiSz[0] = _T('\0'); szMultiSz[1] = _T('\0'); if (RegInetInfo.QueryValue(SZ_INETINFODISPATCH, szMultiSz, dwSize) == NO_ERROR) { // Walk the list to see if the value is already there if (ScanMultiSzForSz(szMultiSz, szServiceName)) return(TRUE); } // Create the value and add it to the list if (!AppendSzToMultiSz(szMultiSz, szServiceName, dwSize)) return(FALSE); // Get the size of the new Multi-sz dwSize = (DWORD)(GetEndOfMultiSz(szMultiSz) - szMultiSz) + 1; // Write the value back to the registry if (RegInetInfo.SetValue(SZ_INETINFODISPATCH, szMultiSz, dwSize * (DWORD) sizeof(TCHAR)) == NO_ERROR) return(TRUE); } // If the InetInfo key is not here, there isn't much we can do ... return(FALSE); } BOOL RemoveServiceFromDispatchList(LPTSTR szServiceName) { TCHAR szMultiSz[4096]; DWORD dwSize = 4096; LPTSTR szTemp; BOOL fFound = FALSE; CRegKey RegInetInfo(HKEY_LOCAL_MACHINE, REG_INETINFOPARAMETERS); if ((HKEY)RegInetInfo) { if (RegInetInfo.QueryValue(SZ_INETINFODISPATCH, szMultiSz, dwSize) == NO_ERROR) { // Walk the list to see if the value is already there while (szTemp = ScanMultiSzForSz(szMultiSz, szServiceName)) { RemoveSzFromMultiSz(szTemp); fFound = TRUE; } } // Write the value back to the registry if necessary, note we // will indicate success if the string is not found if (!fFound) return(TRUE); // Get the size of the new Multi-sz dwSize = (DWORD)(GetEndOfMultiSz(szMultiSz) - szMultiSz) + 1; // Write the value back to the registry if (RegInetInfo.SetValue(SZ_INETINFODISPATCH, szMultiSz, dwSize * (DWORD) sizeof(TCHAR)) == NO_ERROR) return(TRUE); } // If the InetInfo key is not here, there isn't much we can do ... return(FALSE); } void GetIISProgramGroup(CString &csGroupName, BOOL fIsMcisGroup) { TCHAR szName[_MAX_PATH]; CString csTempName; UINT uType, uSize; if (fIsMcisGroup) { csGroupName = ""; } else { // Get the NT program group name from the private data uSize = _MAX_PATH * sizeof(TCHAR); { // We use the default group name MyLoadString(IDS_DEFAULT_NT_PROGRAM_GROUP, csTempName); lstrcpy(szName, csTempName.GetBuffer(_MAX_PATH)); csTempName.ReleaseBuffer(); } csGroupName = szName; csGroupName += _T("\\"); // Get the IIS program group name from the private data uSize = _MAX_PATH * sizeof(TCHAR); { // We use the default group name MyLoadString(IDS_DEFAULT_IIS_PROGRAM_GROUP, csTempName); lstrcpy(szName, csTempName.GetBuffer(_MAX_PATH)); csTempName.ReleaseBuffer(); } csGroupName += szName; } } void MyGetGroupPath(LPCTSTR szGroupName, LPTSTR szPath); BOOL GetFullPathToProgramGroup(DWORD dwMainComponent, CString &csGroupName, BOOL fIsMcisGroup) { // add items to the program group CString csTemp; TCHAR szPath[MAX_PATH]; // Get the program group name from the private data GetIISProgramGroup(csTemp, fIsMcisGroup); // Get the system path to this menu item MyGetGroupPath((LPCTSTR)csTemp, szPath); csGroupName = szPath; // Load up the resource string for the group if (fIsMcisGroup) MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp); else MyLoadString(dwMainComponent == MC_IMS?IDS_PROGGROUP_MAIL:IDS_PROGGROUP_NEWS, csTemp); // Build the program group csGroupName += csTemp; DebugOutput(_T("Program group loaded: %s"), (LPCTSTR)csGroupName); return(TRUE); } BOOL GetFullPathToAdminGroup(DWORD dwMainComponent, CString &csGroupName) { // add items to the program group CString csTemp; TCHAR szPath[MAX_PATH]; // Get the program group name from the private data MyLoadString( IDS_PROGGROUP_ADMINTOOLS, csTemp ); // Get the system path to this menu item MyGetGroupPath((LPCTSTR)csTemp, szPath); csGroupName = szPath; DebugOutput(_T("Program group loaded: %s"), (LPCTSTR)csGroupName); return(TRUE); } BOOL RemoveProgramGroupIfEmpty(DWORD dwMainComponent, BOOL fIsMcisGroup) { // add items to the program group CString csGroupName; CString csTemp; TCHAR szPath[MAX_PATH]; BOOL fResult; // Get the program group name from the private data GetIISProgramGroup(csTemp, fIsMcisGroup); // Get the system path to this menu item MyGetGroupPath((LPCTSTR)csTemp, szPath); csGroupName = szPath; // Load up the resource string for the group if (fIsMcisGroup) MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp); else MyLoadString(dwMainComponent == MC_IMS?IDS_PROGGROUP_MAIL:IDS_PROGGROUP_NEWS, csTemp); // Build the program group csGroupName += csTemp; DebugOutput(_T("Removing Program group: %s"), (LPCTSTR)csGroupName); fResult = RemoveDirectory((LPCTSTR)csGroupName); if (fResult && fIsMcisGroup) { SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, (LPCTSTR)csGroupName, 0); csGroupName = szPath; MyLoadString(IDS_MCIS_2_0, csTemp); csGroupName += csTemp; fResult = RemoveDirectory((LPCTSTR)csGroupName); } if (fResult) { SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, (LPCTSTR)csGroupName, 0); } return(fResult); } BOOL RemoveInternetShortcut(DWORD dwMainComponent, int dwDisplayNameId, BOOL fIsMcisGroup) { CString csItemPath; CString csDisplayName; MyLoadString(dwDisplayNameId, csDisplayName); // Build the full path to the program link GetFullPathToProgramGroup(dwMainComponent, csItemPath, fIsMcisGroup); csItemPath += _T("\\"); csItemPath += csDisplayName; csItemPath += _T(".url"); DebugOutput(_T("Removing shortcut file: %s"), (LPCTSTR)csItemPath); DeleteFile((LPCTSTR)csItemPath); SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, (LPCTSTR)csItemPath, 0); RemoveProgramGroupIfEmpty(dwMainComponent, fIsMcisGroup); return(TRUE); } BOOL RemoveNt5InternetShortcut(DWORD dwMainComponent, int dwDisplayNameId) { CString csItemPath; CString csDisplayName; MyLoadString(dwDisplayNameId, csDisplayName); // Build the full path to the program link GetFullPathToAdminGroup(dwMainComponent, csItemPath); csItemPath += _T("\\"); csItemPath += csDisplayName; csItemPath += _T(".url"); DebugOutput(_T("Removing shortcut file: %s"), (LPCTSTR)csItemPath); DeleteFile((LPCTSTR)csItemPath); SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, (LPCTSTR)csItemPath, 0); return(TRUE); } BOOL RemoveMCIS10MailProgramGroup() { CString csGroupName; CString csNiceName; MyLoadString(IDS_PROGGROUP_MCIS10_MAIL, csGroupName); MyLoadString(IDS_PROGITEM_MCIS10_MAIL_STARTPAGE, csNiceName); MyDeleteItem(csGroupName, csNiceName); MyLoadString(IDS_PROGITEM_MCIS10_MAIL_WEBADMIN, csNiceName); MyDeleteItemEx(csGroupName, csNiceName); return(TRUE); } BOOL RemoveMCIS10NewsProgramGroup() { CString csGroupName; CString csNiceName; // BINLIN: // BUGBUG: need to figure out how to get // the old MCIS 1.0 program group path MyLoadString(IDS_PROGGROUP_MCIS10_NEWS, csGroupName); MyLoadString(IDS_PROGITEM_MCIS10_NEWS_STARTPAGE, csNiceName); MyDeleteItem(csGroupName, csNiceName); MyLoadString(IDS_PROGITEM_MCIS10_NEWS_WEBADMIN, csNiceName); MyDeleteItemEx(csGroupName, csNiceName); return(TRUE); } BOOL RemoveUninstallEntries(LPCTSTR szInfFile) { // All components are removed, we will have to remove // the Add/Remove option from the control panel CRegKey regUninstall( HKEY_LOCAL_MACHINE, REG_UNINSTALL); if ((HKEY)regUninstall) regUninstall.DeleteTree(szInfFile); else return(FALSE); return(TRUE); } BOOL MyDeleteLink(LPTSTR lpszShortcut) { TCHAR szFile[_MAX_PATH]; SHFILEOPSTRUCT fos; ZeroMemory(szFile, sizeof(szFile)); lstrcpy(szFile, lpszShortcut); // only call SHFileOperation if this file/link exists if (0xFFFFFFFF != GetFileAttributes(szFile)) { ZeroMemory(&fos, sizeof(fos)); fos.hwnd = NULL; fos.wFunc = FO_DELETE; fos.pFrom = szFile; fos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION; SHFileOperation(&fos); } return TRUE; } void MyGetGroupPath(LPCTSTR szGroupName, LPTSTR szPath) { int nLen = 0; LPITEMIDLIST pidlPrograms; szPath[0] = NULL; if (NOERROR != SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlPrograms)) return; if (!SHGetPathFromIDList(pidlPrograms, szPath)) return; nLen = lstrlen(szPath); if (szGroupName) { if (nLen == 0 || szPath[nLen-1] != _T('\\')) lstrcat(szPath, _T("\\")); lstrcat(szPath, szGroupName); } return; } BOOL MyAddGroup(LPCTSTR szGroupName) { TCHAR szPath[MAX_PATH]; CString csPath; MyGetGroupPath(szGroupName, szPath); csPath = szPath; CreateLayerDirectory(csPath); SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, szPath, 0); return TRUE; } BOOL MyIsGroupEmpty(LPCTSTR szGroupName) { TCHAR szPath[MAX_PATH]; TCHAR szFile[MAX_PATH]; WIN32_FIND_DATA FindData; HANDLE hFind; BOOL bFindFile = TRUE; BOOL fReturn = TRUE; MyGetGroupPath(szGroupName, szPath); lstrcpy(szFile, szPath); lstrcat(szFile, _T("\\*.*")); hFind = FindFirstFile(szFile, &FindData); if (INVALID_HANDLE_VALUE != hFind) { while (bFindFile) { if(*(FindData.cFileName) != _T('.')) { fReturn = FALSE; break; } //find the next file bFindFile = FindNextFile(hFind, &FindData); } FindClose(hFind); } return fReturn; } BOOL MyDeleteGroup(LPCTSTR szGroupName) { TCHAR szPath[MAX_PATH]; TCHAR szFile[MAX_PATH]; SHFILEOPSTRUCT fos; WIN32_FIND_DATA FindData; HANDLE hFind; BOOL bFindFile = TRUE; BOOL fResult; MyGetGroupPath(szGroupName, szPath); //we can't remove a directory that is not empty, so we need to empty this one lstrcpy(szFile, szPath); lstrcat(szFile, _T("\\*.*")); ZeroMemory(&fos, sizeof(fos)); fos.hwnd = NULL; fos.wFunc = FO_DELETE; fos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION; hFind = FindFirstFile(szFile, &FindData); if (INVALID_HANDLE_VALUE != hFind) { while (bFindFile) { if(*(FindData.cFileName) != _T('.')) { //copy the path and file name to our temp buffer lstrcpy(szFile, szPath); lstrcat(szFile, _T("\\")); lstrcat(szFile, FindData.cFileName); //add a second NULL because SHFileOperation is looking for this lstrcat(szFile, _T("\0")); //delete the file fos.pFrom = szFile; SHFileOperation(&fos); } //find the next file bFindFile = FindNextFile(hFind, &FindData); } FindClose(hFind); } fResult = RemoveDirectory(szPath); if (fResult) { SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, szPath, 0); } return(fResult); } void MyDeleteItem(LPCTSTR szGroupName, LPCTSTR szAppName) { TCHAR szPath[_MAX_PATH]; MyGetGroupPath(szGroupName, szPath); lstrcat(szPath, _T("\\")); lstrcat(szPath, szAppName); lstrcat(szPath, _T(".lnk")); MyDeleteLink(szPath); if (MyIsGroupEmpty(szGroupName)) MyDeleteGroup(szGroupName); } // Use to delete files with extension other than ".lnk" void MyDeleteItemEx(LPCTSTR szGroupName, LPCTSTR szAppName) { TCHAR szPath[_MAX_PATH]; MyGetGroupPath(szGroupName, szPath); lstrcat(szPath, _T("\\")); lstrcat(szPath, szAppName); MyDeleteLink(szPath); if (MyIsGroupEmpty(szGroupName)) MyDeleteGroup(szGroupName); } BOOL RemoveISMLink() { // add items to the program group CString csGroupName; CString csNiceName; CString csTemp; DebugOutput(_T("Removing ISM link ...")); // Get the program group name from the private data GetIISProgramGroup(csGroupName, TRUE); MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp); // Build the program group csGroupName += csTemp; MyLoadString(IDS_PROGITEM_ISM, csNiceName); MyDeleteItem(csGroupName, csNiceName); return(TRUE); } void GetInetpubPathFromMD(CString& csPathInetpub) { TCHAR szw3root[] = _T("\\wwwroot"); TCHAR szPathInetpub[_MAX_PATH]; ZeroMemory( szPathInetpub, sizeof(szPathInetpub) ); CMDKey W3Key; DWORD dwScratch; DWORD dwType; DWORD dwLength; // Get W3Root path W3Key.OpenNode(_T("LM/W3Svc/1/Root")); if ( (METADATA_HANDLE)W3Key ) { dwLength = _MAX_PATH; if (W3Key.GetData(3001, &dwScratch, &dwScratch, &dwType, &dwLength, (LPBYTE)szPathInetpub)) { if (dwType == STRING_METADATA) { dwScratch = lstrlen(szw3root); dwLength = lstrlen(szPathInetpub); // If it ends with "\\wwwroot", then we copy the prefix into csPathInetpub if ((dwLength > dwScratch) && !lstrcmpi(szPathInetpub + (dwLength - dwScratch), szw3root)) { csPathInetpub.Empty(); lstrcpyn( csPathInetpub.GetBuffer(512), szPathInetpub, (dwLength - dwScratch + 1)); csPathInetpub.ReleaseBuffer(); } // otherwise fall back to use the default... } } W3Key.Close(); } return; }