windows-nt/Source/XPSP1/NT/net/config/netoc/nccmak.cpp
2020-09-26 16:20:57 +08:00

723 lines
21 KiB
C++

//+---------------------------------------------------------------------------
//
// File: NCCMAK.CPP
//
// Module: NetOC.DLL
//
// Synopsis: Implements the dll entry points required to integrate into
// NetOC.DLL the installation of the following components.
//
// NETCMAK
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// Author: a-anasj 9 Mar 1998
// quintinb 18 Sep 1998 -- rewrote
//
//+---------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>
#include "ncatl.h"
#include "resource.h"
#include "nccm.h"
//
// Define Globals
//
WCHAR g_szCmakPath[MAX_PATH+1];
//
// Define Strings Chars
//
static const WCHAR c_szCmakRegPath[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CMAK.EXE";
static const WCHAR c_szPathValue[] = L"Path";
static const WCHAR c_szProfiles32Fmt[] = L"%s\\Profiles-32";
static const WCHAR c_szCm32Fmt[] = L"%s\\cm32";
static const WCHAR c_szProfilesFmt[] = L"%s\\Profiles";
static const WCHAR c_szSupportFmt[] = L"%s\\Support";
static const WCHAR c_szCmHelpFmt[] = L"%s\\Support\\CmHelp";
static const WCHAR c_szCmakGroup[] = L"Connection Manager Administration Kit";
const DWORD c_dwCmakDirID = 123174; // just must be larger than DIRID_USER = 0x8000;
//+---------------------------------------------------------------------------
//
// Function: HrOcCmakPreQueueFiles
//
// Purpose: Called by optional components installer code before any files
// are copied to handle any additional installation processing
// for the Connection Manager Administration Kit.
//
// Arguments:
// pnocd [in] Pointer to NETOC data.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: quintinb 18 Sep 1998
//
// Notes:
//
HRESULT HrOcCmakPreQueueFiles(PNETOCDATA pnocd)
{
HRESULT hr = S_OK;
if ((IT_INSTALL == pnocd->eit) || (IT_UPGRADE == pnocd->eit) || (IT_REMOVE == pnocd->eit))
{
// Figure out if CMAK is already installed
// if so, save where it is located
HKEY hKey;
ZeroMemory(g_szCmakPath, sizeof(g_szCmakPath));
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szCmakRegPath, KEY_READ, &hKey);
if (SUCCEEDED(hr))
{
DWORD dwSize = sizeof(g_szCmakPath);
if (ERROR_SUCCESS != RegQueryValueExW(hKey, c_szPathValue, NULL, NULL,
(LPBYTE)g_szCmakPath, &dwSize))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
RegCloseKey(hKey);
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
// This is a fresh install of CMAK, don't return an error
//
hr = SHGetSpecialFolderPath(NULL, g_szCmakPath, CSIDL_PROGRAM_FILES, FALSE);
if (SUCCEEDED(hr))
{
lstrcatW(g_szCmakPath, L"\\Cmak");
}
}
if (SUCCEEDED(hr))
{
// Next Create the CMAK Dir ID
//
hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd);
if (SUCCEEDED(hr))
{
if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwCmakDirID, g_szCmakPath))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}
}
TraceError("HrOcCmakPreQueueFiles", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOcCmakPostInstall
//
// Purpose: Called by optional components installer code to handle
// additional installation requirements for Connection Manager Administration Kit.
//
// Arguments:
// pnocd [in] Pointer to NETOC data.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: a-anasj 9 Mar 1998
//
// Notes:
//
HRESULT HrOcCmakPostInstall(PNETOCDATA pnocd)
{
HRESULT hr = S_OK;
WCHAR szTempDest[MAX_PATH+1];
if ((IT_INSTALL == pnocd->eit) || (IT_UPGRADE == pnocd->eit))
{
//
// Then we need to migrate profiles and potentially delete old directories
//
if (L'\0' != g_szCmakPath[0])
{
wsprintfW(szTempDest, c_szProfilesFmt, g_szCmakPath);
//
// Rename Profiles-32 to Profiles
//
BOOL bFail = !RenameProfiles32(g_szCmakPath, szTempDest);
hr = bFail ? E_UNEXPECTED: S_OK;
//
// Migrate 1.0 Profiles
//
bFail = !migrateProfiles(g_szCmakPath, szTempDest);
hr = bFail ? E_UNEXPECTED: S_OK;
//
// Delete the old directories (cm32 and its sub-dirs)
//
DeleteOldCmakSubDirs(g_szCmakPath);
DeleteOldNtopLinks();
DeleteIeakCmakLinks();
}
}
else if (IT_REMOVE == pnocd->eit)
{
//
// We use the g_szCmakPath string to hold where CMAK was installed.
// To Properly delete the CMAK directory, we must delete the following
// directories CMAK\Support\CMHelp, CMAK\Support, CMAK\Profiles, and CMAK.
// We should only delete these directories if they are empty of both files
// and sub-dirs.
//
wsprintfW(szTempDest, c_szCmHelpFmt, g_szCmakPath);
if (!RemoveDirectory(szTempDest))
{
TraceError("HrOcCmakPostInstall -- Removing CMHelp Dir",
HRESULT_FROM_WIN32(GetLastError()));
}
wsprintfW(szTempDest, c_szSupportFmt, g_szCmakPath);
if (!RemoveDirectory(szTempDest))
{
TraceError("HrOcCmakPostInstall -- Removing Support Dir",
HRESULT_FROM_WIN32(GetLastError()));
}
wsprintfW(szTempDest, c_szProfilesFmt, g_szCmakPath);
if (!RemoveDirectory(szTempDest))
{
TraceError("HrOcCmakPostInstall -- Removing Profiles Dir",
HRESULT_FROM_WIN32(GetLastError()));
}
if (!RemoveDirectory(g_szCmakPath))
{
TraceError("HrOcCmakPostInstall -- Removing CMAK Dir",
HRESULT_FROM_WIN32(GetLastError()));
}
}
TraceError("HrOcCmakPostInstall", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: migrateProfiles
//
// Purpose: This is the function that migrates the profiles. It takes the current
// CMAK dir as its first input and the new CMAK dir as its second input..
//
// Arguments: PCWSTR pszSource - root of source CMAK dir
// PCWSTR pszDestination - root of destination CMAK dir
//
// Returns: BOOL - Returns TRUE if it was able to migrate the profiles.
//
// Author: a-anasj 9 Mar 1998
//
// Notes:
// History: quintinb Created 12/9/97
//
BOOL migrateProfiles(PCWSTR pszSource, PCWSTR pszDestination)
{
WCHAR szSourceProfileSearchString[MAX_PATH+1];
WCHAR szFile[MAX_PATH+1];
HANDLE hFileSearch;
WIN32_FIND_DATA wfdFindData;
BOOL bReturn = TRUE;
SHFILEOPSTRUCT fOpStruct;
//
// Initialize the searchstring and the destination dir
//
wsprintfW(szSourceProfileSearchString, L"%s\\*.*", pszSource);
//
// Create the destination directory
//
CreateDirectory(pszDestination, NULL); //lint !e534 this might fail if it already exists
hFileSearch = FindFirstFile(szSourceProfileSearchString, &wfdFindData);
while (INVALID_HANDLE_VALUE != hFileSearch)
{
if((wfdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(0 != _wcsicmp(wfdFindData.cFileName, L"cm32")) && // 1.1/1.2 Legacy
(0 != _wcsicmp(wfdFindData.cFileName, L"cm16")) && // 1.1/1.2 Legacy
(0 != _wcsicmp(wfdFindData.cFileName, L"Docs")) &&
(0 != _wcsicmp(wfdFindData.cFileName, L"Profiles-32")) && // 1.1/1.2 Legacy
(0 != _wcsicmp(wfdFindData.cFileName, L"Profiles-16")) && // 1.1/1.2 Legacy
(0 != _wcsicmp(wfdFindData.cFileName, L"Support")) &&
(0 != _wcsicmp(wfdFindData.cFileName, L"Profiles")) &&
(0 != _wcsicmp(wfdFindData.cFileName, L".")) &&
(0 != _wcsicmp(wfdFindData.cFileName, L"..")))
{
//
// Then I have a profile directory
//
ZeroMemory(&fOpStruct, sizeof(fOpStruct));
ZeroMemory(szFile, sizeof(szFile));
wsprintfW(szFile, L"%s\\%s", pszSource, wfdFindData.cFileName);
fOpStruct.hwnd = NULL;
fOpStruct.wFunc = FO_MOVE;
fOpStruct.pTo = pszDestination;
fOpStruct.pFrom = szFile;
fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
}
//
// Check to see if we have any more Files
//
if (!FindNextFile(hFileSearch, &wfdFindData))
{
if (ERROR_NO_MORE_FILES != GetLastError())
{
//
// We had some unexpected error, report unsuccessful completion
//
bReturn = FALSE;
}
//
// Exit the loop
//
break;
}
}
if (INVALID_HANDLE_VALUE != hFileSearch)
{
FindClose(hFileSearch);
}
return bReturn;
}
//+---------------------------------------------------------------------------
//
// Function: RenameProfiles32
//
// Purpose: Takes the inputted CMAK path, appends Profiles-32 to it, and then
// renames the resulting dir to the path inputted as pszProfilesDir.
// Note this dir must exist for it to be renamed.
//
// Arguments: PCWSTR pszCMAKpath - current cmak path
// PCWSTR pszProfilesDir - new profiles directory path
//
// Returns: BOOL - Returns TRUE if succeeded
//
// Author: quintinb 13 Aug 1998
//
// Notes:
BOOL RenameProfiles32(PCWSTR pszCMAKpath, PCWSTR pszProfilesDir)
{
SHFILEOPSTRUCT fOpStruct;
WCHAR szTemp[MAX_PATH+1];
ZeroMemory(&fOpStruct, sizeof(fOpStruct));
ZeroMemory(szTemp, sizeof(szTemp));
wsprintfW(szTemp, c_szProfiles32Fmt, pszCMAKpath);
if (SetFileAttributes(szTemp, FILE_ATTRIBUTE_NORMAL))
{
fOpStruct.hwnd = NULL;
fOpStruct.wFunc = FO_MOVE;
fOpStruct.pTo = pszProfilesDir;
fOpStruct.pFrom = szTemp;
fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
return (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
}
else
{
return TRUE;
}
}
//+---------------------------------------------------------------------------
//
// Function: DeleteOldCmakSubDirs
//
// Purpose: Deletes the old Cmak sub directories. Uses FindFirstFile becuase
// we don't want to delete any customized doc files that the user may
// have customized. Thus anything in the CMHelp directory except the
// original help files is deleted.
//
// Arguments: PCWSTR pszCMAKpath - current cmak path
//
// Returns: Nothing
//
// Author: quintinb 6 Nov 1998
//
// Notes:
void DeleteOldCmakSubDirs(PCWSTR pszCmakPath)
{
WCHAR szCm32path[MAX_PATH+1];
WCHAR szCm32SearchString[MAX_PATH+1];
WCHAR szTemp[MAX_PATH+1];
HANDLE hCm32FileSearch;
WIN32_FIND_DATA wfdCm32;
//
// Delete the old IEAK Docs Dir
//
wsprintfW(szTemp, L"%s\\%s", pszCmakPath, SzLoadIds(IDS_OC_OLD_IEAK_DOCDIR));
RemoveDirectory(szTemp);
wsprintfW(szCm32path, c_szCm32Fmt, pszCmakPath);
//
// First look in the Cm32 directory itself. Delete all files found, continue down
// into subdirs.
//
wsprintfW(szCm32SearchString, L"%s\\*.*", szCm32path);
hCm32FileSearch = FindFirstFile(szCm32SearchString, &wfdCm32);
while (INVALID_HANDLE_VALUE != hCm32FileSearch)
{
if (wfdCm32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((0 != lstrcmpiW(wfdCm32.cFileName, L".")) &&
(0 != lstrcmpiW(wfdCm32.cFileName, L"..")))
{
//
// Then we want to delete all the files in this lang sub dir and we
// we want to delete the four help files from the CM help dir. If all the
// files are deleted from a dir then we should remove the directory.
//
WCHAR szLangDirSearchString[MAX_PATH+1];
HANDLE hLangDirFileSearch;
WIN32_FIND_DATA wfdLangDir;
wsprintfW(szLangDirSearchString, L"%s\\%s\\*.*", szCm32path,
wfdCm32.cFileName);
hLangDirFileSearch = FindFirstFile(szLangDirSearchString, &wfdLangDir);
while (INVALID_HANDLE_VALUE != hLangDirFileSearch)
{
if (wfdLangDir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((0 != lstrcmpiW(wfdLangDir.cFileName, L".")) &&
(0 != lstrcmpiW(wfdLangDir.cFileName, L"..")))
{
//
// We only want to delete help files from our help source dirs
//
if (0 == _wcsnicmp(wfdLangDir.cFileName, L"CM", 2))
{
//
// Delete the four help files only.
//
wsprintfW(szTemp, L"%s\\%s\\%s\\cmctx32.rtf", szCm32path,
wfdCm32.cFileName, wfdLangDir.cFileName);
DeleteFile(szTemp);
wsprintfW(szTemp, L"%s\\%s\\%s\\cmmgr32.h", szCm32path,
wfdCm32.cFileName, wfdLangDir.cFileName);
DeleteFile(szTemp);
wsprintfW(szTemp, L"%s\\%s\\%s\\cmmgr32.hpj", szCm32path,
wfdCm32.cFileName, wfdLangDir.cFileName);
DeleteFile(szTemp);
wsprintfW(szTemp, L"%s\\%s\\%s\\cmtrb32.rtf", szCm32path,
wfdCm32.cFileName, wfdLangDir.cFileName);
DeleteFile(szTemp);
//
// Now try to remove the directory
//
wsprintfW(szTemp, L"%s\\%s\\%s", szCm32path,
wfdCm32.cFileName, wfdLangDir.cFileName);
RemoveDirectory(szTemp);
}
}
}
else
{
wsprintfW(szTemp, L"%s\\%s\\%s", szCm32path, wfdCm32.cFileName,
wfdLangDir.cFileName);
DeleteFile(szTemp);
}
//
// Check to see if we have any more Files
//
if (!FindNextFile(hLangDirFileSearch, &wfdLangDir))
{
//
// Exit the loop
//
break;
}
}
if (INVALID_HANDLE_VALUE != hLangDirFileSearch)
{
FindClose(hLangDirFileSearch);
//
// Now try to remove the lang dir directory
//
wsprintfW(szTemp, L"%s\\%s", szCm32path, wfdCm32.cFileName);
RemoveDirectory(szTemp);
}
}
}
else
{
wsprintfW(szTemp, L"%s\\%s", szCm32path, wfdCm32.cFileName);
DeleteFile(szTemp);
}
//
// Check to see if we have any more Files
//
if (!FindNextFile(hCm32FileSearch, &wfdCm32))
{
if (INVALID_HANDLE_VALUE != hCm32FileSearch)
{
FindClose(hCm32FileSearch);
}
//
// Now try to remove the cm32 directory
//
RemoveDirectory(szCm32path);
//
// Exit the loop
//
break;
}
}
}
//+---------------------------------------------------------------------------
//
// Function: DeleteProgramGroupWithLinks
//
// Purpose: Utility function to delete a given program group and its links.
// Thus if you pass in the full path to a program group to delete,
// the function does a findfirstfile to find and delete any links.
// The function ignores sub-dirs.
//
//
// Arguments: PCWSTR pszGroupPath - Full path to the program group to delete.
//
// Returns: Nothing
//
// Author: quintinb 6 Nov 1998
//
// Notes:
void DeleteProgramGroupWithLinks(PCWSTR pszGroupPath)
{
HANDLE hLinkSearch;
WIN32_FIND_DATA wfdLinks;
WCHAR szLinkSearchString[MAX_PATH+1];
WCHAR szTemp[MAX_PATH+1];
wsprintfW(szLinkSearchString, L"%s\\*.*", pszGroupPath);
hLinkSearch = FindFirstFile(szLinkSearchString, &wfdLinks);
while (INVALID_HANDLE_VALUE != hLinkSearch)
{
if (!(wfdLinks.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
wsprintfW(szTemp, L"%s\\%s", pszGroupPath, wfdLinks.cFileName);
DeleteFile(szTemp);
}
//
// Check to see if we have any more Files
//
if (!FindNextFile(hLinkSearch, &wfdLinks))
{
FindClose(hLinkSearch);
//
// Now try to remove the directory
//
RemoveDirectory(pszGroupPath);
//
// Exit the loop
//
break;
}
}
}
//+---------------------------------------------------------------------------
//
// Function: DeleteOldNtopLinks
//
// Purpose: Deletes the old links from the NT 4.0 Option Pack
//
//
// Arguments: None
//
// Returns: Nothing
//
// Author: quintinb 6 Nov 1998
//
// Notes:
void DeleteOldNtopLinks()
{
HRESULT hr;
//
// First Delete the old NTOP4 Path
//
WCHAR szGroup[MAX_PATH+1];
WCHAR szTemp[MAX_PATH+1];
//
// Get the CSIDL_COMMON_PROGRAMS value
//
hr = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_COMMON_PROGRAMS, FALSE);
if (SUCCEEDED(hr))
{
wsprintfW(szGroup, L"%s\\%s\\%s", szTemp,
(PWSTR)SzLoadIds(IDS_OC_NTOP4_GROUPNAME),
(PWSTR)SzLoadIds(IDS_OC_ICS_GROUPNAME));
DeleteProgramGroupWithLinks(szGroup);
}
}
//+---------------------------------------------------------------------------
//
// Function: DeleteIeakCmakLinks
//
// Purpose: Deletes the old links from the IEAK4 CMAK
//
//
// Arguments: None
//
// Returns: Nothing
//
// Author: quintinb 6 Nov 1998
//
// Notes:
void DeleteIeakCmakLinks()
{
WCHAR szUserDirRoot[MAX_PATH+1];
WCHAR szGroup[MAX_PATH+1];
WCHAR szTemp[MAX_PATH+1];
WCHAR szEnd[MAX_PATH+1];
//
// Next Delete the old IEAK CMAK links
//
//
// Get the Desktop directory and then remove the desktop part. This will give us the
// root of the user directories.
//
HRESULT hr = SHGetSpecialFolderPath(NULL, szUserDirRoot, CSIDL_DESKTOPDIRECTORY, FALSE);
if (SUCCEEDED(hr))
{
//
// Remove \\Desktop
//
WCHAR* pszTemp = wcsrchr(szUserDirRoot, L'\\');
if (NULL == pszTemp)
{
return;
}
else
{
*pszTemp = L'\0';
}
HRESULT hr = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_PROGRAMS, FALSE);
if (SUCCEEDED(hr))
{
if (0 == _wcsnicmp(szUserDirRoot, szTemp, wcslen(szUserDirRoot)))
{
lstrcpyW(szEnd, &(szTemp[wcslen(szUserDirRoot)]));
}
}
//
// Remove \\<User Name>>
//
pszTemp = wcsrchr(szUserDirRoot, L'\\');
if (NULL == pszTemp)
{
return;
}
else
{
*pszTemp = L'\0';
}
//
// Now start searching for user dirs to delete the CMAK group from
//
WCHAR szUserDirSearchString[MAX_PATH+1];
HANDLE hUserDirSearch;
WIN32_FIND_DATA wfdUserDirs;
wsprintfW(szUserDirSearchString, L"%s\\*.*", szUserDirRoot);
hUserDirSearch = FindFirstFile(szUserDirSearchString, &wfdUserDirs);
while (INVALID_HANDLE_VALUE != hUserDirSearch)
{
if ((wfdUserDirs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(0 != _wcsicmp(wfdUserDirs.cFileName, L".")) &&
(0 != _wcsicmp(wfdUserDirs.cFileName, L"..")))
{
wsprintfW(szGroup, L"%s\\%s%s\\%s", szUserDirRoot, wfdUserDirs.cFileName,
szEnd, c_szCmakGroup);
DeleteProgramGroupWithLinks(szGroup);
}
if (!FindNextFile(hUserDirSearch, &wfdUserDirs))
{
FindClose(hUserDirSearch);
//
// Exit the loop
//
break;
}
}
}
}