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.
1323 lines
36 KiB
1323 lines
36 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
Fns.cpp
|
|
|
|
Abstract:
|
|
|
|
Contains all of the functions used by the
|
|
application.
|
|
|
|
Notes:
|
|
|
|
Unicode only - Windows 2000, XP & Server 2003
|
|
|
|
History:
|
|
|
|
01/02/2002 rparsons Created
|
|
01/08/2002 rparsons Restructured a bit to add some
|
|
required functionality
|
|
01/10/2002 rparsons Change wsprintf to snwprintf
|
|
01/18/2002 rparsons Major changes - made more installer like
|
|
02/15/2002 rparsons Install SDBInst on W2K.
|
|
Include strsafe.
|
|
04/19/2002 rparsons Install different catalogs for Server 2003 & XP.
|
|
|
|
--*/
|
|
#include "main.h"
|
|
|
|
extern APPINFO g_ai;
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve file version info from a file.
|
|
|
|
The version is specified in the dwFileVersionMS and dwFileVersionLS fields
|
|
of a VS_FIXEDFILEINFO, as filled in by the win32 version APIs.
|
|
|
|
If the file is not a coff image or does not have version resources,
|
|
the function fails.
|
|
|
|
Arguments:
|
|
|
|
pwszFileName - Supplies the full path of the file whose version
|
|
data is desired.
|
|
|
|
pdwlVersion - Receives the version stamp of the file.
|
|
If the file is not a coff image or does not contain
|
|
the appropriate version resource data, the function fails.
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
GetVersionInfoFromImage(
|
|
IN LPWSTR pwszFileName,
|
|
OUT PDWORDLONG pdwlVersion
|
|
)
|
|
{
|
|
UINT cchSize;
|
|
DWORD cbSize, dwIgnored;
|
|
BOOL bResult = FALSE;
|
|
PVOID pVersionBlock = NULL;
|
|
VS_FIXEDFILEINFO* pffi = NULL;
|
|
|
|
if (!pwszFileName || !pdwlVersion) {
|
|
DPF(dlError, "[GetVersionInfoFromImage] Invalid arguments");
|
|
return FALSE;
|
|
}
|
|
|
|
cbSize = GetFileVersionInfoSize(pwszFileName, &dwIgnored);
|
|
|
|
if (0 == cbSize) {
|
|
DPF(dlError,
|
|
"[GetVersionInfoFromImage] 0x%08X Failed to get version size",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Allocate memory block of sufficient size to hold version info block.
|
|
//
|
|
pVersionBlock = HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
cbSize);
|
|
|
|
if (!pVersionBlock) {
|
|
DPF(dlError, "[GetVersionInfoFromImage] Unable to allocate memory");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the version block from the file.
|
|
//
|
|
if (!GetFileVersionInfo(pwszFileName,
|
|
0,
|
|
cbSize,
|
|
pVersionBlock)) {
|
|
DPF(dlError,
|
|
"[GetVersionInfoFromImage] 0x%08X Failed to get version info",
|
|
GetLastError());
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get fixed version info.
|
|
//
|
|
if (!VerQueryValue(pVersionBlock,
|
|
L"\\",
|
|
(LPVOID*)&pffi,
|
|
&cchSize)) {
|
|
DPF(dlError,
|
|
"[GetVersionInfoFromImage] 0x%08X Failed to fixed version info",
|
|
GetLastError());
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Return version to caller.
|
|
//
|
|
*pdwlVersion = (((DWORDLONG)pffi->dwFileVersionMS) << 32) +
|
|
pffi->dwFileVersionLS;
|
|
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
|
|
if (pVersionBlock) {
|
|
HeapFree(GetProcessHeap(), 0, pVersionBlock);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes our data structures with information about
|
|
the files that we're installing/uninstalling.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
InitializeFileInfo(
|
|
void
|
|
)
|
|
{
|
|
UINT uCount = 0;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Set up the information for each file.
|
|
// I realize that a for loop seems much more suitable here,
|
|
// but we have to match up the destination for each file.
|
|
// Ideally, we would have a INF file to read from that tells
|
|
// us where to install each file.
|
|
// For now, copying and pasting is all we need to do.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_APPVERIF_EXE);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (1)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_APPVERIF_EXE,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (2)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\"FILENAME_APPVERIF_EXE,
|
|
g_ai.wszSysDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (3)");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlSrcFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszSrcFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetFileAttributes(g_ai.rgFileInfo[uCount].wszDestFileName) != -1) {
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlDestFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszDestFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_APPVERIF_EXE_PDB);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (4)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_APPVERIF_EXE_PDB,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (5)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\"FILENAME_APPVERIF_EXE_PDB,
|
|
g_ai.wszSysDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (6)");
|
|
return FALSE;
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_APPVERIF_CHM);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (7)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_APPVERIF_CHM,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (8)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\"FILENAME_APPVERIF_CHM,
|
|
g_ai.wszSysDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (9)");
|
|
return FALSE;
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_ACVERFYR_DLL);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (10)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_ACVERFYR_DLL,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (11)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\AppPatch\\"FILENAME_ACVERFYR_DLL,
|
|
g_ai.wszWinDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (12)");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlSrcFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszSrcFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetFileAttributes(g_ai.rgFileInfo[uCount].wszDestFileName) != -1) {
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlDestFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszDestFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_ACVERFYR_DLL_PDB);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (13)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_ACVERFYR_DLL_PDB,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (14)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\AppPatch\\"FILENAME_ACVERFYR_DLL_PDB,
|
|
g_ai.wszWinDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (15)");
|
|
return FALSE;
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_ACVERFYR_DLL);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (16)");
|
|
return FALSE;
|
|
}
|
|
|
|
g_ai.rgFileInfo[uCount].bWin2KOnly = TRUE;
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_ACVERFYR_DLL_W2K,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (17)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\AppPatch\\"FILENAME_ACVERFYR_DLL,
|
|
g_ai.wszWinDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (18)");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlSrcFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszSrcFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetFileAttributes(g_ai.rgFileInfo[uCount].wszDestFileName) != -1) {
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlDestFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszDestFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_ACVERFYR_DLL_PDB);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (19)");
|
|
return FALSE;
|
|
}
|
|
|
|
g_ai.rgFileInfo[uCount].bWin2KOnly = TRUE;
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_ACVERFYR_DLL_W2K_PDB,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (20)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\AppPatch\\"FILENAME_ACVERFYR_DLL_PDB,
|
|
g_ai.wszWinDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (21)");
|
|
return FALSE;
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_MSVCP60_DLL);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (22)");
|
|
return FALSE;
|
|
}
|
|
|
|
g_ai.rgFileInfo[uCount].bWin2KOnly = TRUE;
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_MSVCP60_DLL,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (23)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\"FILENAME_MSVCP60_DLL,
|
|
g_ai.wszWinDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (24)");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlSrcFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszSrcFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetFileAttributes(g_ai.rgFileInfo[uCount].wszDestFileName) != -1) {
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlDestFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszDestFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Next file.
|
|
//
|
|
hr = StringCchCopy(g_ai.rgFileInfo[uCount].wszFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszFileName),
|
|
FILENAME_SDBINST_EXE);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (25)");
|
|
return FALSE;
|
|
}
|
|
|
|
g_ai.rgFileInfo[uCount].bWin2KOnly = TRUE;
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszSrcFileName),
|
|
L"%ls\\"FILENAME_SDBINST_EXE,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (26)");
|
|
return FALSE;
|
|
}
|
|
|
|
hr = StringCchPrintf(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
ARRAYSIZE(g_ai.rgFileInfo[uCount].wszDestFileName),
|
|
L"%ls\\"FILENAME_SDBINST_EXE,
|
|
g_ai.wszSysDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeFileInfo] Buffer too small (27)");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlSrcFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszSrcFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetFileAttributes(g_ai.rgFileInfo[uCount].wszDestFileName) != -1) {
|
|
if (!GetVersionInfoFromImage(g_ai.rgFileInfo[uCount].wszDestFileName,
|
|
&g_ai.rgFileInfo[uCount].dwlDestFileVersion)) {
|
|
DPF(dlError,
|
|
"[InitializeFileInfo] Failed to get version info for %ls",
|
|
g_ai.rgFileInfo[uCount].wszDestFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if any of the files we have to offer
|
|
are newer than ones already installed.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if we have at least one new file to offer.
|
|
FALSE if we don't have at least one new file to offer.
|
|
|
|
--*/
|
|
BOOL
|
|
InstallCheckFileVersions(
|
|
void
|
|
)
|
|
{
|
|
UINT uCount;
|
|
BOOL bReturn = FALSE;
|
|
|
|
for (uCount = 0; uCount < NUM_FILES; uCount++) {
|
|
if (g_ai.rgFileInfo[uCount].dwlSrcFileVersion >=
|
|
g_ai.rgFileInfo[uCount].dwlDestFileVersion) {
|
|
g_ai.rgFileInfo[uCount].bInstall = TRUE;
|
|
bReturn = TRUE;
|
|
}
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if we have a newer version of appverif.exe
|
|
or acverfyr.dll to offer.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if our version is newer than the one installed.
|
|
or if there is no version installed.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
IsPkgAppVerifNewer(
|
|
void
|
|
)
|
|
{
|
|
//
|
|
// Check appverif.exe first.
|
|
//
|
|
if (g_ai.rgFileInfo[0].dwlSrcFileVersion >=
|
|
g_ai.rgFileInfo[0].dwlDestFileVersion) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Check acverfyr.dll if appverif.exe didn't pan out.
|
|
// Do this based on the platform.
|
|
//
|
|
if (g_ai.ePlatform == osWindowsXP || g_ai.ePlatform == osWindowsDotNet) {
|
|
if (g_ai.rgFileInfo[1].dwlSrcFileVersion >=
|
|
g_ai.rgFileInfo[1].dwlDestFileVersion) {
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
if (g_ai.rgFileInfo[2].dwlSrcFileVersion >=
|
|
g_ai.rgFileInfo[2].dwlDestFileVersion) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Perhaps we have a newer version of sdbinst to offer.
|
|
//
|
|
if (g_ai.ePlatform == osWindows2000) {
|
|
if (g_ai.rgFileInfo[8].dwlSrcFileVersion >=
|
|
g_ai.rgFileInfo[8].dwlDestFileVersion) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs a file copy, even if it's in use.
|
|
|
|
Arguments:
|
|
|
|
pwszSourceFileName - Name of the source file to copy.
|
|
pwszDestFileName - Name of the destination file to replace.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
ForceCopy(
|
|
IN LPCWSTR pwszSourceFileName,
|
|
IN LPCWSTR pwszDestFileName
|
|
)
|
|
{
|
|
WCHAR wszTempPath[MAX_PATH];
|
|
WCHAR wszDelFileName[MAX_PATH];
|
|
DWORD cchSize;
|
|
|
|
if (!pwszSourceFileName || !pwszDestFileName) {
|
|
DPF(dlError, "[ForceCopy] Invalid parameters");
|
|
return FALSE;
|
|
}
|
|
|
|
DPF(dlInfo, "[ForceCopy] Source file: %ls", pwszSourceFileName);
|
|
DPF(dlInfo, "[ForceCopy] Destination file: %ls", pwszDestFileName);
|
|
|
|
if (!CopyFile(pwszSourceFileName, pwszDestFileName, FALSE)) {
|
|
|
|
cchSize = GetTempPath(ARRAYSIZE(wszTempPath), wszTempPath);
|
|
|
|
if (cchSize > ARRAYSIZE(wszTempPath) || cchSize == 0) {
|
|
DPF(dlError, "[ForceCopy] Buffer for temp path is too small");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetTempFileName(wszTempPath, L"del", 0, wszDelFileName)) {
|
|
DPF(dlError,
|
|
"[ForceCopy] 0x%08X Failed to get temp file",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if (!MoveFileEx(pwszDestFileName,
|
|
wszDelFileName,
|
|
MOVEFILE_REPLACE_EXISTING)) {
|
|
DPF(dlError,
|
|
"[ForceCopy] 0x%08X Failed to replace file",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if (!MoveFileEx(wszDelFileName,
|
|
NULL,
|
|
MOVEFILE_DELAY_UNTIL_REBOOT)) {
|
|
DPF(dlError,
|
|
"[ForceCopy] 0x%08X Failed to delete file",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
if (!CopyFile(pwszSourceFileName, pwszDestFileName, FALSE)) {
|
|
DPF(dlError,
|
|
"[ForceCopy] 0x%08X Failed to copy file",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a formatted string to the debugger.
|
|
|
|
Arguments:
|
|
|
|
dwDetail - Specifies the level of the information provided.
|
|
pszFmt - The string to be displayed.
|
|
... - A va_list of insertion strings.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
void
|
|
__cdecl
|
|
DebugPrintfEx(
|
|
IN DEBUGLEVEL dwDetail,
|
|
IN LPSTR pszFmt,
|
|
...
|
|
)
|
|
{
|
|
char szT[1024];
|
|
va_list arglist;
|
|
int len;
|
|
|
|
va_start(arglist, pszFmt);
|
|
|
|
//
|
|
// Reserve one character for the potential '\n' that we may be adding.
|
|
//
|
|
StringCchVPrintfA(szT, sizeof(szT) - 1, pszFmt, arglist);
|
|
|
|
va_end(arglist);
|
|
|
|
//
|
|
// Make sure we have a '\n' at the end of the string
|
|
//
|
|
len = strlen(szT);
|
|
|
|
if (len > 0 && szT[len - 1] != '\n') {
|
|
szT[len] = '\n';
|
|
szT[len + 1] = 0;
|
|
}
|
|
|
|
switch (dwDetail) {
|
|
case dlPrint:
|
|
DbgPrint("[MSG ] ");
|
|
break;
|
|
|
|
case dlError:
|
|
DbgPrint("[FAIL] ");
|
|
break;
|
|
|
|
case dlWarning:
|
|
DbgPrint("[WARN] ");
|
|
break;
|
|
|
|
case dlInfo:
|
|
DbgPrint("[INFO] ");
|
|
break;
|
|
|
|
default:
|
|
DbgPrint("[XXXX] ");
|
|
break;
|
|
}
|
|
|
|
DbgPrint("%s", szT);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the installer. Sets up paths, version
|
|
information, etc.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success.
|
|
FALSE on failure.
|
|
-1 if the operating system is not supported.
|
|
|
|
--*/
|
|
int
|
|
InitializeInstaller(
|
|
void
|
|
)
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
WCHAR* pTemp = NULL;
|
|
UINT cchSize;
|
|
DWORD cchReturned;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Find out what operating system we're running on.
|
|
//
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx(&osvi)) {
|
|
DPF(dlError,
|
|
"[InitializeInstaller] 0x%08X Failed to get OS version info",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// No support for Win9x or NT4.
|
|
//
|
|
if (osvi.dwMajorVersion == 4) {
|
|
DPF(dlInfo, "[InitializeInstaller] OS not supported");
|
|
return -1;
|
|
}
|
|
|
|
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
|
|
g_ai.ePlatform = osWindows2000;
|
|
} else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
|
|
g_ai.ePlatform = osWindowsXP;
|
|
} else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 2) {
|
|
g_ai.ePlatform = osWindowsDotNet;
|
|
}
|
|
|
|
//
|
|
// Find out where we're running from.
|
|
//
|
|
g_ai.wszModuleName[ARRAYSIZE(g_ai.wszModuleName) - 1] = 0;
|
|
cchReturned = GetModuleFileName(NULL,
|
|
g_ai.wszModuleName,
|
|
ARRAYSIZE(g_ai.wszModuleName));
|
|
|
|
if (g_ai.wszModuleName[ARRAYSIZE(g_ai.wszModuleName) - 1] != 0 ||
|
|
cchReturned == 0) {
|
|
DPF(dlError,
|
|
"[InitializeInstaller] 0x%08X Failed to get module file name",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Save away our current directory for later use.
|
|
//
|
|
hr = StringCchCopy(g_ai.wszCurrentDir,
|
|
ARRAYSIZE(g_ai.wszCurrentDir),
|
|
g_ai.wszModuleName);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InitializeInstaller] 0x%08X String copy failed", hr);
|
|
return FALSE;
|
|
}
|
|
|
|
pTemp = wcsrchr(g_ai.wszCurrentDir, '\\');
|
|
|
|
if (pTemp) {
|
|
*pTemp = 0;
|
|
}
|
|
|
|
//
|
|
// Save away paths to the Windows & System32 directories for later use.
|
|
//
|
|
cchSize = GetSystemWindowsDirectory(g_ai.wszWinDir,
|
|
ARRAYSIZE(g_ai.wszWinDir));
|
|
|
|
if (cchSize > ARRAYSIZE(g_ai.wszWinDir) || cchSize == 0) {
|
|
DPF(dlError,
|
|
"[InitializeInstaller] 0x%08X Failed to get Windows directory",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
cchSize = GetSystemDirectory(g_ai.wszSysDir, ARRAYSIZE(g_ai.wszSysDir));
|
|
|
|
if (cchSize > ARRAYSIZE(g_ai.wszSysDir) || cchSize == 0) {
|
|
DPF(dlError,
|
|
"[InitializeInstaller] 0x%08X Failed to get system directory",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Launches the Application Verifier.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
void
|
|
InstallLaunchExe(
|
|
void
|
|
)
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
WCHAR wszAppVerifExe[MAX_PATH];
|
|
HRESULT hr;
|
|
|
|
hr = StringCchPrintf(wszAppVerifExe,
|
|
ARRAYSIZE(wszAppVerifExe),
|
|
L"%ls\\"FILENAME_APPVERIF_EXE,
|
|
g_ai.wszSysDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InstallLaunchExe] Buffer too small");
|
|
return;
|
|
}
|
|
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
if (!CreateProcess(wszAppVerifExe,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi)) {
|
|
DPF(dlError,
|
|
"[InstallLaunchExe] 0x%08X Failed to launch %ls",
|
|
GetLastError(),
|
|
wszAppVerifExe);
|
|
return;
|
|
}
|
|
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Installs the catalog file.
|
|
|
|
Arguments:
|
|
|
|
pwszCatFileName - Name of the catalog file to install.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
InstallCatalogFile(
|
|
IN LPWSTR pwszCatFileName
|
|
)
|
|
{
|
|
HCATADMIN hCatAdmin;
|
|
HCATINFO hCatInfo;
|
|
GUID guidCatRoot;
|
|
|
|
if (!pwszCatFileName) {
|
|
DPF(dlError, "[InstallCatalogFile] Invalid parameter");
|
|
return FALSE;
|
|
}
|
|
|
|
StringToGuid(L"{F750E6C3-38EE-11D1-85E5-00C04FC295EE}", &guidCatRoot);
|
|
|
|
if (!CryptCATAdminAcquireContext(&hCatAdmin, &guidCatRoot, 0)) {
|
|
DPF(dlError,
|
|
"[InstallCatalogFile] 0x%08X Failed to acquire context",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
hCatInfo = CryptCATAdminAddCatalog(hCatAdmin,
|
|
pwszCatFileName,
|
|
NULL,
|
|
0);
|
|
|
|
if (hCatInfo) {
|
|
CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0);
|
|
CryptCATAdminReleaseContext(hCatAdmin, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
CryptCATAdminReleaseContext(hCatAdmin, 0);
|
|
|
|
DPF(dlError,
|
|
"[InstallCatalogFile] 0x%08X Failed to add catalog %ls",
|
|
GetLastError(),
|
|
pwszCatFileName);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Installs a certificate into the certificate store.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
InstallCertificateFile(
|
|
void
|
|
)
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
WCHAR wszCertMgrName[MAX_PATH];
|
|
WCHAR wszCertMgrCmdLine[MAX_PATH];
|
|
HRESULT hr;
|
|
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
//
|
|
// Set up the path to certmgr.exe.
|
|
//
|
|
hr = StringCchPrintf(wszCertMgrName,
|
|
ARRAYSIZE(wszCertMgrName),
|
|
L"%ls\\"CERTMGR_EXE,
|
|
g_ai.wszCurrentDir);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InstallCertificateFile] Buffer too small (1)");
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Set up the command-line for certmgr.exe.
|
|
//
|
|
hr = StringCchPrintf(wszCertMgrCmdLine,
|
|
ARRAYSIZE(wszCertMgrCmdLine),
|
|
L"%ls\\%ls %ls",
|
|
g_ai.wszCurrentDir,
|
|
CERTMGR_EXE,
|
|
CERTMGR_CMD);
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[InstallCertificateFile] Buffer too small (2)");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!CreateProcess(wszCertMgrName,
|
|
wszCertMgrCmdLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi)) {
|
|
|
|
DPF(dlError,
|
|
"[InstallCertificateFile] 0x%08X Failed to launch '%ls %ls'",
|
|
GetLastError(),
|
|
wszCertMgrName,
|
|
wszCertMgrCmdLine);
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs the installation of the catalog file
|
|
on Windows XP or Windows Server 2003.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
PerformCatalogInstall(
|
|
void
|
|
)
|
|
{
|
|
WCHAR wszCatalog[MAX_PATH];
|
|
HRESULT hr;
|
|
|
|
if (g_ai.ePlatform == osWindowsXP) {
|
|
hr = StringCchPrintf(wszCatalog,
|
|
ARRAYSIZE(wszCatalog),
|
|
L"%ls\\"FILENAME_DELTA_CAT_XP,
|
|
g_ai.wszCurrentDir);
|
|
|
|
} else if (g_ai.ePlatform == osWindowsDotNet) {
|
|
hr = StringCchPrintf(wszCatalog,
|
|
ARRAYSIZE(wszCatalog),
|
|
L"%ls\\"FILENAME_DELTA_CAT_DOTNET,
|
|
g_ai.wszCurrentDir);
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
DPF(dlError, "[PerformCatalogInstall] Buffer too small");
|
|
return FALSE;
|
|
}
|
|
|
|
return (InstallCatalogFile(wszCatalog));
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies the files that we've determined are
|
|
newer to their specified destination.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE otherwise.
|
|
|
|
--*/
|
|
BOOL
|
|
InstallCopyFiles(
|
|
void
|
|
)
|
|
{
|
|
UINT uCount;
|
|
|
|
while (TRUE) {
|
|
for (uCount = 0; uCount < NUM_FILES; uCount++) {
|
|
if (g_ai.rgFileInfo[uCount].bInstall) {
|
|
//
|
|
// If we're on XP and the file is not specifically for
|
|
// Windows 2000, copy it over.
|
|
//
|
|
if (g_ai.ePlatform != osWindows2000 &&
|
|
g_ai.rgFileInfo[uCount].bWin2KOnly) {
|
|
break;
|
|
}
|
|
|
|
if (!ForceCopy(g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
g_ai.rgFileInfo[uCount].wszDestFileName)) {
|
|
DPF(dlError,
|
|
"[InstallCopyFiles] Failed to copy %ls to %ls",
|
|
g_ai.rgFileInfo[uCount].wszSrcFileName,
|
|
g_ai.rgFileInfo[uCount].wszDestFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs the installation. This is the main routine
|
|
for the install.
|
|
|
|
Arguments:
|
|
|
|
hWndParent - Parent window handle for message boxes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
void
|
|
PerformInstallation(
|
|
IN HWND hWndParent
|
|
)
|
|
{
|
|
WCHAR wszError[MAX_PATH];
|
|
|
|
SendMessage(g_ai.hWndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, NUM_PB_STEPS));
|
|
SendMessage(g_ai.hWndProgress, PBM_SETSTEP, 1, 0);
|
|
|
|
//
|
|
// Initialize our structure with new files that need to be installed.
|
|
// This should not fail because we've already performed a check and
|
|
// it told us that we had new files to install.
|
|
//
|
|
if (!InstallCheckFileVersions()) {
|
|
DPF(dlError, "[PerformInstallation] Failed to check file versions");
|
|
goto InstallError;
|
|
}
|
|
|
|
//
|
|
// If we're running on Windows XP or Server 2003, install a catalog file
|
|
// and our certificate. We have different catalogs for XP versus Server 2003.
|
|
//
|
|
if (g_ai.ePlatform == osWindowsXP || g_ai.ePlatform == osWindowsDotNet) {
|
|
if (!PerformCatalogInstall()) {
|
|
DPF(dlError, "[PerformInstallation] Failed to install catalog");
|
|
goto InstallError;
|
|
}
|
|
|
|
SendMessage(g_ai.hWndProgress, PBM_STEPIT, 0, 0);
|
|
|
|
if (!InstallCertificateFile()) {
|
|
DPF(dlError, "[PerformInstallation] Failed to install certificate");
|
|
goto InstallError;
|
|
}
|
|
}
|
|
|
|
SendMessage(g_ai.hWndProgress, PBM_STEPIT, 0, 0);
|
|
|
|
if (!InstallCopyFiles()) {
|
|
DPF(dlError, "[PerformInstallation] Failed to copy files");
|
|
goto InstallError;
|
|
}
|
|
|
|
SendMessage(g_ai.hWndProgress, PBM_STEPIT, 0, 0);
|
|
|
|
DPF(dlInfo, "[PerformInstallation] Installation completed successfully");
|
|
|
|
g_ai.bInstallSuccess = TRUE;
|
|
|
|
//
|
|
// Install successful.
|
|
//
|
|
SendMessage(g_ai.hWndProgress, PBM_SETPOS, NUM_PB_STEPS, 0);
|
|
LoadString(g_ai.hInstance, IDS_INSTALL_COMPLETE, wszError, ARRAYSIZE(wszError));
|
|
SetDlgItemText(hWndParent, IDC_STATUS, wszError);
|
|
EnableWindow(GetDlgItem(hWndParent, IDOK), TRUE);
|
|
ShowWindow(GetDlgItem(hWndParent, IDC_LAUNCH), SW_SHOW);
|
|
|
|
return;
|
|
|
|
InstallError:
|
|
SendMessage(g_ai.hWndProgress, PBM_SETPOS, NUM_PB_STEPS, 0);
|
|
LoadString(g_ai.hInstance, IDS_INSTALL_FAILED, wszError, ARRAYSIZE(wszError));
|
|
SetDlgItemText(hWndParent, IDC_STATUS, wszError);
|
|
EnableWindow(GetDlgItem(hWndParent, IDCANCEL), TRUE);
|
|
}
|
|
|
|
|