Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1922 lines
63 KiB

// adminpak.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include <stdio.h>
#include <shellapi.h>
#include "shlobj.h"
#include "adminpak.h"
#define STRSAFE_NO_DEPRECATE
#include "strsafe.h"
#include "shlwapi.h"
// version resource specific structures
typedef struct __tagLanguageAndCodePage {
WORD wLanguage;
WORD wCodePage;
} TTRANSLATE, *PTTRANSLATE;
typedef struct __tagVersionBreakup {
DWORD dwMajor;
DWORD dwMinor;
DWORD dwRevision; // build number
DWORD dwSubRevision; // QFE / SP
} TVERSION, *PTVERSION;
enum {
translateError = -2,
translateLesser = -1, translateEqual = 0, translateGreater = 1,
translateWrongFile = 2
};
#define ADMINPAK_EXPORTS 1
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
UNREFERENCED_PARAMETER( hModule );
UNREFERENCED_PARAMETER( lpReserved );
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// CMAK Migration Code
//
// Define Strings Chars
//
static const CHAR c_szDaoClientsPath[] = "SOFTWARE\\Microsoft\\Shared Tools\\DAO\\Clients";
static const CHAR c_szCmakRegPath[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CMAK.EXE";
static const CHAR c_szPathValue[] = "Path";
static const CHAR c_szProfiles32Fmt[] = "%s\\Profiles-32";
static const CHAR c_szCm32Fmt[] = "%s\\cm32";
static const CHAR c_szProfilesFmt[] = "%s\\Profiles";
static const CHAR c_szSupportFmt[] = "%s\\Support";
static const CHAR c_szCmHelpFmt[] = "%s\\Support\\CmHelp";
static const CHAR c_szCmakGroup[] = "Connection Manager Administration Kit";
static const CHAR OC_OLD_IEAK_DOCDIR[] = "Docs";
static const CHAR OC_NTOP4_GROUPNAME[] = "Windows NT 4.0 Option Pack";
static const CHAR OC_ICS_GROUPNAME[] = "Internet Connection Services for RAS";
static const CHAR OC_ADMIN_TOOLS[] = "\\Administrative Tools\\Phone Book Administrator.lnk";
static const CHAR OC_PBA_DESC[] = "Use Phone Book Administrator to create Connection Manager Phone Book ";
static const CHAR OC_PWS_GROUPNAME[] = "Microsoft Personal Web Server";
const DWORD c_dwCmakDirID = 123174; // just must be larger than DIRID_USER = 0x8000;
//
// Define Functions
//
BOOL migrateProfiles(LPCTSTR pszSource, LPCTSTR pszDestination, LPCTSTR pszDestinationProfiles);
void DeleteOldCmakSubDirs(LPCTSTR pszCmakPath);
void DeleteProgramGroupWithLinks(LPCTSTR pszGroupPath);
void DeleteOldNtopLinks();
void DeleteIeakCmakLinks();
void DeleteCmakRegKeys();
void CreateNewProfilesDirectory( LPCTSTR pszNewProfilePath );
HRESULT HrGetPBAPathIfInstalled(PSTR pszCpaPath, DWORD dwNumChars);
BOOL GetAdminToolsFolder(PSTR pszAdminTools);
HRESULT HrCreatePbaShortcut(PSTR pszCpaPath);
// This function migrates the old profile versions of CMAK to the new one placed
// by the adminpak....
extern "C" ADMINPAK_API int __stdcall fnMigrateProfilesToNewCmak( MSIHANDLE hInstall )
{
OutputDebugString("ADMINPAK: fnMigrateProfilesToNewCmak...\n");
// Get the location of the old CMAK folder.
DWORD dwPathLength = MAX_PATH * sizeof(char);
char *szCmakOldPath = NULL;
DWORD dwCmakOldPathLen = dwPathLength;
char *szCmakOldProfilePath = NULL;
DWORD dwCmakOldProfilePathLen = dwPathLength;
char *szCmakNewPath = NULL;
DWORD dwCmakNewPathLen = dwPathLength;
char *szCmakNewProfilePath = NULL;
DWORD dwCmakNewProfilePathLen = dwPathLength;
long sc;
UINT uintRet;
HKEY phkResult = NULL;
HRESULT res = S_OK;
#if (defined(DBG) || defined(_DEBUG) || defined(DEBUG))
char tempOut1[MAX_PATH];
#endif
szCmakOldPath = new char[dwCmakOldPathLen];
szCmakNewPath = new char[dwCmakNewPathLen];
szCmakOldProfilePath = new char[dwCmakOldProfilePathLen];
szCmakNewProfilePath = new char[dwCmakNewProfilePathLen];
if ( szCmakOldPath == NULL ||
szCmakNewPath == NULL ||
szCmakOldProfilePath == NULL ||
szCmakNewProfilePath == NULL )
{
if ( szCmakOldPath != NULL )
{
delete [] szCmakOldPath;
}
if ( szCmakNewPath != NULL )
{
delete [] szCmakNewPath;
}
if ( szCmakOldProfilePath != NULL )
{
delete [] szCmakOldProfilePath;
}
if ( szCmakNewProfilePath != NULL )
{
delete [] szCmakNewProfilePath;
}
return E_OUTOFMEMORY;
}
// Put together OLD path information
sc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, c_szCmakRegPath, 0, KEY_READ, &phkResult);
if ( sc != ERROR_SUCCESS )
{
delete [] szCmakOldPath;
delete [] szCmakOldProfilePath;
delete [] szCmakNewPath;
delete [] szCmakNewProfilePath;
return sc;
}
sc = RegQueryValueEx( phkResult, "Path", NULL, NULL, (unsigned char*)szCmakOldPath, &dwCmakOldPathLen );
RegCloseKey( phkResult );
// sc = ERROR_SUCCESS;
// strcpy(szCmakOldPath, "c:\\cmak\\");
if ( sc == ERROR_SUCCESS ) {
dwCmakOldPathLen = (DWORD)strlen( szCmakOldPath );
char tmpLastChar = *(szCmakOldPath + (dwCmakOldPathLen - 1));
if ( tmpLastChar == '\\' ) {
*(szCmakOldPath + (dwCmakOldPathLen - 1)) = NULL;
dwCmakOldPathLen = (DWORD)strlen( szCmakOldPath );
}
#if (defined(DBG) || defined(_DEBUG) || defined(DEBUG))
// StringCchPrintf(tempOut1, "ADMINPAK: szCmakOldPath: %s\n", szCmakOldPath);
OutputDebugString( tempOut1 );
#endif
res = StringCchCopy( szCmakOldProfilePath, dwPathLength, szCmakOldPath );
dwCmakOldProfilePathLen = dwCmakOldPathLen;
res = StringCchCat(szCmakOldProfilePath, dwPathLength, "\\Profiles");
dwCmakOldProfilePathLen = (DWORD)strlen( szCmakOldProfilePath );
}
// Put together NEW path information
uintRet = MsiGetTargetPath( hInstall, "DirCMAK", szCmakNewPath, &dwCmakNewPathLen);
// uintRet = ERROR_SUCCESS;
// strcpy(szCmakNewPath, "c:\\cmak\\program files");
if ( uintRet == ERROR_SUCCESS ) {
dwCmakNewPathLen = (DWORD)strlen( szCmakNewPath );
char tmpLastChar = *(szCmakNewPath + (dwCmakNewPathLen - 1));
if ( tmpLastChar == '\\' ) {
*(szCmakNewPath + (dwCmakNewPathLen - 1)) = NULL;
dwCmakNewPathLen = (DWORD)strlen( szCmakNewPath );
}
#if (defined(DBG) || defined(_DEBUG) || defined(DEBUG))
// StringCchPrintf(tempOut1, "ADMINPAK: szCmakNewPath: %s\n", szCmakNewPath);
OutputDebugString( tempOut1 );
#endif
res = StringCchCopy( szCmakNewProfilePath, dwPathLength, szCmakNewPath );
dwCmakNewProfilePathLen = dwCmakNewPathLen;
res = StringCchCat(szCmakNewProfilePath, dwPathLength, "\\Profiles");
dwCmakNewProfilePathLen = strlen( szCmakNewProfilePath );
}
// if all is Success then DO IT!
if ( sc == ERROR_SUCCESS && uintRet == ERROR_SUCCESS && res == S_OK) {
// RenameProfiles32(LPCTSTR pszCMAKpath, LPCTSTR pszProfilesDir);
// RenameProfiles32( szCmakOldPath, szCmakNewProfilePath );
// BOOL migrateProfiles(PCWSTR pszSource, LPCTSTR pszDestination);
migrateProfiles( szCmakOldPath, szCmakNewPath, szCmakNewProfilePath );
// DeleteOldCmakSubDirs(LPCTSTR pszCmakPath);
DeleteOldCmakSubDirs( szCmakOldPath );
}
delete [] szCmakOldPath;
delete [] szCmakOldProfilePath;
delete [] szCmakNewPath;
delete [] szCmakNewProfilePath;
return ERROR_SUCCESS;
}
extern "C" ADMINPAK_API int __stdcall fnDeleteOldCmakVersion( MSIHANDLE hInstall )
{
OutputDebugString("ADMINPAK: fnDeleteOldCmakVersion...\n");
// If PBA exists, you need to
CHAR szPbaInstallPath[MAX_PATH+1];
HRESULT hr;
hr = HrGetPBAPathIfInstalled(szPbaInstallPath, MAX_PATH);
UNREFERENCED_PARAMETER( hInstall );
if (S_OK == hr)
{
HrCreatePbaShortcut(szPbaInstallPath);
}
DeleteOldNtopLinks();
DeleteIeakCmakLinks();
DeleteCmakRegKeys();
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// 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(LPCTSTR pszSource, LPCTSTR pszDestination, LPCTSTR pszDestinationProfiles)
{
OutputDebugString("ADMINPAK: migrateProfiles...\n");
CHAR szSourceProfileSearchString1[MAX_PATH+1] ="" ;
CHAR szSourceProfileSearchString2[MAX_PATH+1] = "";
CHAR szFile[MAX_PATH+1] = "";
HANDLE hFileSearch;
WIN32_FIND_DATA fdFindData;
BOOL bReturn = TRUE;
SHFILEOPSTRUCT fOpStruct;
DWORD dwSize = _MAX_PATH;
HRESULT res;
//
// Initialize the searchstring and the destination dir
//
//StringCchPrintf(szSourceProfileSearchString1, "%s\\*.*", pszSource);
//
// Create the destination directory
//
CreateNewProfilesDirectory( pszDestinationProfiles );
// ::CreateDirectory(pszDestination, NULL); //lint !e534 this might fail if it already exists
hFileSearch = FindFirstFile(szSourceProfileSearchString1, &fdFindData);
while (INVALID_HANDLE_VALUE != hFileSearch)
{
if((fdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(0 != _stricmp(fdFindData.cFileName, "cm32")) && // 1.1/1.2 Legacy
(0 != _stricmp(fdFindData.cFileName, "cm16")) && // 1.1/1.2 Legacy
(0 != _stricmp(fdFindData.cFileName, "Docs")) &&
(0 != _stricmp(fdFindData.cFileName, "Profiles-32")) && // 1.1/1.2 Legacy
(0 != _stricmp(fdFindData.cFileName, "Profiles-16")) && // 1.1/1.2 Legacy
(0 != _stricmp(fdFindData.cFileName, "Support")) &&
(0 != _stricmp(fdFindData.cFileName, "Profiles")) &&
(0 != _stricmp(fdFindData.cFileName, ".")) &&
(0 != _stricmp(fdFindData.cFileName, "..")))
{
//
// Then I have a profile directory
//
ZeroMemory(&fOpStruct, sizeof(fOpStruct));
ZeroMemory(szFile, sizeof(szFile));
//StringCchPrintf(szFile, "%s\\%s", pszSource, fdFindData.cFileName);
fOpStruct.hwnd = NULL;
fOpStruct.wFunc = FO_MOVE;
fOpStruct.pTo = pszDestinationProfiles;
fOpStruct.pFrom = szFile;
fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
}
else if((fdFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
((0 == _stricmp(fdFindData.cFileName, "Profiles")) ||// 1.1/1.2 Legacy
(0 == _stricmp(fdFindData.cFileName, "Profiles-32")) ||// 1.1/1.2 Legacy
(0 == _stricmp(fdFindData.cFileName, "Profiles-16"))) )// 1.1/1.2 Legacy
{
//
// Then I have a profile directory
//
res = StringCchCopy(szSourceProfileSearchString2, dwSize, pszSource);
res = StringCchCat(szSourceProfileSearchString2, dwSize,"\\");
res = StringCchCat(szSourceProfileSearchString2, dwSize,fdFindData.cFileName);
//StringCchPrintf(szSourceProfileSearchString2, "%s\\*.*", szSourceProfileSearchString2);
if (res == S_OK)
{
HANDLE hFileSearch2;
WIN32_FIND_DATA fdFindData2;
hFileSearch2 = FindFirstFile(szSourceProfileSearchString2, &fdFindData2);
while (INVALID_HANDLE_VALUE != hFileSearch2)
{
if((fdFindData2.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(0 != _stricmp(fdFindData2.cFileName, ".")) &&
(0 != _stricmp(fdFindData2.cFileName, "..")))
{
ZeroMemory(&fOpStruct, sizeof(fOpStruct));
ZeroMemory(szFile, sizeof(szFile));
//StringCchPrintf(szFile, "%s\\%s\\%s", pszSource, fdFindData.cFileName, fdFindData2.cFileName);
fOpStruct.hwnd = NULL;
fOpStruct.wFunc = FO_MOVE;
fOpStruct.pTo = pszDestinationProfiles;
fOpStruct.pTo = NULL;
fOpStruct.pFrom = szFile;
fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
}
if (!FindNextFile(hFileSearch2, &fdFindData2)) {
// Delete the folder
if ( 0 != _stricmp(fdFindData.cFileName, "Profiles") ) {
//StringCchPrintf(szFile, "%s\\%s", pszSource, fdFindData.cFileName);
::RemoveDirectory(szFile);
}
break;
}
}
if (INVALID_HANDLE_VALUE != hFileSearch2) {
FindClose(hFileSearch2);
}
}
}
//Modified by v-mmosko. Need speical case to leave behind these 2 files
else if ( 0 != _stricmp(fdFindData.cFileName, "cmproxy.dll") ||
0 != _stricmp(fdFindData.cFileName, "cmroute.dll") )
{
}
else if ( 0 != _stricmp(fdFindData.cFileName, ".") &&
0 != _stricmp(fdFindData.cFileName, "..") )
{
ZeroMemory(&fOpStruct, sizeof(fOpStruct));
ZeroMemory(szFile, sizeof(szFile));
//StringCchPrintf(szFile, "%s\\%s", pszSource, fdFindData.cFileName);
fOpStruct.hwnd = NULL;
fOpStruct.wFunc = FO_DELETE;
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, &fdFindData))
{
if (ERROR_NO_MORE_FILES != GetLastError())
{
//
// We had some unexpected error, report unsuccessful completion
//
bReturn = FALSE;
}
// Exit loop
break;
}
}
if (INVALID_HANDLE_VALUE != hFileSearch)
{
FindClose(hFileSearch);
}
//
// Delete the old CMAK directory if it is not the same as the new directory.
//
if ( 0 != _stricmp(pszSource, pszDestination) ) {
ZeroMemory(&fOpStruct, sizeof(fOpStruct));
fOpStruct.hwnd = NULL;
fOpStruct.wFunc = FO_DELETE;
fOpStruct.pTo = NULL;
fOpStruct.pFrom = pszSource;
fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
bReturn &= (0== SHFileOperation(&fOpStruct)); //lint !e514, intended use of boolean, quintinb
}
return bReturn;
}
//+---------------------------------------------------------------------------
//
// 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(LPCTSTR pszCmakPath)
{
UNREFERENCED_PARAMETER( pszCmakPath );
OutputDebugString("ADMINPAK: DeleteOldCmakSubDirs...\n");
CHAR szCm32path[MAX_PATH+1];
CHAR szCm32SearchString[MAX_PATH+1];
CHAR szTemp[MAX_PATH+1];
HANDLE hCm32FileSearch;
WIN32_FIND_DATA fdCm32;
//
// Delete the old IEAK Docs Dir
//
//StringCchPrintf(szTemp, "%s\\%s", pszCmakPath, OC_OLD_IEAK_DOCDIR);
RemoveDirectory(szTemp);
//StringCchPrintf(szCm32path, c_szCm32Fmt, pszCmakPath);
//
// First look in the Cm32 directory itself. Delete all files found, continue down
// into subdirs.
//
//StringCchPrintf(szCm32SearchString, "%s\\*.*", szCm32path);
hCm32FileSearch = FindFirstFile(szCm32SearchString, &fdCm32);
while (INVALID_HANDLE_VALUE != hCm32FileSearch)
{
if (fdCm32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((0 != _stricmp(fdCm32.cFileName, ".")) &&
(0 != _stricmp(fdCm32.cFileName, "..")))
{
//
// 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.
//
CHAR szLangDirSearchString[MAX_PATH+1];
HANDLE hLangDirFileSearch;
WIN32_FIND_DATA fdLangDir;
//StringCchPrintf(szLangDirSearchString, "%s\\%s\\*.*", szCm32path, fdCm32.cFileName);
hLangDirFileSearch = FindFirstFile(szLangDirSearchString, &fdLangDir);
while (INVALID_HANDLE_VALUE != hLangDirFileSearch)
{
if (fdLangDir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((0 != _stricmp(fdLangDir.cFileName, ".")) &&
(0 != _stricmp(fdLangDir.cFileName, "..")))
{
//
// We only want to delete help files from our help source dirs
//
if (0 == _strnicmp(fdLangDir.cFileName, "CM", 2))
{
//
// Delete the four help files only.
//
//StringCchPrintf(szTemp, "%s\\%s\\%s\\cmctx32.rtf", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
DeleteFile(szTemp);
//StringCchPrintf(szTemp, "%s\\%s\\%s\\cmmgr32.h", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
DeleteFile(szTemp);
//StringCchPrintf(szTemp, "%s\\%s\\%s\\cmmgr32.hpj", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
DeleteFile(szTemp);
//StringCchPrintf(szTemp, "%s\\%s\\%s\\cmtrb32.rtf", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
DeleteFile(szTemp);
//
// Now try to remove the directory
//
//StringCchPrintf(szTemp, "%s\\%s\\%s", szCm32path, fd32.cFileName, fdLangDir.cFileName);
RemoveDirectory(szTemp);
}
}
}
else
{
//StringCchPrintf(szTemp, "%s\\%s\\%s", szCm32path, fdCm32.cFileName, fdLangDir.cFileName);
DeleteFile(szTemp);
}
//
// Check to see if we have any more Files
//
if (!FindNextFile(hLangDirFileSearch, &fdLangDir))
{
//
// Exit the loop
//
break;
}
}
if (INVALID_HANDLE_VALUE != hLangDirFileSearch)
{
FindClose(hLangDirFileSearch);
//
// Now try to remove the lang dir directory
//
//StringCchPrintf(szTemp, "%s\\%s", szCm32path, fdCm32.cFileName);
RemoveDirectory(szTemp);
}
}
}
else
{
//StringCchPrintf(szTemp, "%s\\%s", szCm32path, fdCm32.cFileName);
DeleteFile(szTemp);
}
//
// Check to see if we have any more Files
//
if (!FindNextFile(hCm32FileSearch, &fdCm32))
{
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(LPCTSTR pszGroupPath)
{
OutputDebugString("ADMINPAK: DeleteProgramGroupWithLinks...\n");
HANDLE hLinkSearch;
WIN32_FIND_DATA fdLinks;
CHAR szLinkSearchString[MAX_PATH+1];
CHAR szTemp[MAX_PATH+1];
//StringCchPrintf(szLinkSearchString, "%s\\*.*", pszGroupPath);
hLinkSearch = FindFirstFile(szLinkSearchString, &fdLinks);
while (INVALID_HANDLE_VALUE != szLinkSearchString)
{
if (!(fdLinks.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
//StringCchPrintf(szTemp, "%s\\%s", pszGroupPath, fdLinks.cFileName);
DeleteFile(szTemp);
}
//
// Check to see if we have any more Files
//
if (!FindNextFile(hLinkSearch, &fdLinks))
{
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()
{
OutputDebugString("ADMINPAK: DeleteOldNtopLinks...\n");
BOOL bResult = FALSE;
//
// First Delete the old NTOP4 Path
//
CHAR szGroup[MAX_PATH+1];
CHAR szTemp[MAX_PATH+1];
//
// Get the CSIDL_COMMON_PROGRAMS value
//
bResult = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_COMMON_PROGRAMS, FALSE);
if ( bResult == TRUE )
{
//StringCchPrintf(szGroup, "%s\\%s\\%s", szTemp, OC_NTOP4_GROUPNAME, OC_ICS_GROUPNAME);
DeleteProgramGroupWithLinks(szGroup);
//StringCchPrintf(szGroup, "%s\\%s\\%s", szTemp, OC_PWS_GROUPNAME, 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()
{
OutputDebugString("ADMINPAK: DeleteIeakCmakLinks...\n");
CHAR szUserDirRoot[MAX_PATH+1];
CHAR szGroup[MAX_PATH+1];
CHAR szTemp[MAX_PATH+1];
CHAR szEnd[MAX_PATH+1];
DWORD dwSize = _MAX_PATH;
HRESULT res;
//
// 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.
//
BOOL bResult = SHGetSpecialFolderPath(NULL, szUserDirRoot, CSIDL_DESKTOPDIRECTORY, FALSE);
if (bResult == TRUE)
{
//
// Remove \\Desktop
//
CHAR* pszTemp = strrchr(szUserDirRoot, '\\');
if (NULL == pszTemp)
{
return;
}
else
{
*pszTemp = '\0';
}
bResult = SHGetSpecialFolderPath(NULL, szTemp, CSIDL_PROGRAMS, FALSE);
if (bResult == TRUE )
{
if (0 == _strnicmp(szUserDirRoot, szTemp, strlen(szUserDirRoot)))
{
res = StringCchCopy(szEnd, dwSize, &(szTemp[strlen(szUserDirRoot)]));
if (res != S_OK)
return;
}
}
//
// Remove \\<User Name>>
//
pszTemp = strrchr(szUserDirRoot, '\\');
if (NULL == pszTemp)
{
return;
}
else
{
*pszTemp = '\0';
}
//
// Now start searching for user dirs to delete the CMAK group from
//
CHAR szUserDirSearchString[MAX_PATH+1];
HANDLE hUserDirSearch;
WIN32_FIND_DATA fdUserDirs;
//StringCchPrintf(szUserDirSearchString, "%s\\*.*", szUserDirRoot);
hUserDirSearch = FindFirstFile(szUserDirSearchString, &fdUserDirs);
while (INVALID_HANDLE_VALUE != hUserDirSearch)
{
if ((fdUserDirs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(0 != _stricmp(fdUserDirs.cFileName, ".")) &&
(0 != _stricmp(fdUserDirs.cFileName, "..")))
{
//StringCchPrintf(szGroup, "%s\\%s%s\\%s", szUserDirRoot, fdUserDirs.cFileName, szEnd, c_szCmakGroup);
DeleteProgramGroupWithLinks(szGroup);
}
if (!FindNextFile(hUserDirSearch, &fdUserDirs))
{
FindClose(hUserDirSearch);
//
// Exit the loop
//
break;
}
}
}
}
//+---------------------------------------------------------------------------
//
// Function: DeleteCmakRegKeys
//
// Purpose: Deletes the old Keys from Registery
//
//
// Arguments: None
//
// Returns: Nothing
//
// Author: Darryl W. Wood 13 Jul 1999
//
// Notes:
void DeleteCmakRegKeys()
{
OutputDebugString("ADMINPAK: DeleteCmakRegKeys...\n");
LRESULT lResult;
char szCmakUnInstRegPath[MAX_PATH] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\CMAK";
lResult = RegDeleteKey (
HKEY_LOCAL_MACHINE, // handle to open key
szCmakUnInstRegPath // address of name of subkey to delete
);
char szCmakAppRegPath[MAX_PATH] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\CMAK.EXE";
lResult = RegDeleteKey (
HKEY_LOCAL_MACHINE, // handle to open key
szCmakAppRegPath // address of name of subkey to delete
);
char szCmakAppUserInfoPath[MAX_PATH] = "SOFTWARE\\Microsoft\\Connection Manager Administration Kit\\User Info";
lResult = RegDeleteKey (
HKEY_LOCAL_MACHINE, // handle to open key
szCmakAppUserInfoPath // address of name of subkey to delete
);
}
//+---------------------------------------------------------------------------
//
// Function: CreateNewProfilesDirectory
//
// Author: Darryl W. Wood 13 Jul 1999
//
// Notes:
void CreateNewProfilesDirectory( LPCTSTR pszNewProfilePath )
{
OutputDebugString("ADMINPAK: CreateNewProfilesDirectory...\n");
char seps[] = "\\";
char *token = NULL;
char *szDriectoryString = NULL;
szDriectoryString = new char[MAX_PATH * sizeof(char)];
if ( NULL == szDriectoryString )
{
return;
}
char *szNewString = NULL;
szNewString = new char[MAX_PATH * sizeof(char)];
if ( NULL == szNewString )
{
if ( szDriectoryString != NULL )
{
delete [] szDriectoryString;
}
return;
}
HRESULT res;
DWORD dwSize = _MAX_PATH;
(void)StringCchCopy( szNewString, MAX_PATH * sizeof( char ), "" );
res = StringCchCopy(szDriectoryString, dwSize, pszNewProfilePath);
token = strtok( szDriectoryString, seps );
res = StringCchCopy(szNewString, dwSize, token);
res = StringCchCat(szNewString, dwSize, "\\");
while( token != NULL && res == S_OK )
{
/* Get next token: */
token = strtok( NULL, seps );
if ( token == NULL ) {
break;
}
res = StringCchCat(szNewString, dwSize, token);
::CreateDirectory(szNewString, NULL);
res = StringCchCat(szNewString, dwSize, "\\");
}
delete [] szDriectoryString;
delete [] szNewString;
}
HRESULT HrGetPBAPathIfInstalled(PSTR pszCpaPath, DWORD dwNumChars)
{
HRESULT hr;
HKEY hKey;
BOOL bFound = FALSE;
// We need to see if PBA is installed or not. If it is then we want to
// add back the PBA start menu link. If it isn't, then we want to do nothing
// with PBA.
//
ZeroMemory(pszCpaPath, sizeof(CHAR)*dwNumChars);
hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDaoClientsPath, 0, KEY_READ, &hKey);
if (SUCCEEDED(hr))
{
CHAR szCurrentValue[MAX_PATH+1];
CHAR szCurrentData[MAX_PATH+1];
DWORD dwValueSize = MAX_PATH;
DWORD dwDataSize = MAX_PATH;
DWORD dwType;
DWORD dwIndex = 0;
HRESULT res;
while (ERROR_SUCCESS == RegEnumValue(hKey, dwIndex, szCurrentValue, &dwValueSize, NULL, &dwType,
(LPBYTE)szCurrentData, &dwDataSize))
{
_strlwr(szCurrentValue);
if (NULL != strstr(szCurrentValue, "pbadmin.exe"))
{
//
// Then we have found the PBA path
//
CHAR* pszTemp = strrchr(szCurrentValue, '\\');
if (NULL != pszTemp)
{
*pszTemp = '\0';
res = StringCchCopy(pszCpaPath, dwDataSize ,szCurrentValue);
bFound = TRUE;
break;
}
}
dwValueSize = MAX_PATH;
dwDataSize = MAX_PATH;
dwIndex++;
}
RegCloseKey(hKey);
}
if (!bFound)
{
// We didn't find PBA, so lets return S_FALSE
//
hr = S_FALSE;
}
else
{
hr = S_OK;
}
return hr;
}
BOOL GetAdminToolsFolder(PSTR pszAdminTools)
{
BOOL bReturn = FALSE;
HRESULT res;
DWORD dwSize = _MAX_PATH;
if (pszAdminTools)
{
bReturn = SHGetSpecialFolderPath(NULL, pszAdminTools, CSIDL_COMMON_PROGRAMS, TRUE);
if (bReturn)
{
// Now Append Administrative Tools
//
res = StringCchCat(pszAdminTools, dwSize, OC_ADMIN_TOOLS);
if (res != S_OK)
return FALSE;
}
}
return bReturn;
}
HRESULT HrCreatePbaShortcut(PSTR pszCpaPath)
{
HRESULT hr = CoInitialize(NULL);
DWORD dwSize = _MAX_PATH;
if (SUCCEEDED(hr))
{
IShellLink *psl = NULL;
hr = CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, //CLSCTX_LOCAL_SERVER,
IID_IShellLink,
(LPVOID*)&psl);
if (SUCCEEDED(hr))
{
IPersistFile *ppf = NULL;
// Set up the properties of the Shortcut
//
static const CHAR c_szPbAdmin[] = "\\pbadmin.exe";
CHAR szPathToPbadmin[MAX_PATH+1] = {0};
DWORD dwLen = strlen(c_szPbAdmin) + strlen(pszCpaPath) + 1;
if (MAX_PATH >= dwLen)
{
// Set the Path to pbadmin.exe
//
hr = StringCchCopy(szPathToPbadmin, dwSize,pszCpaPath);
hr = StringCchCat(szPathToPbadmin, dwSize,c_szPbAdmin);
hr = psl->SetPath(szPathToPbadmin);
if (SUCCEEDED(hr))
{
// Set the Description to Phone Book Administrator
//
hr = psl->SetDescription(OC_PBA_DESC);
if (SUCCEEDED(hr))
{
hr = psl->QueryInterface(IID_IPersistFile,
(LPVOID *)&ppf);
if (SUCCEEDED(hr))
{
CHAR szAdminTools[MAX_PATH+1] = {0};
if (GetAdminToolsFolder(szAdminTools))
{
// Create the link file.
//
long nLenString = 0;
nLenString = strlen(szAdminTools) + 1;
WCHAR wszAdminTools[MAX_PATH+1] = {0};
mbstowcs( wszAdminTools, szAdminTools, nLenString );
hr = ppf->Save(wszAdminTools, TRUE);
}
if ( ppf ) {
ppf->Release();
ppf = NULL;
}
}
}
}
}
if ( psl ) {
psl->Release();
psl = NULL;
}
}
CoUninitialize();
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// MMC Detection Code
//
//Sets the MMCDETECTED property to True if MMC is found to be running on the machine
extern "C" ADMINPAK_API int __stdcall fnDetectMMC(MSIHANDLE hInstall)
{
HWND lpWindowReturned = NULL;
lpWindowReturned = FindWindowEx(NULL, NULL, "MMCMainFrame",NULL);
if (lpWindowReturned != NULL)
MsiSetProperty(hInstall, TEXT("MMCDETECTED"), "Yes"); //set property in MSI
else
MsiSetProperty(hInstall, TEXT("MMCDETECTED"), "No"); //set property in MSI
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// Admin Tools start menu folder Code
//
//Sets the AdminTools start menu folder to On
extern "C" ADMINPAK_API int __stdcall fnAdminToolsFolderOn(MSIHANDLE hInstall)
{
DWORD dwError = NO_ERROR;
HKEY hKey;
LPCTSTR key = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
LPCTSTR value = "Not set";
DWORD data = 0;
UNREFERENCED_PARAMETER( hInstall );
//Open key to write to in the registry
dwError = RegOpenKeyEx(HKEY_CURRENT_USER,key, 0, KEY_WRITE, &hKey );
if ( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
//Turn on the admin tools folder via their reg keys
data = 2;
value = "Start_AdminToolsRoot";
dwError = RegSetValueEx(hKey, value, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
if ( dwError != ERROR_SUCCESS )
{
RegCloseKey(hKey);
return ERROR_INVALID_HANDLE;
}
data = 1;
value = "StartMenuAdminTools";
dwError = RegSetValueEx(hKey, value, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
if ( dwError != ERROR_SUCCESS )
{
RegCloseKey(hKey);
return ERROR_INVALID_HANDLE;
}
//Close key and exit
RegCloseKey(hKey);
return ERROR_SUCCESS;
}
//Sets the AdminTools start menu folder to Off
extern "C" ADMINPAK_API int __stdcall fnAdminToolsFolderOff(MSIHANDLE hInstall)
{
DWORD dwError = NO_ERROR;
HKEY hKey;
const TCHAR key[] = TEXT( "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced" );
const TCHAR valueRoot[] = TEXT( "Start_AdminToolsRoot" );
const TCHAR valueMenu[] = TEXT( "StartMenuAdminTools" );
TCHAR lparam[] = TEXT( "Policy" );
DWORD data = 0;
DWORD_PTR dwResult = 0; //unused
UNREFERENCED_PARAMETER( hInstall );
//Open key to write to in the registry
dwError = RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_WRITE, &hKey );
if ( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
//Turn off the admin tools folder via their reg keys
// value = "Start_AdminToolsRoot";
data = 0;
dwError = RegSetValueEx(hKey, valueRoot, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
if ( dwError != ERROR_SUCCESS )
{
RegCloseKey(hKey);
return ERROR_INVALID_HANDLE;
}
// value = "StartMenuAdminTools";
data = 0;
dwError = RegSetValueEx(hKey, valueMenu, 0, REG_DWORD, (CONST BYTE *)&data, sizeof(data));
if ( dwError != ERROR_SUCCESS )
{
RegCloseKey(hKey);
return ERROR_INVALID_HANDLE;
}
//Close key and exit
RegCloseKey(hKey);
//Undocumented API call to force a redraw of the start menu to remove the admin tools folder without logging off or having the user have to manually "apply" the changes to the start menu
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) lparam , SMTO_ABORTIFHUNG, 1000, &dwResult );
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
//AdminpakBackup table handling Code
//
//Backup files from the AdminpakBackup table
extern "C" ADMINPAK_API int __stdcall fnBackupAdminpakBackupTable(MSIHANDLE hInstall)
{
DWORD dwLength = MAX_PATH; //Length of string to return from MSI
DWORD dwError = NO_ERROR; //Error variable
TCHAR szDir[MAX_PATH]; //Directory read from the MSI
TCHAR szDirFromMSI[MAX_PATH]; //Directory read from Adminbackup table
TCHAR szFileToBackup[MAX_PATH]; //File name to backup
TCHAR szBackupFileName[MAX_PATH]; //Backed up file name
TCHAR szFileToBackupFromMSI[MAX_PATH]; //File name to backup from MSI
TCHAR szBackupFileNameFromMSI[MAX_PATH]; //Backed up file name
HRESULT res;
PMSIHANDLE hView; //MSI view handle
PMSIHANDLE hRecord; //MSI record handle
PMSIHANDLE hDatabase; //MSI database handle
TCHAR szSQL[MAX_PATH]; //SQL to return table from MSI
res = StringCchCopy(szSQL, dwLength,TEXT("SELECT * FROM `AdminpackBackup`"));
// Get a handle on the MSI database
hDatabase = MsiGetActiveDatabase(hInstall);
if( hDatabase == 0 )
return ERROR_INVALID_HANDLE;
//Get a view of our table in the MSI
dwError = MsiDatabaseOpenView(hDatabase, szSQL, &hView );
if( dwError == ERROR_SUCCESS )
dwError = MsiViewExecute(hView, NULL );
// If no errors, get our records
if( dwError != ERROR_SUCCESS )
{
return ERROR_INVALID_HANDLE;
}
else
{
//Loop through records in the AdminpakBackup table
while(MsiViewFetch(hView, &hRecord ) == ERROR_SUCCESS )
{
dwError = MsiRecordGetString(hRecord, BACKUPFILENAME, szBackupFileNameFromMSI , &dwLength);
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
dwError = MsiRecordGetString(hRecord, ORIGINALFILENAME, szFileToBackupFromMSI , &dwLength);
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
dwError = MsiRecordGetString(hRecord, BACKUPDIRECTORY, szDirFromMSI , &dwLength);
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
dwError = MsiGetProperty( hInstall, TEXT(szDirFromMSI), szDir, &dwLength );
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
//Build up the paths for the file to backup
res = StringCchCopy(szFileToBackup, dwLength ,szDir);
res = StringCchCat(szFileToBackup, dwLength, szFileToBackupFromMSI);
res = StringCchCopy(szBackupFileName, dwLength, szDir);
res = StringCchCat(szBackupFileName, dwLength, szBackupFileNameFromMSI);
//Perform backup
//We know MoveFileEx is inseucure due to ACL's, but we are moving to same directory and planing on moving file back on uninstall, so we should be OK as far as ACL's are concearned
if (res == S_OK)
{
dwError = MoveFileEx(szFileToBackup,szBackupFileName, MOVEFILE_WRITE_THROUGH);
}
if( dwError == 0 )
{
if ( GetLastError() == ERROR_FILE_NOT_FOUND )
{
// ignore this error
}
else
{
// even in this case, we will ignore this error
// this is because, anyhow, the failure of this action
// will not stop from MSI installing the package --
// so, practically, there is no meaning in stoping this action in middle
//
// return ERROR_INVALID_HANDLE;
//
}
}
dwError = MsiCloseHandle(hRecord); //Close record
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
}
}
dwError = MsiViewClose( hView ); //Close view
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwError = MsiCloseHandle( hDatabase ); //Close Database
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
return ERROR_SUCCESS;
}
//Restores files specified in the AdminpakBackup table, called during uninstall...
extern "C" ADMINPAK_API int __stdcall fnRestoreAdminpakBackupTable(MSIHANDLE hInstall)
{
DWORD dwLength = MAX_PATH; //Length of string to return from MSI
DWORD dwError = ERROR_SUCCESS; //Error variable
HRESULT res;
TCHAR szDir[MAX_PATH]; //Directory read from the MSI
TCHAR szDirFromMSI[MAX_PATH]; //Directory read from Adminbackup table
TCHAR szFileToRestore[MAX_PATH]; //File name to restore
TCHAR szBackupFileName[MAX_PATH]; //Backed up file name
TCHAR szFileToRestoreFromMSI[MAX_PATH]; //File name to restore
TCHAR szBackupFileNameFromMSI[MAX_PATH]; //Backed up file name
TCHAR szSQL[MAX_PATH]; //SQL to return table from MSI
res = StringCchCopy(szSQL, dwLength, TEXT("SELECT * FROM `AdminpackBackup`"));
PMSIHANDLE hView; //MSI view handle
PMSIHANDLE hRecord; //MSI record handle
PMSIHANDLE hDatabase; //MSI database handle
// Get a handle on the MSI database
hDatabase = MsiGetActiveDatabase(hInstall);
if( hDatabase == 0 )
return ERROR_INVALID_HANDLE;
//Get a view of our table in the MSI
dwError = MsiDatabaseOpenView(hDatabase, szSQL, &hView );
if( dwError == ERROR_SUCCESS )
dwError = MsiViewExecute(hView, NULL );
// If no errors, get our records
if( dwError != ERROR_SUCCESS )
{
return ERROR_INVALID_HANDLE;
}
else
{
//Loop through records in the AdminpakBackup table
while(MsiViewFetch(hView, &hRecord ) == ERROR_SUCCESS )
{
dwError = MsiRecordGetString(hRecord, ORIGINALFILENAME, szBackupFileNameFromMSI , &dwLength);
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
dwError = MsiRecordGetString(hRecord, BACKUPFILENAME, szFileToRestoreFromMSI , &dwLength);
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
dwError = MsiRecordGetString(hRecord, BACKUPDIRECTORY, szDirFromMSI , &dwLength);
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
dwError = MsiGetProperty( hInstall, TEXT(szDirFromMSI), szDir, &dwLength );
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwLength = MAX_PATH;
//Build up the paths for the file to restore
res = StringCchCopy(szFileToRestore, dwLength, szDir);
res = StringCchCat(szFileToRestore, dwLength, szBackupFileNameFromMSI);
res = StringCchCopy(szBackupFileName, dwLength, szDir);
res = StringCchCat(szBackupFileName, dwLength, szFileToRestoreFromMSI);
//Perform restore
dwError = MoveFileEx(szBackupFileName, szFileToRestore, MOVEFILE_REPLACE_EXISTING); //Restore the file
if( dwError == 0 )
{
if ( GetLastError() == ERROR_FILE_NOT_FOUND )
{
// ignore this error
}
else
{
// even in this case, we will ignore this error
// this is because, anyhow, the failure of this action
// will not stop from MSI installing the package --
// so, practically, there is no meaning in stoping this action in middle
//
// return ERROR_INVALID_HANDLE;
//
}
}
dwError = MsiCloseHandle(hRecord); //Close Record
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
}
}
dwError = MsiViewClose(hView); //Close View
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
dwError = MsiCloseHandle(hDatabase); //Close Database
if( dwError != ERROR_SUCCESS )
return ERROR_INVALID_HANDLE;
return ERROR_SUCCESS;
}
// check whether the OEM code page and SYSTEM code are same or not
extern "C" ADMINPAK_API int __stdcall fnNativeOSLanguage( MSIHANDLE hInstall )
{
// local variables
HRESULT hr = S_OK;
LANGID langOEM = 0;
WCHAR wszLanguageCode[ 10 ] = L"\0";
// get the OEM code page
langOEM = GetSystemDefaultUILanguage();
// convert the numeric value into string format
hr = StringCchPrintfW( wszLanguageCode, 10, L"%d", langOEM );
if ( FAILED( hr ) )
{
return ERROR_INVALID_HANDLE;
}
// save the native OS language information
MsiSetPropertyW( hInstall, L"NativeOSLanguage", wszLanguageCode );
// return success
return ERROR_SUCCESS;
}
void fnDeleteShortcut(MSIHANDLE, TCHAR[_MAX_PATH]);
//Cleans up after a Win2k adminpak upgrade as Win2k adminpak leaves behind several shortcuts that we need to clean up after
extern "C" ADMINPAK_API int __stdcall fnCleanW2KUpgrade( MSIHANDLE hInstall )
{
//Call fnDeleteShortcut with the name of the shortcut you want to delete
fnDeleteShortcut(hInstall, "Internet Services Manager");
fnDeleteShortcut(hInstall, "Routing and Remote Access");
fnDeleteShortcut(hInstall, "Distributed File System");
fnDeleteShortcut(hInstall, "Local Security Policy");
// return success
return ERROR_SUCCESS;
}
//Actually does the shortcut deletion
void fnDeleteShortcut(MSIHANDLE hInstall, TCHAR LinkName[])
{
HRESULT hr = S_OK;
TCHAR buf[_MAX_PATH]; //shortcut path/name buffer
DWORD dwLength = _MAX_PATH; //Length of string to return from MSI
LPITEMIDLIST pidl; //used to get admin tools shortcut path
UNREFERENCED_PARAMETER( hInstall );
//get admin tools shortcut folder
hr = SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_ADMINTOOLS, &pidl );
SHGetPathFromIDList(pidl, buf);
//append shortcut name and extention
hr = StringCchCat( buf, dwLength, "\\" );
hr = StringCchCat( buf, dwLength, LinkName );
hr = StringCchCat( buf, dwLength, ".lnk");
//delete the shortcut and return
DeleteFile( buf );
}
BOOL TranslateVersionString( LPCWSTR pwszVersion, PTVERSION pVersion )
{
// local variables
DWORD dwLoop = 0;
LONG lPosition = 0;
CHString strTemp;
CHString strVersion;
CHString strVersionField;
LPWSTR pwszTemp = NULL;
LPWSTR pwszNumber = NULL;
DWORD dwNumbers[ 4 ];
// check the input parameters
if ( pVersion == NULL || pwszVersion == NULL )
{
return FALSE;
}
// init the version struct to zero's
ZeroMemory( pVersion, sizeof( TVERSION ) );
ZeroMemory( dwNumbers, 4 * sizeof( DWORD ) );
try
{
// get the version info into the class variable
strVersion = pwszVersion;
// trim the string
strVersion.TrimLeft();
strVersion.TrimRight();
// cut the string till the first space we encountered in it
lPosition = strVersion.Find( L' ' );
if ( lPosition != -1 )
{
strTemp = strVersion.Mid( 0, lPosition );
strVersion = strTemp;
}
// we need to get 4 parts from the version string
for ( dwLoop = 0; dwLoop < 4; dwLoop++ )
{
lPosition = strVersion.Find( L'.' );
if ( lPosition == -1 )
{
// this might be the last number
if ( strVersion.GetLength() == 0 )
{
break;
}
else
{
strVersionField = strVersion;
strVersion.Empty();
}
}
else
{
strVersionField = strVersion.Mid( 0, lPosition );
strTemp = strVersion.Mid( lPosition + 1 );
strVersion = strTemp;
}
// get the version field internal buffer
// NOTE: assuming no. of digits in a version string is never going to larger than 10 digits
pwszNumber = strVersionField.GetBuffer( 10 );
if ( pwszNumber == NULL )
{
return FALSE;
}
// convert the number
dwNumbers[ dwLoop ] = wcstoul( pwszNumber, &pwszTemp, 10 );
//
// check the validity of the number
//
if ( errno == ERANGE || (pwszTemp != NULL && lstrlenW( pwszTemp ) != 0 ))
{
strVersionField.ReleaseBuffer( -1 );
return FALSE;
}
// release the buffer
strVersionField.ReleaseBuffer( -1 );
}
// check the no. of loops that are done -- it the loops are not equal to 3, error
// we dont care whether we got the sub-revision or not -- so, we are not checking for 4 here
if ( dwLoop < 3 || strVersion.GetLength() != 0 )
{
return FALSE;
}
// everything went well
pVersion->dwMajor = dwNumbers[ 0 ];
pVersion->dwMinor = dwNumbers[ 1 ];
pVersion->dwRevision = dwNumbers[ 2 ];
pVersion->dwSubRevision = dwNumbers[ 3 ];
// return
return TRUE;
}
catch( ... )
{
return FALSE;
}
}
LONG CheckFileVersion( LPCWSTR pwszFileName,
LPCWSTR pwszRequiredInternalName,
LPCWSTR pwszRequiredFileVersion )
{
// local variables
DWORD dw = 0;
UINT dwSize = 0;
UINT dwTranslateSize = 0;
LPVOID pVersionInfo = NULL;
PTTRANSLATE pTranslate = NULL;
LPCWSTR pwszFileVersion = NULL;
LPCWSTR pwszInternalName = NULL;
TVERSION verFileVersion;
TVERSION verRequiredFileVersion;
// check the input
// NOTE: we dont care whether "pwszRequiredInternalName" is passed or not
if ( pwszFileName == NULL || pwszRequiredFileVersion == NULL )
{
return translateError;
}
// translate the required file version string into TVERSION struct
if ( TranslateVersionString( pwszRequiredFileVersion, &verRequiredFileVersion ) == FALSE )
{
// version string passed is invalid
return translateError;
}
// init
dw = 0;
dwSize = _MAX_PATH;
// get the version information size
dwSize = GetFileVersionInfoSizeW( pwszFileName, 0 );
if ( dwSize == 0 )
{
// tool might have encountered error (or)
// tool doesn't have version information
// but version information is mandatory for us
// so, just exit
if ( GetLastError() == NO_ERROR )
{
SetLastError( ERROR_INVALID_PARAMETER );
return translateError;
}
// ...
return translateError;
}
// allocate memory for the version resource
// take some 10 bytes extra -- for safety purposes
dwSize += 10;
pVersionInfo = new BYTE[ dwSize ];
if ( pVersionInfo == NULL )
{
return translateError;
}
// now get the version information
if ( GetFileVersionInfoW( pwszFileName, 0, dwSize, pVersionInfo ) == FALSE )
{
delete [] pVersionInfo;
return translateError;
}
// get the translation info
if ( VerQueryValueW( pVersionInfo,
L"\\VarFileInfo\\Translation",
(LPVOID*) &pTranslate, &dwTranslateSize ) == FALSE )
{
delete [] pVersionInfo;
return translateError;
}
// try to get the internal name of the tool for each language and code page.
pwszFileVersion = NULL;
pwszInternalName = NULL;
for( dw = 0; dw < ( dwTranslateSize / sizeof( TTRANSLATE ) ); dw++ )
{
try
{
//
// prepare the format string to get the localized the version info
//
CHString strBuffer;
LPWSTR pwszBuffer = NULL;
//
// file version
strBuffer.Format(
L"\\StringFileInfo\\%04x%04x\\FileVersion",
pTranslate[ dw ].wLanguage, pTranslate[ dw ].wCodePage );
// retrieve file description for language and code page "i".
pwszBuffer = strBuffer.LockBuffer();
if ( VerQueryValueW( pVersionInfo, pwszBuffer,
(LPVOID*) &pwszFileVersion, &dwSize ) == FALSE )
{
// we cannot decide the failure based on the result of this
// function failure -- we will decide about this
// after terminating from the 'for' loop
// for now, make the pwszFileVersion to NULL -- this will
// enable us to decide the result
pwszFileVersion = NULL;
}
// release the earlier access buffer
strBuffer.UnlockBuffer();
//
// internal name
strBuffer.Format(
L"\\StringFileInfo\\%04x%04x\\InternalName",
pTranslate[ dw ].wLanguage, pTranslate[ dw ].wCodePage );
// retrieve file description for language and code page "i".
pwszBuffer = strBuffer.LockBuffer();
if ( VerQueryValueW( pVersionInfo, pwszBuffer,
(LPVOID*) &pwszInternalName, &dwSize ) == FALSE )
{
// we cannot decide the failure based on the result of this
// function failure -- we will decide about this
// after terminating from the 'for' loop
// for now, make the pwszInternalName to NULL -- this will
// enable us to decide the result
pwszInternalName = NULL;
}
// release the earlier access buffer
strBuffer.UnlockBuffer();
// check whether we got the information that we are looking for or not
if ( pwszInternalName != NULL && pwszFileVersion != NULL )
{
// we got the information
break;
}
}
catch( ... )
{
// do not return -- we might miss the cleanup
// so just break from the loop and rest will be taken care
// outside the loop
pwszFileVersion = NULL;
pwszInternalName = NULL;
break;
}
}
// check whether we got the information or we need or not
if ( pwszInternalName == NULL || pwszFileVersion == NULL )
{
delete [] pVersionInfo;
return translateError;
}
// check the internal name -- this is important to make sure that
// user is not trying to cheat the installation
if ( pwszRequiredInternalName != NULL )
{
if ( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE,
pwszInternalName, -1, pwszRequiredInternalName, -1 ) != CSTR_EQUAL )
{
// installation is being cheated
delete [] pVersionInfo;
return translateWrongFile;
}
}
//
// translate the version string
if ( TranslateVersionString( pwszFileVersion, &verFileVersion ) == FALSE )
{
delete [] pVersionInfo;
return translateError;
}
// we are dont with pVersionInfo -- release the memory
delete [] pVersionInfo;
//
// now compare the file version with the required file version
// major version
if ( verFileVersion.dwMajor == verRequiredFileVersion.dwMajor )
{
// need to proceed with checking minor version
}
else if ( verFileVersion.dwMajor < verRequiredFileVersion.dwMajor )
{
return translateLesser;
}
else if ( verFileVersion.dwMajor > verRequiredFileVersion.dwMajor )
{
return translateGreater;
}
// minor version
if ( verFileVersion.dwMinor == verRequiredFileVersion.dwMinor )
{
// need to proceed with checking revision (build number)
}
else if ( verFileVersion.dwMinor < verRequiredFileVersion.dwMinor )
{
return translateLesser;
}
else if ( verFileVersion.dwMinor > verRequiredFileVersion.dwMinor )
{
return translateGreater;
}
// revision (build number)
if ( verFileVersion.dwRevision == verRequiredFileVersion.dwRevision )
{
// need to proceed with checking sub-revision (QFE / SP)
}
else if ( verFileVersion.dwRevision < verRequiredFileVersion.dwRevision )
{
return translateLesser;
}
else if ( verFileVersion.dwRevision > verRequiredFileVersion.dwRevision )
{
return translateGreater;
}
// sub-revision (QFE / SP)
if ( verFileVersion.dwSubRevision == verRequiredFileVersion.dwSubRevision )
{
// done -- version's matched
return translateEqual;
}
else if ( verFileVersion.dwSubRevision < verRequiredFileVersion.dwSubRevision )
{
return translateLesser;
}
else if ( verFileVersion.dwSubRevision > verRequiredFileVersion.dwSubRevision )
{
return translateGreater;
}
// return -- we should not come to this point -- if reached -- error
return translateError;
}
// verify the existence of the QFE
extern "C" ADMINPAK_API int __stdcall fnCheckForQFE( MSIHANDLE hInstall )
{
// local variables
CHString strFile;
CHString strSystemDirectory;
// get the path reference to the "system32" directory
// NOTE: we cannot proceed if we cant get the path to the "system32" directory
if ( PropertyGet_String( hInstall, L"SystemFolder", strSystemDirectory ) == FALSE )
{
return ERROR_INVALID_HANDLE;
}
// form the path
strFile.Format( L"%s%s", strSystemDirectory, L"dsprop.dll" );
// now check ...
switch( CheckFileVersion( strFile, L"ShADprop", L"5.1.2600.101" ) )
{
case translateEqual:
case translateGreater:
{
// set the native OS language information
MsiSetPropertyW( hInstall, L"QFE_DSPROP", L"Yes" );
break;
}
default:
// do nothing
break;
}
// return
return ERROR_SUCCESS;
}