3515 lines
104 KiB
C
3515 lines
104 KiB
C
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define ARRAYSIZE(x) (sizeof((x))/sizeof((x)[0]))
|
|
|
|
#include <oleauto.h>
|
|
#include <stdio.h>
|
|
|
|
//
|
|
// use the same name as the Win9x upgrade report
|
|
//
|
|
#define S_APPCOMPAT_DATABASE_FILE TEXT("compdata\\drvmain.chm")
|
|
#define S_APPCOMPAT_TEXT_FILE TEXT("compdata\\drvmain.inf")
|
|
#define DRVCOMPAT_FIELD_IDENTIFIER TEXT('*')
|
|
|
|
|
|
|
|
typedef struct {
|
|
PVOID Text;
|
|
BOOL Unicode;
|
|
} COMPAT_TEXT_PARAMS, *PCOMPAT_TEXT_PARAMS;
|
|
|
|
|
|
LIST_ENTRY CompatibilityData;
|
|
DWORD CompatibilityCount;
|
|
DWORD IncompatibilityStopsInstallation = FALSE;
|
|
DWORD GlobalCompFlags;
|
|
BOOL g_DeleteRunOnceFlag;
|
|
|
|
//
|
|
// we use poor global variable instead of changing the COMPATIBILITY_CONTEXT
|
|
// structure, which would require a recompile of all the compatibility dlls.
|
|
// eventually this should move into that structure (and the structure should also have
|
|
// a Size member so we can version it in the future.)
|
|
//
|
|
//
|
|
DWORD PerCompatDllFlags;
|
|
|
|
BOOL AnyNt5CompatDlls = FALSE;
|
|
|
|
BOOL
|
|
SaveCompatibilityData(
|
|
IN LPCTSTR FileName,
|
|
IN BOOL IncludeHiddenItems
|
|
);
|
|
|
|
BOOL
|
|
ProcessLine (
|
|
IN DWORD CompatFlags
|
|
);
|
|
|
|
WNDPROC OldEditProc;
|
|
|
|
LRESULT
|
|
CALLBACK
|
|
TextEditSubProc(
|
|
IN HWND hwnd,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
//
|
|
// For setsel messages, make start and end the same.
|
|
//
|
|
if ((msg == EM_SETSEL) && ((LPARAM)wParam != lParam)) {
|
|
lParam = wParam;
|
|
}
|
|
|
|
return CallWindowProc( OldEditProc, hwnd, msg, wParam, lParam );
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetTextInDialog(
|
|
HWND hwnd,
|
|
PCOMPAT_TEXT_PARAMS Params
|
|
)
|
|
{
|
|
OldEditProc = (WNDPROC) GetWindowLongPtr( hwnd, GWLP_WNDPROC );
|
|
SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)TextEditSubProc );
|
|
|
|
#ifdef UNICODE
|
|
|
|
if (Params->Unicode) {
|
|
SendMessageW (hwnd, WM_SETTEXT, 0, (LPARAM)Params->Text);
|
|
} else {
|
|
SendMessageA (hwnd, WM_SETTEXT, 0, (LPARAM)Params->Text);
|
|
}
|
|
|
|
#else
|
|
|
|
MYASSERT (!Params->Unicode);
|
|
if (Params->Unicode) {
|
|
return FALSE;
|
|
}
|
|
SendMessageA (hwnd, WM_SETTEXT, 0, (LPARAM)Params->Text);
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
CompatibilityTextDlgProc(
|
|
HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
switch(uMsg) {
|
|
case WM_INITDIALOG:
|
|
SetTextInDialog( GetDlgItem( hwndDlg, IDC_TEXT ), (PCOMPAT_TEXT_PARAMS) lParam );
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if (wParam == IDOK) {
|
|
EndDialog( hwndDlg, IDOK );
|
|
}
|
|
break;
|
|
|
|
case WM_CTLCOLOREDIT:
|
|
SetBkColor( (HDC)wParam, GetSysColor(COLOR_BTNFACE));
|
|
return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
EndDialog (hwndDlg, IDOK);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
LaunchIE4Instance(
|
|
LPWSTR szResourceURL
|
|
);
|
|
|
|
BOOL
|
|
LaunchIE3Instance(
|
|
LPWSTR szResourceURL
|
|
);
|
|
|
|
BOOL
|
|
pGetDisplayInfo (
|
|
IN PCTSTR Source,
|
|
OUT PTSTR UrlName,
|
|
IN DWORD UrlChars
|
|
)
|
|
{
|
|
TCHAR filePath[MAX_PATH];
|
|
BOOL b = TRUE;
|
|
|
|
if (!Source || !*Source) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (*Source == DRVCOMPAT_FIELD_IDENTIFIER) {
|
|
if (FindPathToWinnt32File (S_APPCOMPAT_DATABASE_FILE, filePath, MAX_PATH)) {
|
|
_sntprintf (UrlName, UrlChars, TEXT("mk:@msitstore:%s::/%s"), filePath, Source + 1);
|
|
} else {
|
|
DebugLog (Winnt32LogError,
|
|
TEXT("Compatibility data file \"%1\" not found"),
|
|
0,
|
|
S_APPCOMPAT_DATABASE_FILE
|
|
);
|
|
b = FALSE;
|
|
}
|
|
} else {
|
|
if (FindPathToWinnt32File (Source, filePath, MAX_PATH)) {
|
|
_sntprintf (UrlName, UrlChars, TEXT("file://%s"), filePath);
|
|
} else {
|
|
DebugLog (Winnt32LogError,
|
|
TEXT("Compatibility data file \"%1\" not found"),
|
|
0,
|
|
Source
|
|
);
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pGetText (
|
|
IN PCTSTR TextSource,
|
|
OUT PVOID* Text,
|
|
OUT PBOOL Unicode
|
|
)
|
|
{
|
|
TCHAR filePath[MAX_PATH];
|
|
DWORD FileSize;
|
|
HANDLE FileHandle;
|
|
HANDLE MappingHandle;
|
|
PVOID BaseAddress;
|
|
HINF infAppCompat;
|
|
INFCONTEXT ic;
|
|
BOOL bValid;
|
|
DWORD totalSize, size;
|
|
PTSTR data, current;
|
|
PSTR text;
|
|
BOOL b = FALSE;
|
|
|
|
if (!TextSource || !*TextSource) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (*TextSource == DRVCOMPAT_FIELD_IDENTIFIER) {
|
|
if (FindPathToWinnt32File (S_APPCOMPAT_TEXT_FILE, filePath, MAX_PATH)) {
|
|
infAppCompat = SetupapiOpenInfFile (filePath, NULL, INF_STYLE_WIN4, NULL);
|
|
if (infAppCompat != INVALID_HANDLE_VALUE) {
|
|
bValid = TRUE;
|
|
totalSize = 0;
|
|
data = NULL;
|
|
if (SetupapiFindFirstLine (infAppCompat, TextSource + 1, NULL, &ic)) {
|
|
do {
|
|
if (!SetupapiGetStringField (&ic, 1, NULL, 0, &FileSize)) {
|
|
bValid = FALSE;
|
|
break;
|
|
}
|
|
totalSize += FileSize + 2 - 1;
|
|
} while (SetupapiFindNextLine (&ic, &ic));
|
|
}
|
|
if (bValid && totalSize > 0) {
|
|
totalSize++;
|
|
data = (PTSTR) MALLOC (totalSize * sizeof (TCHAR));
|
|
if (data) {
|
|
current = data;
|
|
size = totalSize;
|
|
if (SetupapiFindFirstLine (infAppCompat, TextSource + 1, NULL, &ic)) {
|
|
do {
|
|
if (!SetupapiGetStringField (&ic, 1, current, size, NULL)) {
|
|
bValid = FALSE;
|
|
break;
|
|
}
|
|
lstrcat (current, TEXT("\r\n"));
|
|
size -= lstrlen (current);
|
|
current = _tcschr (current, 0);
|
|
} while (SetupapiFindNextLine (&ic, &ic));
|
|
}
|
|
}
|
|
}
|
|
|
|
SetupapiCloseInfFile (infAppCompat);
|
|
|
|
if (bValid) {
|
|
if (data) {
|
|
*Text = data;
|
|
#ifdef UNICODE
|
|
*Unicode = TRUE;
|
|
#else
|
|
*Unicode = FALSE;
|
|
#endif
|
|
b = TRUE;
|
|
}
|
|
} else {
|
|
FREE (data);
|
|
}
|
|
}
|
|
if (!b) {
|
|
DebugLog (
|
|
Winnt32LogError,
|
|
TEXT("Unable to read section [%1] from \"%2\""),
|
|
0,
|
|
TextSource + 1,
|
|
filePath
|
|
);
|
|
}
|
|
} else {
|
|
DebugLog (Winnt32LogError,
|
|
TEXT("Compatibility data file \"%1\" not found"),
|
|
0,
|
|
S_APPCOMPAT_DATABASE_FILE
|
|
);
|
|
}
|
|
} else {
|
|
if (FindPathToWinnt32File (TextSource, filePath, MAX_PATH)) {
|
|
if (MapFileForRead (filePath, &FileSize, &FileHandle, &MappingHandle, &BaseAddress) == ERROR_SUCCESS) {
|
|
text = (PSTR) MALLOC (FileSize + 1);
|
|
if (text) {
|
|
CopyMemory (text, BaseAddress, FileSize);
|
|
text[FileSize] = '\0';
|
|
*Text = text;
|
|
*Unicode = FALSE;
|
|
b = TRUE;
|
|
}
|
|
UnmapFile (MappingHandle, BaseAddress);
|
|
CloseHandle (FileHandle);
|
|
}
|
|
} else {
|
|
DebugLog (Winnt32LogError,
|
|
TEXT("Compatibility data file \"%1\" not found"),
|
|
0,
|
|
TextSource
|
|
);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
pShowDetails (
|
|
IN HWND Hdlg,
|
|
IN PCOMPATIBILITY_DATA CompData
|
|
)
|
|
{
|
|
TCHAR urlName[2 * MAX_PATH];
|
|
PWSTR Url;
|
|
INT i;
|
|
PVOID textDescription;
|
|
BOOL bUnicode;
|
|
BOOL UseText = FALSE;
|
|
|
|
//
|
|
// We check to see if the pointer as well as its contents are valid. If the contents are Null then we try
|
|
// the txt file before we decide to not do anything.
|
|
//
|
|
|
|
if (pGetDisplayInfo (CompData->HtmlName, urlName, 2 * MAX_PATH)) {
|
|
|
|
i = _tcslen( urlName );
|
|
Url = (LPWSTR)SysAllocStringLen( NULL, i );
|
|
|
|
if( Url ) {
|
|
#ifdef UNICODE
|
|
wcscpy( Url, urlName );
|
|
#else
|
|
MultiByteToWideChar( CP_ACP, 0, urlName, -1, Url, i);
|
|
#endif
|
|
|
|
if (!LaunchIE4Instance(Url)) {
|
|
// If we don't have IE4 or better, display text
|
|
UseText = TRUE;
|
|
}
|
|
|
|
SysFreeString( Url );
|
|
}
|
|
} else if( CheckUpgradeOnly ) {
|
|
|
|
TCHAR Caption[512];
|
|
|
|
//
|
|
// If we don't have a URL, and we're only checking
|
|
// the ability to upgrade, then this is probably
|
|
// an item from a message box that's been redirected
|
|
// to the compability list. Just display a message
|
|
// box with the full text.
|
|
//
|
|
if(!LoadString(hInst,AppTitleStringId,Caption,sizeof(Caption)/sizeof(TCHAR))) {
|
|
Caption[0] = 0;
|
|
}
|
|
|
|
|
|
MessageBox( Hdlg,
|
|
CompData->Description,
|
|
Caption,
|
|
MB_OK | MB_ICONWARNING );
|
|
|
|
} else {
|
|
UseText = TRUE;
|
|
}
|
|
|
|
if (UseText) {
|
|
if (pGetText (CompData->TextName, &textDescription, &bUnicode)) {
|
|
|
|
COMPAT_TEXT_PARAMS params;
|
|
|
|
params.Text = textDescription;
|
|
params.Unicode = bUnicode;
|
|
|
|
DialogBoxParam(
|
|
hInst,
|
|
MAKEINTRESOURCE(IDD_COMPATIBILITY_TEXT),
|
|
NULL,
|
|
CompatibilityTextDlgProc,
|
|
(LPARAM)¶ms
|
|
);
|
|
|
|
FREE (textDescription);
|
|
|
|
} else {
|
|
|
|
TCHAR Heading[512];
|
|
PTSTR Message;
|
|
|
|
//
|
|
// When there is no txt name present, as last resort we put up this message
|
|
//
|
|
if(!LoadString(hInst,AppTitleStringId,Heading,sizeof(Heading)/sizeof(TCHAR))) {
|
|
Heading[0] = 0;
|
|
}
|
|
|
|
if (FormatMessage (
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
|
|
hInst,
|
|
MSG_NO_DETAILS,
|
|
0,
|
|
(LPTSTR)&Message,
|
|
0,
|
|
NULL
|
|
)) {
|
|
MessageBox (Hdlg, Message, Heading, MB_OK | MB_ICONWARNING);
|
|
LocalFree ((HLOCAL)Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
CompatibilityWizPage(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
TCHAR FullPath[MAX_PATH+8], *t;
|
|
LPWSTR Url;
|
|
BOOL b = FALSE;
|
|
DWORD i;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
DWORD Index;
|
|
static int CurrentSelectionIndex=0;
|
|
static DWORD Count = 0;
|
|
LV_ITEM lvi = {0};
|
|
HWND TmpHwnd;
|
|
static BOOL WarningsPresent = FALSE;
|
|
static BOOL ErrorsPresent = FALSE;
|
|
static BOOL CheckUpgradeNoItems = TRUE;
|
|
PPAGE_RUNTIME_DATA WizPage = (PPAGE_RUNTIME_DATA)GetWindowLongPtr(hdlg,DWLP_USER);
|
|
TCHAR Buffer1[MAX_PATH] = {0};
|
|
|
|
switch(msg) {
|
|
|
|
case WM_INITDIALOG:
|
|
if( ISNT() && CheckUpgradeOnly ) {
|
|
|
|
TCHAR Desc_String[512];
|
|
PLIST_ENTRY Next;
|
|
PPAGE_RUNTIME_DATA WizPage = (PPAGE_RUNTIME_DATA)GetWindowLongPtr(hdlg,DWLP_USER);
|
|
|
|
//
|
|
// Fix up the subtitle and buttons for Checkupgradeonly.
|
|
//
|
|
SetDlgItemText(hdlg,IDT_SUBTITLE,(PTSTR)TEXT("") );
|
|
|
|
|
|
//
|
|
// If we're doing a CheckUpgradeOnly, then
|
|
// we've been sending error popups to the compatibility
|
|
// list. It doesn't look like there were any problems or
|
|
// incompatibilities. We'll put in an "everything's okay"
|
|
// message.
|
|
//
|
|
|
|
Next = CompatibilityData.Flink;
|
|
if (Next) {
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
|
|
CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
|
|
Next = CompData->ListEntry.Flink;
|
|
if( (!(CompData->Flags & COMPFLAG_HIDE)) && ProcessLine( CompData->Flags)) {
|
|
CheckUpgradeNoItems = FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
if( CheckUpgradeNoItems ){
|
|
|
|
if (!CompatibilityData.Flink) {
|
|
InitializeListHead (&CompatibilityData);
|
|
}
|
|
|
|
CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
|
|
if (CompData == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
|
|
|
|
if(!LoadString(hInst,IDS_COMPAT_NOPROBLEMS,Desc_String,(sizeof(Desc_String)/sizeof(TCHAR))))
|
|
CompData->Description = 0;
|
|
else
|
|
CompData->Description = DupString(Desc_String);
|
|
|
|
CompData->Flags = 0;
|
|
InsertTailList( &CompatibilityData, &CompData->ListEntry );
|
|
CompatibilityCount++;
|
|
}
|
|
}
|
|
|
|
if (CompatibilityCount) {
|
|
|
|
HWND hList = GetDlgItem( hdlg, IDC_ROOT_LIST );
|
|
PLIST_ENTRY Next;
|
|
HIMAGELIST himl;
|
|
HICON hIcon;
|
|
LV_COLUMN lvc = {0};
|
|
RECT rc;
|
|
|
|
GetClientRect( hList, &rc );
|
|
lvc.mask = LVCF_WIDTH;
|
|
lvc.cx = rc.right - rc.left - 16;
|
|
ListView_InsertColumn( hList, 0, &lvc );
|
|
|
|
Next = CompatibilityData.Flink;
|
|
if (Next) {
|
|
himl = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
|
|
GetSystemMetrics(SM_CXSMICON),
|
|
ILC_COLOR,
|
|
2,
|
|
0 );
|
|
ListView_SetImageList( hList, himl, LVSIL_SMALL );
|
|
hIcon = LoadIcon( NULL, IDI_HAND );
|
|
ImageList_AddIcon( himl, hIcon );
|
|
hIcon = LoadIcon( NULL, IDI_EXCLAMATION );
|
|
ImageList_AddIcon( himl, hIcon );
|
|
|
|
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
|
|
lvi.state = 0;
|
|
lvi.stateMask = 0;
|
|
lvi.iItem = 0;
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
|
|
CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
|
|
|
|
Next = CompData->ListEntry.Flink;
|
|
|
|
if (ProcessLine( CompData->Flags)) {
|
|
AnyNt5CompatDlls = TRUE;
|
|
} else {
|
|
goto NextIteration;
|
|
}
|
|
|
|
if ((CompData->Flags & COMPFLAG_HIDE) == 0) {
|
|
|
|
//
|
|
// Add the icon.
|
|
//
|
|
if( himl ) {
|
|
if (ISNT() && CheckUpgradeOnly && CheckUpgradeNoItems) {
|
|
lvi.iImage = -1;
|
|
WarningsPresent = TRUE;
|
|
} else {
|
|
if( CompData->Flags & COMPFLAG_STOPINSTALL ) {
|
|
lvi.iImage = 0;
|
|
ErrorsPresent = TRUE;
|
|
} else {
|
|
lvi.iImage = 1;
|
|
WarningsPresent = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// And the text...
|
|
//
|
|
lvi.pszText = (LPTSTR)CompData->Description;
|
|
lvi.lParam = (LPARAM)CompData;
|
|
if (ListView_InsertItem( hList, &lvi ) != -1) {
|
|
lvi.iItem++;
|
|
}
|
|
|
|
Count += 1;
|
|
}
|
|
|
|
//
|
|
// Log the items...
|
|
//
|
|
DebugLog( Winnt32LogInformation,
|
|
CompData->Description,
|
|
0 );
|
|
DebugLog( Winnt32LogInformation,
|
|
TEXT("\r\n"),
|
|
0 );
|
|
NextIteration:
|
|
NOTHING;
|
|
}
|
|
|
|
}
|
|
|
|
// If we have an item then make it the default selection
|
|
|
|
if( ErrorsPresent || WarningsPresent ){
|
|
|
|
|
|
|
|
SetFocus( hList );
|
|
ListView_SetItemState( hList,
|
|
0,
|
|
LVIS_SELECTED | LVIS_FOCUSED,
|
|
LVIS_SELECTED | LVIS_FOCUSED);
|
|
CurrentSelectionIndex = 0;
|
|
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = 0;
|
|
lvi.iSubItem = 0;
|
|
ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
|
|
CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
|
|
|
|
TmpHwnd = GetDlgItem( hdlg, IDC_HAVE_DISK );
|
|
if (CompData->Flags & COMPFLAG_USE_HAVEDISK)
|
|
UnHideWindow( TmpHwnd );
|
|
else
|
|
HideWindow( TmpHwnd );
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
|
|
{
|
|
LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
|
|
|
|
|
|
if( (pnmv->hdr.code == LVN_ITEMCHANGED) ) {
|
|
|
|
|
|
Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
|
|
(int)-1,
|
|
(UINT) (LVNI_ALL | LVNI_SELECTED | LVNI_FOCUSED) );
|
|
|
|
|
|
|
|
if( (Index != LB_ERR) && (pnmv->iItem != CurrentSelectionIndex)) {
|
|
|
|
CurrentSelectionIndex = Index;
|
|
|
|
//
|
|
// Select the item, and see if we need
|
|
// to display the "have disk" button.
|
|
//
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = Index;
|
|
lvi.iSubItem = 0;
|
|
ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
|
|
CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
|
|
|
|
TmpHwnd = GetDlgItem( hdlg, IDC_HAVE_DISK );
|
|
HideWindow( TmpHwnd );
|
|
|
|
// Always set the Details button
|
|
TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
|
|
EnableWindow( TmpHwnd, TRUE );
|
|
|
|
if (CompData->Flags & COMPFLAG_USE_HAVEDISK) {
|
|
TmpHwnd = GetDlgItem( hdlg, IDC_HAVE_DISK );
|
|
UnHideWindow( TmpHwnd );
|
|
}
|
|
InvalidateRect( GetParent(hdlg), NULL, FALSE );
|
|
|
|
}else if((Index != LB_ERR) && (pnmv->uNewState == (LVIS_SELECTED|LVIS_FOCUSED))){
|
|
|
|
//Transition from nothing selected to previous selection
|
|
|
|
TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
|
|
EnableWindow( TmpHwnd, TRUE );
|
|
|
|
}else if( Index == LB_ERR){
|
|
|
|
// Disable the "Details" button as nothing is selected
|
|
|
|
TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
|
|
EnableWindow( TmpHwnd, FALSE );
|
|
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
|
|
if ((LOWORD(wParam) == IDC_HAVE_DISK) && (HIWORD(wParam) == BN_CLICKED)) {
|
|
Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
|
|
(int)-1,
|
|
(UINT) (LVNI_ALL | LVNI_SELECTED) );
|
|
if( Index != LB_ERR ) {
|
|
//
|
|
// Select the item, and see if we need
|
|
// to display the "have disk" button.
|
|
//
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = Index;
|
|
lvi.iSubItem = 0;
|
|
ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
|
|
CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
|
|
|
|
__try {
|
|
i = CompData->CompHaveDisk(hdlg,CompData->SaveValue);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
i = GetExceptionCode();
|
|
}
|
|
if (i == 0) {
|
|
ListView_DeleteItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), Index );
|
|
RemoveEntryList( &CompData->ListEntry );
|
|
CompatibilityCount -= 1;
|
|
|
|
} else {
|
|
MessageBoxFromMessageWithSystem(
|
|
hdlg,
|
|
i,
|
|
AppTitleStringId,
|
|
MB_OK | MB_ICONERROR | MB_TASKMODAL,
|
|
CompData->hModDll
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((LOWORD(wParam) == IDC_DETAILS) && (HIWORD(wParam) == BN_CLICKED)) {
|
|
|
|
TCHAR filePath[MAX_PATH];
|
|
|
|
Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
|
|
(int)-1,
|
|
(UINT) (LVNI_ALL | LVNI_SELECTED) );
|
|
if (Index == LB_ERR) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Select the item, and see if we need
|
|
// to display the "have disk" button.
|
|
//
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = Index;
|
|
lvi.iSubItem = 0;
|
|
if (!ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi )) {
|
|
break;
|
|
}
|
|
CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
|
|
pShowDetails (hdlg, CompData);
|
|
SetFocus( GetDlgItem( hdlg, IDC_ROOT_LIST ) );
|
|
ListView_SetItemState( GetDlgItem( hdlg, IDC_ROOT_LIST ),Index, LVIS_SELECTED, LVIS_SELECTED);
|
|
break;
|
|
}
|
|
|
|
if ((LOWORD(wParam) == IDC_SAVE_AS) && (HIWORD(wParam) == BN_CLICKED)) {
|
|
OPENFILENAME ofn;
|
|
TCHAR Buffer[MAX_PATH] = {0};
|
|
TCHAR File_Type[MAX_PATH];
|
|
BOOL SaveFlag;
|
|
|
|
//
|
|
// Initialize OPENFILENAME
|
|
//
|
|
ZeroMemory( &ofn, sizeof(OPENFILENAME));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hdlg;
|
|
ofn.lpstrFile = Buffer;
|
|
ofn.nMaxFile = MAX_PATH;
|
|
|
|
LoadString(hInst,IDS_DEFAULT_COMPATIBILITY_REPORT_NAME,ofn.lpstrFile,(sizeof(Buffer)/sizeof(TCHAR)));
|
|
|
|
|
|
if( LoadString(hInst, IDS_FILE_MASK_TYPES, File_Type, (sizeof(File_Type)/sizeof(TCHAR))) ){
|
|
lstrcpy((File_Type+lstrlen(File_Type)+1), TEXT("*.txt\0"));
|
|
File_Type[lstrlen(File_Type)+7]='\0'; //We need to terminate the pair of strings with double null termination
|
|
ofn.lpstrFilter = File_Type;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Force to begin in %windir%
|
|
MyGetWindowsDirectory( Buffer1, MAX_PATH );
|
|
ofn.lpstrInitialDir = Buffer1;
|
|
ofn.Flags = OFN_NOCHANGEDIR | // leave the CWD unchanged
|
|
OFN_EXPLORER |
|
|
OFN_OVERWRITEPROMPT |
|
|
OFN_HIDEREADONLY;
|
|
|
|
// Let user select disk or directory
|
|
SaveFlag = GetSaveFileName( &ofn );
|
|
if( SaveFlag ) {
|
|
//
|
|
// Save it...
|
|
//
|
|
PTSTR p;
|
|
|
|
p=_tcsrchr(ofn.lpstrFile,'.');
|
|
if( !p || (p && lstrcmpi(p, TEXT(".txt"))))
|
|
lstrcat(ofn.lpstrFile,TEXT(".txt"));
|
|
|
|
SaveCompatibilityData( ofn.lpstrFile, FALSE);
|
|
} else {
|
|
i = CommDlgExtendedError();
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WMX_ACTIVATEPAGE:
|
|
|
|
if (wParam) {
|
|
if (ISNT ()) {
|
|
MyGetWindowsDirectory (Buffer1, MAX_PATH);
|
|
wsprintf (FullPath, TEXT("%s\\%s"), Buffer1, S_DEFAULT_NT_COMPAT_FILENAME);
|
|
SaveCompatibilityData (FullPath, TRUE);
|
|
}
|
|
|
|
CHECKUPGRADEONLY_Q();
|
|
|
|
if( CheckUpgradeOnly ) {
|
|
//
|
|
// Fix up the buttons for Checkupgradeonly.
|
|
//
|
|
PropSheet_SetWizButtons( GetParent(hdlg), (WizPage->CommonData.Buttons | PSWIZB_FINISH) );
|
|
EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),FALSE);
|
|
ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_HIDE);
|
|
}
|
|
|
|
if(ISNT() && OsVersion.dwMajorVersion == 5 ){
|
|
|
|
if (!AnyNt5CompatDlls) {
|
|
//
|
|
// sanity check
|
|
//
|
|
MYASSERT (!IncompatibilityStopsInstallation);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
if (Count) {
|
|
//
|
|
// only need this page if there are incompatibities
|
|
//
|
|
|
|
if( (!CheckUpgradeOnly) && (UnattendedOperation) && (ErrorsPresent == FALSE) ) {
|
|
//
|
|
// We're doing an unattended upgrade, and there are
|
|
// only warnings. Blow past the page.
|
|
//
|
|
b = FALSE;
|
|
|
|
} else {
|
|
TCHAR Text[512];
|
|
|
|
//
|
|
// Customize the look of the page, depending on
|
|
// what we have to display. 3 cases are possible:
|
|
// 1. Warnings only (services we'll stop).
|
|
// 2. Errors only (items that will prevent installation).
|
|
// 3. combination of 1. and 2.
|
|
//
|
|
if( (CheckUpgradeOnly == TRUE) && (CheckUpgradeNoItems == TRUE) ) {
|
|
LoadString(hInst,IDS_COMPAT_CHECKUPGRADE,Text,sizeof(Text)/sizeof(TCHAR));
|
|
} else if( (WarningsPresent == TRUE) && (ErrorsPresent == TRUE) ) {
|
|
LoadString(hInst,IDS_COMPAT_ERR_WRN,Text,sizeof(Text)/sizeof(TCHAR));
|
|
} else if( WarningsPresent == TRUE ) {
|
|
LoadString(hInst,IDS_COMPAT_WRN,Text,sizeof(Text)/sizeof(TCHAR));
|
|
} else if( ErrorsPresent == TRUE ) {
|
|
LoadString(hInst,IDS_COMPAT_ERR,Text,sizeof(Text)/sizeof(TCHAR));
|
|
}
|
|
SetDlgItemText(hdlg,IDC_INTRO_TEXT,Text);
|
|
|
|
b = TRUE;
|
|
|
|
if (BatchMode || (CheckUpgradeOnly && UnattendSwitchSpecified)) {
|
|
//
|
|
// don't stop on this page in batch mode
|
|
//
|
|
UNATTENDED(PSBTN_NEXT);
|
|
}
|
|
else
|
|
{
|
|
// Stop the bill board and show the wizard again.
|
|
SendMessage(GetParent (hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!b) {
|
|
//
|
|
// sanity check
|
|
//
|
|
MYASSERT (!IncompatibilityStopsInstallation);
|
|
}
|
|
|
|
} else {
|
|
b = TRUE;
|
|
}
|
|
break;
|
|
|
|
case WMX_NEXTBUTTON:
|
|
|
|
if (IncompatibilityStopsInstallation) {
|
|
SaveMessageForSMS( MSG_INCOMPATIBILITIES );
|
|
// Send the ID of the page we wish to advance to
|
|
*((LONG *)lParam) = IDD_CLEANING;
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ProcessLine (
|
|
IN DWORD CompatFlags
|
|
)
|
|
{
|
|
DWORD currentVersion;
|
|
//return (OsVersion.dwMajorVersion < 5) || (CompatFlags & COMPFLAG_ALLOWNT5COMPAT);
|
|
switch (OsVersionNumber) {
|
|
case 400:
|
|
return ( !(CompatFlags & COMPFLAG_SKIPNT40CHECK));
|
|
case 500:
|
|
return ( !(CompatFlags & COMPFLAG_SKIPNT50CHECK));
|
|
case 501: // version 5.1
|
|
return ( !(CompatFlags & COMPFLAG_SKIPNT51CHECK));
|
|
default:
|
|
return TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ProcessRegistryLine(
|
|
LPVOID InfHandle,
|
|
LPTSTR SectionName,
|
|
DWORD Index
|
|
)
|
|
{
|
|
LONG Error;
|
|
HKEY hKey;
|
|
DWORD Size, Reg_Type;
|
|
LPBYTE Buffer;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
LPCTSTR RegKey;
|
|
LPCTSTR RegValue;
|
|
LPCTSTR RegValueExpect;
|
|
LPCTSTR Flags;
|
|
TCHAR Value[20];
|
|
PCTSTR Data;
|
|
DWORD compatFlags = 0;
|
|
BOOL bFail;
|
|
|
|
|
|
//
|
|
// first check if this line should be processed on NT5
|
|
//
|
|
Flags = InfGetFieldByIndex( InfHandle, SectionName, Index, 9 );
|
|
if( Flags ){
|
|
StringToInt ( Flags, &compatFlags);
|
|
}
|
|
if (!ProcessLine (compatFlags)) {
|
|
return 0;
|
|
}
|
|
|
|
RegKey = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
|
|
RegValue = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
|
|
RegValueExpect = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
|
|
|
|
|
|
//
|
|
// open the reg key
|
|
//
|
|
|
|
Error = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
RegKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
if( Error != ERROR_SUCCESS ) {
|
|
//
|
|
// bogus reg key
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// find out how much data there is
|
|
//
|
|
|
|
Error = RegQueryValueEx(
|
|
hKey,
|
|
RegValue,
|
|
NULL,
|
|
&Reg_Type,
|
|
NULL,
|
|
&Size
|
|
);
|
|
if( Error == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// allocate the buffer
|
|
//
|
|
|
|
Buffer = (LPBYTE) MALLOC( Size );
|
|
if (Buffer == NULL) {
|
|
RegCloseKey( hKey );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// read the data
|
|
//
|
|
|
|
Error = RegQueryValueEx(
|
|
hKey,
|
|
RegValue,
|
|
NULL,
|
|
NULL,
|
|
Buffer,
|
|
&Size
|
|
);
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
FREE( Buffer );
|
|
return 0;
|
|
}
|
|
|
|
if( Reg_Type == REG_DWORD ){
|
|
_itot( *(DWORD*)Buffer, Value, 10 );
|
|
Data = Value;
|
|
} else {
|
|
Data = (PCTSTR)Buffer;
|
|
}
|
|
|
|
bFail = RegValueExpect && *RegValueExpect && (lstrcmp( RegValueExpect, Data ) != 0);
|
|
|
|
FREE( Buffer );
|
|
|
|
if (bFail) {
|
|
return 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if (RegValue && *RegValue) {
|
|
return 0;
|
|
}
|
|
if (Error != ERROR_FILE_NOT_FOUND) {
|
|
return 0;
|
|
}
|
|
if (RegValueExpect && *RegValueExpect) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
|
|
if (CompData == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
|
|
|
|
CompData->Type = TEXT('r');
|
|
CompData->RegKey = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
|
|
CompData->RegValue = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
|
|
CompData->RegValueExpect = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
|
|
CompData->HtmlName = InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
|
|
CompData->TextName = InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
|
|
if (!(CompData->TextName && *CompData->TextName)) {
|
|
CompData->TextName = CompData->HtmlName;
|
|
}
|
|
CompData->Description = InfGetFieldByIndex( InfHandle, SectionName, Index, 6 );
|
|
CompData->InfName = InfGetFieldByIndex( InfHandle, SectionName, Index, 7 );
|
|
CompData->InfSection = InfGetFieldByIndex( InfHandle, SectionName, Index, 8 );
|
|
CompData->Flags = compatFlags | GlobalCompFlags;
|
|
|
|
|
|
InsertTailList( &CompatibilityData, &CompData->ListEntry );
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ProcessServiceLine(
|
|
LPVOID InfHandle,
|
|
LPTSTR SectionName,
|
|
DWORD Index,
|
|
BOOL SetCheckedFlag
|
|
)
|
|
{
|
|
TCHAR KeyName[MAX_PATH];
|
|
LONG Error;
|
|
HKEY hKey;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
LPCTSTR ServiceName;
|
|
LPDWORD RegData;
|
|
DWORD Value;
|
|
DWORD ValueSize;
|
|
LPCTSTR FileName, FileVer, Flags;
|
|
LPCTSTR linkDateStr, binProdVerStr;
|
|
DWORD compatFlags = 0;
|
|
|
|
|
|
Flags = InfGetFieldByIndex( InfHandle, SectionName, Index, 7 );
|
|
if( Flags ){
|
|
StringToInt ( Flags, &compatFlags);
|
|
}
|
|
|
|
//
|
|
// first check if this line should be processed on NT5
|
|
//
|
|
if (!ProcessLine (compatFlags)) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
ServiceName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
|
|
BuildPath (KeyName, TEXT("SYSTEM\\CurrentControlSet\\Services"), ServiceName);
|
|
//
|
|
// get an open key to the services database
|
|
//
|
|
|
|
Error = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
KeyName,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hKey
|
|
);
|
|
if( Error != ERROR_SUCCESS ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// We'll ceate a key here so that others will know that we've
|
|
// already checked this service. We'll remove it later. We
|
|
// don't care about error codes here because this is only used
|
|
// as a safety net for checks that may come after us.
|
|
//
|
|
if( SetCheckedFlag ) {
|
|
Value = 1;
|
|
RegSetValueEx( hKey,
|
|
TEXT("SetupChecked"),
|
|
0,
|
|
REG_DWORD,
|
|
(CONST BYTE *)&Value,
|
|
sizeof(DWORD) );
|
|
} else {
|
|
//
|
|
// The user has asked us to simply remove these 'checked' flags
|
|
// from the services that we've examined.
|
|
//
|
|
RegDeleteValue( hKey,
|
|
TEXT("SetupChecked") );
|
|
RegCloseKey( hKey );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Check the start value of our target service.
|
|
//
|
|
ValueSize = sizeof(Value);
|
|
|
|
Error = RegQueryValueEx(
|
|
hKey,
|
|
TEXT("Start"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&Value,
|
|
&ValueSize
|
|
);
|
|
|
|
if( Error != ERROR_SUCCESS){
|
|
Value = (DWORD)-1;
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
// Have to check for the contents being NULL as InfGetFieldByIndex returns
|
|
// a valid pointer holding NULL if the field is blank. Also we need to go on in that case
|
|
// to look for Flags.
|
|
FileName = InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
|
|
FileVer = InfGetFieldByIndex( InfHandle, SectionName, Index, 6 );
|
|
|
|
if( FileName && *FileName) {
|
|
|
|
linkDateStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 10);
|
|
binProdVerStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 11);
|
|
|
|
if (!CheckForFileVersionEx ( FileName, FileVer, binProdVerStr, linkDateStr))
|
|
return 0;
|
|
}
|
|
|
|
RegData = (LPDWORD)MALLOC( sizeof(DWORD) );
|
|
if (RegData == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
|
|
if (CompData == NULL) {
|
|
FREE(RegData);
|
|
return 0;
|
|
}
|
|
|
|
ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
|
|
|
|
CompData->Type = TEXT('s');
|
|
CompData->Flags = compatFlags;
|
|
|
|
CompData->ServiceName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
|
|
CompData->HtmlName = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
|
|
CompData->TextName = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
|
|
if (!(CompData->TextName && *CompData->TextName)) {
|
|
CompData->TextName = CompData->HtmlName;
|
|
}
|
|
CompData->Description = InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
|
|
CompData->RegKeyName = DupString( KeyName );
|
|
CompData->RegValName = DupString( TEXT("Start") );
|
|
RegData[0] = SERVICE_DISABLED;
|
|
CompData->RegValData = RegData;
|
|
CompData->RegValDataSize = sizeof(DWORD);
|
|
CompData->Flags |= GlobalCompFlags;
|
|
CompData->InfName = InfGetFieldByIndex( InfHandle, SectionName, Index, 8 );
|
|
CompData->InfSection = InfGetFieldByIndex( InfHandle, SectionName, Index, 9 );
|
|
|
|
|
|
if( Value == SERVICE_DISABLED) {
|
|
// Let's not block installation since we didn't before and doesn't need to be now either.
|
|
CompData->Flags &= ~COMPFLAG_STOPINSTALL;
|
|
// Don't display any warnings since they can't do anything about it.
|
|
CompData->Flags |= COMPFLAG_HIDE;
|
|
}
|
|
InsertTailList( &CompatibilityData, &CompData->ListEntry );
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ProcessTextModeLine(
|
|
LPVOID InfHandle,
|
|
LPTSTR SectionName,
|
|
DWORD Index
|
|
)
|
|
{
|
|
//
|
|
// Format of line:
|
|
// 0, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8
|
|
// t,"fullpath","version.minor","html","text",%stringid%,flags,linkdate,binprodversion
|
|
//
|
|
PCOMPATIBILITY_DATA CompData;
|
|
LPCTSTR FileName;
|
|
LPCTSTR Flags;
|
|
LPCTSTR FileVer;
|
|
DWORD CompatFlags = 0;
|
|
|
|
//
|
|
// The only thing we need to start is the file name.
|
|
//
|
|
FileName = InfGetFieldByIndex(InfHandle, SectionName, Index, 1);
|
|
|
|
//
|
|
// If there was a filename, then see if its version and whatnot actually
|
|
// match
|
|
//
|
|
if ( FileName && *FileName )
|
|
{
|
|
LPCTSTR linkDateStr, binProdVerStr;
|
|
|
|
FileVer = InfGetFieldByIndex(InfHandle, SectionName, Index, 2);
|
|
linkDateStr = InfGetFieldByIndex(InfHandle, SectionName, Index, 7);
|
|
binProdVerStr = InfGetFieldByIndex(InfHandle, SectionName, Index, 8);
|
|
|
|
if ( !CheckForFileVersionEx( FileName, FileVer, binProdVerStr, linkDateStr ) )
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
Flags = InfGetFieldByIndex(InfHandle, SectionName, Index, 6);
|
|
|
|
if ( Flags != NULL ){
|
|
StringToInt(Flags, &CompatFlags);
|
|
}
|
|
|
|
CompData = (PCOMPATIBILITY_DATA)MALLOC(sizeof(COMPATIBILITY_DATA));
|
|
if ( CompData == NULL )
|
|
return 0;
|
|
|
|
//
|
|
// Now fill out the compdata structure
|
|
//
|
|
ZeroMemory(CompData, sizeof(*CompData));
|
|
CompData->FileName = FileName;
|
|
CompData->FileVer = FileVer;
|
|
CompData->HtmlName = InfGetFieldByIndex(InfHandle, SectionName, Index, 3);
|
|
CompData->TextName = InfGetFieldByIndex(InfHandle, SectionName, Index, 4);
|
|
if ( ( CompData->TextName == NULL ) || !CompData->TextName[0] )
|
|
CompData->TextName = CompData->HtmlName;
|
|
CompData->Description = InfGetFieldByIndex(InfHandle, SectionName, Index, 5);
|
|
|
|
//
|
|
CompData->Flags = CompatFlags | GlobalCompFlags | COMPFLAG_HIDE;
|
|
CompData->Type = TEXT('t');
|
|
|
|
InsertTailList(&CompatibilityData, &CompData->ListEntry);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
DWORD
|
|
ProcessFileLine(
|
|
LPVOID InfHandle,
|
|
LPTSTR SectionName,
|
|
DWORD Index
|
|
)
|
|
{
|
|
|
|
PCOMPATIBILITY_DATA CompData;
|
|
LPCTSTR FileName;
|
|
LPCTSTR FileVer;
|
|
LPCTSTR Flags;
|
|
LPCTSTR linkDateStr, binProdVerStr;
|
|
DWORD compatFlags = 0;
|
|
|
|
|
|
//
|
|
// first check if this line should be processed on NT5
|
|
//
|
|
Flags = InfGetFieldByIndex( InfHandle, SectionName, Index, 8);
|
|
if( Flags ){
|
|
StringToInt ( Flags, &compatFlags);
|
|
}
|
|
if (!ProcessLine (compatFlags)) {
|
|
return 0;
|
|
}
|
|
|
|
FileName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
|
|
FileVer = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
|
|
|
|
|
|
if( FileName && *FileName ){
|
|
|
|
linkDateStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 9);
|
|
binProdVerStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 10);
|
|
|
|
if (!CheckForFileVersionEx ( FileName, FileVer, binProdVerStr, linkDateStr)) {
|
|
return 0;
|
|
}
|
|
}else{
|
|
return 0;
|
|
}
|
|
|
|
|
|
CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
|
|
if (CompData == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
|
|
|
|
CompData->Type = TEXT('f');
|
|
CompData->FileName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
|
|
CompData->FileVer = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
|
|
CompData->HtmlName = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
|
|
CompData->TextName = InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
|
|
if (!(CompData->TextName && *CompData->TextName)) {
|
|
CompData->TextName = CompData->HtmlName;
|
|
}
|
|
CompData->Description = InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
|
|
CompData->InfName = InfGetFieldByIndex( InfHandle, SectionName, Index, 6 );
|
|
CompData->InfSection = InfGetFieldByIndex( InfHandle, SectionName, Index, 7 );
|
|
CompData->Flags = compatFlags | GlobalCompFlags;
|
|
|
|
InsertTailList( &CompatibilityData, &CompData->ListEntry );
|
|
|
|
return 1;
|
|
}
|
|
|
|
BOOL
|
|
CompatibilityCallback(
|
|
PCOMPATIBILITY_ENTRY CompEntry,
|
|
PCOMPATIBILITY_CONTEXT CompContext
|
|
)
|
|
{
|
|
PCOMPATIBILITY_DATA CompData;
|
|
|
|
//
|
|
// parameter validation
|
|
//
|
|
|
|
if (CompEntry->Description == NULL || CompEntry->Description[0] == 0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_DESC_MISSING );
|
|
return FALSE;
|
|
}
|
|
|
|
if (CompEntry->TextName == NULL || CompEntry->TextName[0] ==0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_TEXTNAME_MISSING );
|
|
return FALSE;
|
|
}
|
|
|
|
if (CompEntry->RegKeyName) {
|
|
if (CompEntry->RegValName == NULL) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_REGVALNAME_MISSING );
|
|
return FALSE;
|
|
}
|
|
if (CompEntry->RegValData == NULL) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_REGVALDATA_MISSING );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
if (CompEntry->InfName) {
|
|
if (CompEntry->InfSection == NULL) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_INFSECTION_MISSING );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
if (IsTextUnicode( CompEntry->Description, wcslen(CompEntry->Description)*sizeof(WCHAR), NULL ) == 0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_DESC_NOT_UNICODE );
|
|
return FALSE;
|
|
}
|
|
if (IsTextUnicode( CompEntry->TextName, wcslen(CompEntry->TextName)*sizeof(WCHAR), NULL ) == 0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_TEXTNAME_NOT_UNICODE );
|
|
return FALSE;
|
|
}
|
|
if (CompEntry->HtmlName) {
|
|
if (IsTextUnicode( CompEntry->HtmlName, wcslen(CompEntry->HtmlName)*sizeof(WCHAR), NULL ) == 0) {
|
|
SetLastError( COMP_ERR_HTMLNAME_NOT_UNICODE );
|
|
return FALSE;
|
|
}
|
|
}
|
|
if (CompEntry->RegKeyName) {
|
|
if (IsTextUnicode( CompEntry->RegKeyName, wcslen(CompEntry->RegKeyName)*sizeof(WCHAR), NULL ) == 0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_REGKEYNAME_NOT_UNICODE );
|
|
return FALSE;
|
|
}
|
|
if (IsTextUnicode( CompEntry->RegValName, wcslen(CompEntry->RegValName)*sizeof(WCHAR), NULL ) == 0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_REGVALNAME_NOT_UNICODE );
|
|
return FALSE;
|
|
}
|
|
}
|
|
if (CompEntry->InfName) {
|
|
if (IsTextUnicode( CompEntry->InfName, wcslen(CompEntry->InfName)*sizeof(WCHAR), NULL ) == 0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_INFNAME_NOT_UNICODE );
|
|
return FALSE;
|
|
}
|
|
if (IsTextUnicode( CompEntry->InfSection, wcslen(CompEntry->InfSection)*sizeof(WCHAR), NULL ) == 0) {
|
|
//
|
|
// who did this?
|
|
//
|
|
MYASSERT (FALSE);
|
|
SetLastError( COMP_ERR_INFSECTION_NOT_UNICODE );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
//
|
|
// allocate the compatibility structure
|
|
//
|
|
|
|
CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
|
|
if (CompData == NULL) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory(CompData, sizeof(COMPATIBILITY_DATA));
|
|
|
|
//
|
|
// save the sata
|
|
//
|
|
|
|
CompData->Description = DupString( CompEntry->Description );
|
|
CompData->HtmlName = CompEntry->HtmlName ? DupString( CompEntry->HtmlName ) : NULL;
|
|
CompData->TextName = DupString( CompEntry->TextName );
|
|
CompData->SaveValue = CompEntry->SaveValue;
|
|
CompData->Flags = CompEntry->Flags;
|
|
CompData->Flags |= PerCompatDllFlags;
|
|
CompData->Flags |= GlobalCompFlags;
|
|
CompData->CompHaveDisk = CompContext->CompHaveDisk;
|
|
CompData->hModDll = CompContext->hModDll;
|
|
if (CompEntry->RegKeyName) {
|
|
CompData->RegKeyName = DupString( CompEntry->RegKeyName );
|
|
CompData->RegValName = DupString( CompEntry->RegValName );
|
|
CompData->RegValDataSize = CompEntry->RegValDataSize;
|
|
CompData->RegValData = MALLOC(CompEntry->RegValDataSize);
|
|
if (CompData->RegValData) {
|
|
CopyMemory( CompData->RegValData, CompEntry->RegValData, CompEntry->RegValDataSize );
|
|
}
|
|
}
|
|
if (CompEntry->InfName){
|
|
CompData->InfName = DupString( CompEntry->InfName );
|
|
CompData->InfSection = DupString( CompEntry->InfSection );
|
|
|
|
}
|
|
|
|
InsertTailList( &CompatibilityData, &CompData->ListEntry );
|
|
|
|
CompContext->Count += 1;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ProcessDLLLine(
|
|
LPVOID InfHandle,
|
|
LPTSTR SectionName,
|
|
DWORD Index
|
|
)
|
|
{
|
|
TCHAR Buffer[MAX_PATH];
|
|
TCHAR FullPath[MAX_PATH];
|
|
HMODULE hMod;
|
|
CHAR CompCheckEntryPoint[MAX_PATH];
|
|
CHAR HaveDiskEntryPoint[MAX_PATH];
|
|
PCOMPAIBILITYCHECK CompCheck;
|
|
PCOMPAIBILITYHAVEDISK CompHaveDisk;
|
|
LPTSTR DllName;
|
|
LPTSTR CompCheckEntryPointW;
|
|
LPTSTR HaveDiskEntryPointW;
|
|
LPTSTR ProcessOnCleanInstall;
|
|
LPTSTR Flags;
|
|
COMPATIBILITY_CONTEXT CompContext;
|
|
BOOL Rslt;
|
|
DWORD Status;
|
|
DWORD compatFlags = 0;
|
|
|
|
PerCompatDllFlags = 0;
|
|
DllName = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
|
|
if (!DllName)
|
|
return 0;
|
|
CompCheckEntryPointW = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
|
|
HaveDiskEntryPointW = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
|
|
if((HaveDiskEntryPointW != NULL) && (lstrlen(HaveDiskEntryPointW) == 0)) {
|
|
//
|
|
// If HaveDiskEntryPointW points to an empty string, then make it NULL.
|
|
// This is necessary because since this field is optional, the user may have specified
|
|
// it in dosnet.inf as ,, and in this case the winnt32 parser will translate the info in
|
|
// filed as an empty string.
|
|
//
|
|
HaveDiskEntryPointW = NULL;
|
|
}
|
|
ProcessOnCleanInstall = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
|
|
|
|
if( !Upgrade &&
|
|
((ProcessOnCleanInstall == NULL) ||
|
|
(lstrlen( ProcessOnCleanInstall ) == 0) ||
|
|
(_ttoi(ProcessOnCleanInstall) == 0))
|
|
) {
|
|
//
|
|
// On clean install, we don't process the dll if 'ProcessOnCleanInstall' was not
|
|
// specified, or if it was specified as 0.
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
Flags = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
|
|
if( Flags ){
|
|
//check return value
|
|
StringToInt ( Flags, &compatFlags);
|
|
}
|
|
PerCompatDllFlags = compatFlags;
|
|
|
|
|
|
if (!ExpandEnvironmentStrings( DllName, Buffer, sizeof(Buffer)/sizeof(TCHAR) )) {
|
|
return 0;
|
|
}
|
|
|
|
if (!FindPathToWinnt32File (Buffer, FullPath, MAX_PATH) ||
|
|
!(hMod = LoadLibrary (FullPath))) {
|
|
return 0;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
CompCheckEntryPointW,
|
|
-1,
|
|
CompCheckEntryPoint,
|
|
sizeof(CompCheckEntryPoint),
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (HaveDiskEntryPointW) {
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
HaveDiskEntryPointW,
|
|
-1,
|
|
HaveDiskEntryPoint,
|
|
sizeof(HaveDiskEntryPoint),
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
#else
|
|
lstrcpy( CompCheckEntryPoint, CompCheckEntryPointW );
|
|
if (HaveDiskEntryPointW) {
|
|
lstrcpy( HaveDiskEntryPoint, HaveDiskEntryPointW );
|
|
}
|
|
#endif
|
|
|
|
CompCheck = (PCOMPAIBILITYCHECK) GetProcAddress( hMod, CompCheckEntryPoint );
|
|
if (CompCheck == NULL) {
|
|
FreeLibrary( hMod );
|
|
return 0;
|
|
}
|
|
|
|
if (HaveDiskEntryPointW) {
|
|
CompHaveDisk = (PCOMPAIBILITYHAVEDISK) GetProcAddress( hMod, HaveDiskEntryPoint );
|
|
if (CompHaveDisk == NULL) {
|
|
FreeLibrary( hMod );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
CompContext.Count = 0;
|
|
CompContext.CompHaveDisk = CompHaveDisk;
|
|
CompContext.hModDll = hMod;
|
|
|
|
if ( !ProcessLine( compatFlags )) {
|
|
Rslt = FALSE;
|
|
} else {
|
|
__try {
|
|
Rslt = CompCheck( (PCOMPAIBILITYCALLBACK)CompatibilityCallback, (LPVOID)&CompContext );
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
Rslt = FALSE;
|
|
}
|
|
}
|
|
|
|
PerCompatDllFlags = 0;
|
|
|
|
if (!Rslt) {
|
|
FreeLibrary( hMod );
|
|
return 0;
|
|
}
|
|
|
|
if (CompContext.Count == 0) {
|
|
FreeLibrary( hMod );
|
|
}
|
|
|
|
return CompContext.Count;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ProcessCompatibilitySection(
|
|
LPVOID InfHandle,
|
|
LPTSTR SectionName
|
|
)
|
|
{
|
|
DWORD LineCount;
|
|
DWORD Count;
|
|
DWORD i;
|
|
LPCTSTR Type;
|
|
DWORD Good;
|
|
|
|
|
|
//
|
|
// get the section count, zero means bail out
|
|
//
|
|
|
|
LineCount = InfGetSectionLineCount( InfHandle, SectionName );
|
|
if (LineCount == 0 || LineCount == 0xffffffff) {
|
|
return 0;
|
|
}
|
|
|
|
for (i=0,Count=0; i<LineCount; i++) {
|
|
|
|
Type = InfGetFieldByIndex( InfHandle, SectionName, i, 0 );
|
|
if (Type == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// On clean install we only process dll line.
|
|
// (We need to process the line that checks for unsupported architectures)
|
|
//
|
|
if( !Upgrade && ( _totlower(Type[0]) != TEXT('d') ) ) {
|
|
continue;
|
|
}
|
|
switch (_totlower(Type[0])) {
|
|
case TEXT('r'):
|
|
//
|
|
// registry value
|
|
//
|
|
Count += ProcessRegistryLine( InfHandle, SectionName, i );
|
|
break;
|
|
|
|
case TEXT('s'):
|
|
//
|
|
// service or driver
|
|
//
|
|
Count += ProcessServiceLine( InfHandle, SectionName, i, TRUE );
|
|
break;
|
|
|
|
case TEXT('f'):
|
|
//
|
|
// presence of a file
|
|
//
|
|
Count += ProcessFileLine( InfHandle, SectionName, i );
|
|
break;
|
|
|
|
case TEXT('d'):
|
|
//
|
|
// run an external dll
|
|
//
|
|
Count += ProcessDLLLine( InfHandle, SectionName, i );
|
|
break;
|
|
|
|
case TEXT('t'):
|
|
//
|
|
// Textmode should know to overwrite this file
|
|
//
|
|
Count += ProcessTextModeLine( InfHandle, SectionName, i );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveCompatibilityServiceEntries(
|
|
LPVOID InfHandle,
|
|
LPTSTR SectionName
|
|
)
|
|
{
|
|
DWORD LineCount;
|
|
DWORD Count;
|
|
DWORD i;
|
|
LPCTSTR Type;
|
|
DWORD Good;
|
|
|
|
|
|
//
|
|
// get the section count, zero means bail out
|
|
//
|
|
|
|
LineCount = InfGetSectionLineCount( InfHandle, SectionName );
|
|
if (LineCount == 0 || LineCount == 0xffffffff) {
|
|
return;
|
|
}
|
|
|
|
for (i=0,Count=0; i<LineCount; i++) {
|
|
|
|
Type = InfGetFieldByIndex( InfHandle, SectionName, i, 0 );
|
|
if (Type == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// On clean install we only process dll line.
|
|
// (We need to process the line that checks for unsupported architectures)
|
|
//
|
|
if( !Upgrade && ( _totlower(Type[0]) != TEXT('d') ) ) {
|
|
continue;
|
|
}
|
|
switch (_totlower(Type[0])) {
|
|
case TEXT('s'):
|
|
//
|
|
// service or driver
|
|
//
|
|
Count += ProcessServiceLine( InfHandle, SectionName, i, FALSE );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// HACKHACK - NT4's explorer.exe will fail to properly process runonce values
|
|
// whose value name is > 31 characters. We call this function to
|
|
// workaround this NT4 bug. It basically truncates any value names
|
|
// so that explorer will process and delete them.
|
|
//
|
|
void FixRunOnceForNT4(DWORD dwNumValues)
|
|
{
|
|
HKEY hkRunOnce;
|
|
int iValueNumber = 20; // start this at 20 to minimize chance of name collision.
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
|
|
0,
|
|
MAXIMUM_ALLOWED,
|
|
&hkRunOnce) == ERROR_SUCCESS)
|
|
{
|
|
TCHAR szValueName[MAX_PATH];
|
|
TCHAR szValueContents[MAX_PATH * 3]; // big enough to hold a large regsvr32 command
|
|
DWORD dwValueIndex = 0;
|
|
DWORD dwSanityCheck = 0;
|
|
DWORD dwNameSize = MAX_PATH;
|
|
DWORD dwValueSize = sizeof(szValueContents);
|
|
DWORD dwType;
|
|
|
|
while (RegEnumValue(hkRunOnce,
|
|
dwValueIndex,
|
|
szValueName,
|
|
&dwNameSize,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)szValueContents,
|
|
&dwValueSize) == ERROR_SUCCESS)
|
|
{
|
|
// increment our counters
|
|
dwValueIndex++;
|
|
dwSanityCheck++;
|
|
|
|
// reset these for the next RegEnumValue call
|
|
dwNameSize = MAX_PATH;
|
|
dwValueSize = sizeof(szValueContents);
|
|
|
|
if ((dwType == REG_SZ) && (lstrlen(szValueName) > 31))
|
|
{
|
|
TCHAR szNewValueName[32];
|
|
TCHAR szTemp[32];
|
|
|
|
// we have a value name that is too big for NT4's explorer.exe,
|
|
// so we need to truncate to 10 characters and add a number on the
|
|
// end to insure that it is unique.
|
|
lstrcpyn(szTemp, szValueName, 10);
|
|
wsprintf(szNewValueName, TEXT("%s%d"), szTemp, iValueNumber++);
|
|
|
|
RegDeleteValue(hkRunOnce, szValueName);
|
|
|
|
RegSetValueEx(hkRunOnce,
|
|
szNewValueName,
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)szValueContents,
|
|
(lstrlen(szValueContents) + 1) * sizeof(TCHAR));
|
|
|
|
// backup our regenum index to be sure we don't miss a value (since we are adding/deleteing
|
|
// values during the enumeration, its kinda messy)
|
|
dwValueIndex--;
|
|
}
|
|
|
|
if (dwSanityCheck > (2 * dwNumValues))
|
|
{
|
|
// something has gone terribly wrong, we have looped in RegEnumValue *way* to
|
|
// many times!
|
|
break;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkRunOnce);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
pCheckForPendingRunOnce (
|
|
VOID
|
|
)
|
|
{
|
|
LONG Error;
|
|
HKEY hKey = NULL;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
HKEY setupKey = NULL;
|
|
DWORD dataSize;
|
|
BOOL result = FALSE;
|
|
TCHAR textBuffer[512];
|
|
TCHAR exeBuffer[512];
|
|
DWORD exeBufferSize;
|
|
DWORD type;
|
|
DWORD valueNumber;
|
|
BOOL foundValues = FALSE;
|
|
INF_ENUM e;
|
|
BOOL warningIssued = FALSE;
|
|
BOOL ignore;
|
|
|
|
__try {
|
|
//
|
|
// Open regisry keys.
|
|
//
|
|
// ISSUE: Should this be expanded to include HKCU?
|
|
//
|
|
|
|
Error = RegOpenKeyEx (
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey
|
|
);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
//
|
|
// no RunOnce key [this should exist in all cases]
|
|
//
|
|
__leave;
|
|
}
|
|
|
|
Error = RegOpenKeyEx (
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&setupKey
|
|
);
|
|
|
|
//
|
|
// Did we already provide a warning?
|
|
//
|
|
|
|
if (setupKey) {
|
|
dataSize = sizeof (textBuffer);
|
|
|
|
Error = RegQueryValueEx (
|
|
setupKey,
|
|
S_WINNT32_WARNING,
|
|
NULL,
|
|
NULL,
|
|
(PBYTE) textBuffer,
|
|
&dataSize
|
|
);
|
|
|
|
if (Error == ERROR_SUCCESS) {
|
|
//
|
|
// Warning was issued. Did user reboot as instructed? If they
|
|
// did, then the RunOnce entry should be gone. Otherwise, we
|
|
// will not provide the warning again if someone keeps
|
|
// putting junk in RunOnce.
|
|
//
|
|
|
|
dataSize = sizeof (textBuffer);
|
|
|
|
Error = RegQueryValueEx (
|
|
hKey,
|
|
S_WINNT32_WARNING,
|
|
NULL,
|
|
NULL,
|
|
(PBYTE) textBuffer,
|
|
&dataSize
|
|
);
|
|
|
|
if (Error == ERROR_SUCCESS) {
|
|
foundValues = TRUE;
|
|
} else {
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// The warning has never been issued. Check if there are any RunOnce
|
|
// entries present. Skip excluded entries.
|
|
//
|
|
// NOTE: We restrict the loop to 10000, in line with existing code that
|
|
// is protecting itself from enumerations that never end on NT
|
|
// 4. It is not clear this is needed, but 10000 should be high
|
|
// enough to take care of this risk without introducing other
|
|
// problems.
|
|
//
|
|
|
|
if (!foundValues) {
|
|
|
|
for (valueNumber = 0 ; valueNumber < 10000 ; valueNumber++) {
|
|
|
|
dataSize = sizeof (textBuffer) / sizeof (TCHAR);
|
|
exeBufferSize = sizeof (exeBuffer);
|
|
|
|
Error = RegEnumValue (
|
|
hKey,
|
|
valueNumber,
|
|
textBuffer,
|
|
&dataSize,
|
|
NULL,
|
|
&type,
|
|
(PBYTE) exeBuffer,
|
|
&exeBufferSize
|
|
);
|
|
|
|
if (Error == ERROR_NO_MORE_ITEMS) {
|
|
break;
|
|
}
|
|
|
|
if (Error == ERROR_SUCCESS) {
|
|
//
|
|
// Test registry value against pattern list
|
|
//
|
|
|
|
ignore = FALSE;
|
|
if (EnumFirstInfLine (&e, MainInf, TEXT("RunOnceExclusions.Value"))) {
|
|
do {
|
|
if (IsPatternMatch (e.FieldZeroData, textBuffer)) {
|
|
AbortInfLineEnum (&e);
|
|
ignore = TRUE;
|
|
break;
|
|
}
|
|
} while (EnumNextInfLine (&e));
|
|
}
|
|
|
|
if (ignore) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Test command line against pattern list
|
|
//
|
|
|
|
if (EnumFirstInfLine (&e, MainInf, TEXT("RunOnceExclusions.ValueData"))) {
|
|
do {
|
|
if (IsPatternMatch (e.FieldZeroData, exeBuffer)) {
|
|
AbortInfLineEnum (&e);
|
|
ignore = TRUE;
|
|
break;
|
|
}
|
|
} while (EnumNextInfLine (&e));
|
|
}
|
|
|
|
if (ignore) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Found a RunOnce entry that should be executed before upgrading
|
|
//
|
|
|
|
foundValues = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If no RunOnce values found, don't provide the warning.
|
|
//
|
|
|
|
if (!foundValues) {
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Otherwise, provide the warning, and write Winnt32Warning to the Setup
|
|
// key and RunOnce key.
|
|
//
|
|
|
|
CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
|
|
if (CompData == NULL) {
|
|
__leave;
|
|
}
|
|
|
|
ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
|
|
|
|
if(!LoadString(hInst,IDS_COMPAT_PENDING_REBOOT,textBuffer,sizeof(textBuffer)/sizeof(TCHAR))) {
|
|
CompData->Description = 0;
|
|
} else {
|
|
CompData->Description = DupString(textBuffer);
|
|
}
|
|
|
|
CompData->Flags |= GlobalCompFlags;
|
|
CompData->HtmlName = DupString( TEXT("compdata\\runonce.htm") );
|
|
CompData->TextName = DupString( TEXT("compdata\\runonce.txt") );
|
|
|
|
InsertTailList( &CompatibilityData, &CompData->ListEntry );
|
|
|
|
if (ISNT() && BuildNumber <= 1381) {
|
|
//
|
|
// Get the number of values for the worker fn, so it
|
|
// can protect itself against a runaway enumeration.
|
|
//
|
|
|
|
Error = RegQueryInfoKey (
|
|
hKey,
|
|
NULL, // class
|
|
NULL, // class size
|
|
NULL, // reserved
|
|
NULL, // subkey count
|
|
NULL, // max subkeys
|
|
NULL, // max class
|
|
&valueNumber, // value count
|
|
NULL, // max value name len
|
|
NULL, // max value data len
|
|
NULL, // security desc
|
|
NULL // last write time
|
|
);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
valueNumber = 100; // some random count, doesn't really matter because failure case is impracticle
|
|
}
|
|
|
|
FixRunOnceForNT4 (valueNumber);
|
|
}
|
|
|
|
RegSetValueEx (
|
|
setupKey,
|
|
S_WINNT32_WARNING,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE) TEXT(""), // value is all that matters, data is irrelevant
|
|
sizeof (TCHAR)
|
|
);
|
|
|
|
RegSetValueEx (
|
|
hKey,
|
|
S_WINNT32_WARNING,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE) TEXT("user.exe"), // this EXE exists on all machines, terminates right away
|
|
// and produces no UI
|
|
sizeof (TEXT("user.exe"))
|
|
);
|
|
|
|
result = TRUE;
|
|
}
|
|
__finally {
|
|
if (!result && setupKey) {
|
|
//
|
|
// Clean up warning flag at the end of WINNT32
|
|
//
|
|
|
|
g_DeleteRunOnceFlag = TRUE;
|
|
}
|
|
|
|
if (hKey) {
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
if (setupKey) {
|
|
RegCloseKey (setupKey);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ProcessCompatibilityData(
|
|
HWND hDlg
|
|
)
|
|
{
|
|
DWORD Count;
|
|
|
|
|
|
if( !CompatibilityData.Flink ) {
|
|
InitializeListHead( &CompatibilityData );
|
|
}
|
|
|
|
//
|
|
// On clean install we have to process [ServicesToStopInstallation].
|
|
// This section will contain at least the check for unsupported architectures that has to be
|
|
// executed onb clean install.
|
|
//
|
|
GlobalCompFlags = COMPFLAG_STOPINSTALL;
|
|
//
|
|
// please don't reset this variable; it may be > 0 intentionally!
|
|
//
|
|
// CompatibilityCount = 0;
|
|
//
|
|
// check for "RunOnce" Stuff
|
|
//
|
|
if( (Upgrade) && !(CheckUpgradeOnly) ) {
|
|
if (pCheckForPendingRunOnce()) {
|
|
CompatibilityCount++;
|
|
IncompatibilityStopsInstallation = TRUE;
|
|
}
|
|
}
|
|
|
|
if (ISNT()) {
|
|
|
|
CompatibilityCount += ProcessCompatibilitySection( NtcompatInf, TEXT("ServicesToStopInstallation") );
|
|
if (CompatibilityCount) {
|
|
IncompatibilityStopsInstallation = TRUE;
|
|
}
|
|
|
|
GlobalCompFlags = 0;
|
|
CompatibilityCount += ProcessCompatibilitySection( NtcompatInf, TEXT("ServicesToDisable") );
|
|
|
|
//
|
|
// Now cleanup any turds we left in the registry on the services we checked.
|
|
//
|
|
RemoveCompatibilityServiceEntries( NtcompatInf, TEXT("ServicesToStopInstallation") );
|
|
RemoveCompatibilityServiceEntries( NtcompatInf, TEXT("ServicesToDisable") );
|
|
}
|
|
|
|
if( CompatibilityCount ) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WriteTextmodeReplaceData(
|
|
IN HANDLE hTargetFile
|
|
)
|
|
{
|
|
CHAR Buffer[MAX_PATH*2];
|
|
PLIST_ENTRY Next;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
BOOL Result = FALSE;
|
|
DWORD Bytes;
|
|
|
|
//
|
|
// For textmode "overwriting" files, write them out to the
|
|
// WINNT_OVERWRITE_EXISTING (IncompatibleFilesToOverWrite) section
|
|
// of this compatibility data file.
|
|
//
|
|
// Textmode just needs to know the name of the file.
|
|
//
|
|
SetFilePointer(hTargetFile, 0, 0, FILE_END);
|
|
sprintf(Buffer, "\r\n[%s]\r\n", WINNT_OVERWRITE_EXISTING_A);
|
|
WriteFile(hTargetFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL);
|
|
|
|
//
|
|
// Loop down the list of items
|
|
//
|
|
if ( ( Next = CompatibilityData.Flink ) != NULL )
|
|
{
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData)
|
|
{
|
|
CompData = CONTAINING_RECORD(Next, COMPATIBILITY_DATA, ListEntry);
|
|
Next = CompData->ListEntry.Flink;
|
|
|
|
if (!ProcessLine(CompData->Flags))
|
|
continue;
|
|
|
|
//
|
|
// The set string is:
|
|
//
|
|
// "shortfilename" = "fullpathname","version.string"
|
|
//
|
|
// ExpandEnvironmentStrings to ensure that the full path for any
|
|
// 't' line is expanded properly
|
|
//
|
|
if ((CompData->Type == TEXT('t')) && CompData->FileName)
|
|
{
|
|
static TCHAR tchLocalExpandedPath[MAX_PATH*2];
|
|
PTSTR ptszFileNameBit = NULL;
|
|
DWORD dwResult = 0;
|
|
|
|
dwResult = ExpandEnvironmentStrings(
|
|
CompData->FileName,
|
|
tchLocalExpandedPath,
|
|
MAX_PATH );
|
|
|
|
//
|
|
// Did we run out of characters expanding the path? Wierd...
|
|
//
|
|
if ( dwResult > MAX_PATH*2 )
|
|
goto Exit;
|
|
|
|
//
|
|
// Find the actual file name by looking backwards from the end of
|
|
// the string.
|
|
//
|
|
ptszFileNameBit = _tcsrchr( tchLocalExpandedPath, TEXT('\\') );
|
|
if ( ptszFileNameBit == NULL )
|
|
ptszFileNameBit = _tcsrchr( tchLocalExpandedPath, TEXT('/') );
|
|
|
|
//
|
|
// Form up this buffer containing the details Texmode will want.
|
|
// If there's no filenamebit, use the full path name. Textmode
|
|
// will likely fail to find the file, but Nothing Bad will happen.
|
|
// If the version is missing (strange....) then use a blank string
|
|
// to avoid upsetting textmode.
|
|
//
|
|
wsprintfA(
|
|
Buffer,
|
|
#ifdef UNICODE
|
|
"\"%ls\" = \"%ls\",\"%ls\"\r\n",
|
|
#else
|
|
"\"%s\" = \"%s\",\"%s\"\r\n",
|
|
#endif
|
|
ptszFileNameBit ? ptszFileNameBit + 1 : tchLocalExpandedPath,
|
|
CompData->FileVer ? CompData->FileVer : TEXT(""),
|
|
tchLocalExpandedPath );
|
|
|
|
//
|
|
// Spit the buffer (in ansi chars, no less) into the file.
|
|
//
|
|
if (!WriteFile(hTargetFile, Buffer, strlen(Buffer), &Bytes, NULL ))
|
|
goto Exit;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
Result = TRUE;
|
|
Exit:
|
|
return Result;
|
|
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
|
|
BOOL
|
|
pIsOEMService (
|
|
IN PCTSTR ServiceKeyName,
|
|
OUT PTSTR OemInfPath, OPTIONAL
|
|
IN INT BufferSize OPTIONAL
|
|
);
|
|
//This function is defined in unsupdrv.c
|
|
#endif
|
|
|
|
|
|
BOOL
|
|
WriteCompatibilityData(
|
|
IN LPCTSTR FileName
|
|
)
|
|
{
|
|
TCHAR Text[MAX_PATH*2];
|
|
PLIST_ENTRY Next;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
HANDLE hFile;
|
|
CHAR Buffer[MAX_PATH*2];
|
|
DWORD Bytes;
|
|
PSTRINGLIST listServices = NULL, p;
|
|
PCTSTR serviceName;
|
|
BOOL b = FALSE;
|
|
|
|
if (CompatibilityCount == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
hFile = CreateFile(
|
|
FileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if(hFile == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
SetFilePointer( hFile, 0, 0, FILE_END );
|
|
|
|
sprintf( Buffer, "\r\n[%s]\r\n", WINNT_COMPATIBILITY_A );
|
|
WriteFile( hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL );
|
|
|
|
Next = CompatibilityData.Flink;
|
|
if (Next) {
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
|
|
CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
|
|
Next = CompData->ListEntry.Flink;
|
|
|
|
if( !( ProcessLine( CompData->Flags) ))
|
|
continue;
|
|
|
|
|
|
if (CompData->RegKeyName) {
|
|
if (CompData->RegValDataSize == sizeof(DWORD)) {
|
|
wsprintf( Text, TEXT("HKLM,\"%s\",\"%s\",0x%08x,%d\r\n"),
|
|
CompData->RegKeyName, CompData->RegValName, FLG_ADDREG_TYPE_DWORD, *(LPDWORD)CompData->RegValData );
|
|
if (*(LPDWORD)CompData->RegValData == SERVICE_DISABLED) {
|
|
//
|
|
// also record this as a service to be disabled
|
|
// for additional service-specific processing during textmode setup
|
|
//
|
|
serviceName = _tcsrchr (CompData->RegKeyName, TEXT('\\'));
|
|
if (!serviceName) {
|
|
SetLastError (ERROR_INVALID_DATA);
|
|
__leave;
|
|
}
|
|
if (!InsertList (
|
|
(PGENERIC_LIST*)&listServices,
|
|
(PGENERIC_LIST)CreateStringCell (serviceName + 1)
|
|
)) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
}
|
|
} else {
|
|
wsprintf( Text, TEXT("HKLM,\"%s\",\"%s\",0x%08x,\"%s\"\r\n"),
|
|
CompData->RegKeyName, CompData->RegValName, FLG_ADDREG_TYPE_SZ, (LPTSTR)CompData->RegValData );
|
|
}
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
Text,
|
|
-1,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (!WriteFile( hFile, Buffer, strlen(Buffer), &Bytes, NULL )) {
|
|
__leave;
|
|
}
|
|
#else
|
|
if (!WriteFile( hFile, Text, strlen(Text), &Bytes, NULL )) {
|
|
__leave;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
if (listServices) {
|
|
sprintf (Buffer, "\r\n[%s]\r\n", WINNT_SERVICESTODISABLE_A);
|
|
if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
|
|
__leave;
|
|
}
|
|
for (p = listServices; p; p = p->Next) {
|
|
#ifdef UNICODE
|
|
wsprintfA (Buffer, "\"%ls\"\r\n", p->String);
|
|
#else
|
|
wsprintfA (Buffer, "\"%s\"\r\n", p->String);
|
|
#endif
|
|
if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//////////////////////////////////////////////////
|
|
Next = CompatibilityData.Flink;
|
|
if (Next) {
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
|
|
CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
|
|
Next = CompData->ListEntry.Flink;
|
|
|
|
if( !( ProcessLine( CompData->Flags) ))
|
|
continue;
|
|
|
|
if (CompData->ServiceName
|
|
&& (CompData->Flags & COMPFLAG_DELETE_INF))
|
|
{
|
|
TCHAR oemInfFileName[MAX_PATH];
|
|
|
|
if (pIsOEMService(CompData->ServiceName, oemInfFileName, ARRAYSIZE(oemInfFileName)))
|
|
{
|
|
|
|
//
|
|
// Write the following in the answer file
|
|
//
|
|
// note that 17 is the code for %windir%\INF
|
|
//
|
|
/*
|
|
|
|
[DelInf.serv]
|
|
Delfiles=DelInfFiles.serv
|
|
|
|
[DelInfFiles.serv]
|
|
"oem0.inf"
|
|
|
|
[DestinationDirs]
|
|
DelInfFiles.serv= 17
|
|
|
|
*/
|
|
if(_snprintf(Buffer, ARRAYSIZE(Buffer),
|
|
"\r\n[DelInf.%ls]\r\n"
|
|
"Delfiles=DelInfFiles.%ls\r\n"
|
|
"\r\n[DelInfFiles.%ls]\r\n",
|
|
CompData->ServiceName,
|
|
CompData->ServiceName,
|
|
CompData->ServiceName) < 0)
|
|
{
|
|
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
|
|
MYASSERT(FALSE);
|
|
continue;
|
|
}
|
|
|
|
if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
|
|
__leave;
|
|
}
|
|
|
|
|
|
if(_snprintf(Buffer, ARRAYSIZE(Buffer),
|
|
"\"%ls\"\r\n"
|
|
"\r\n[DestinationDirs]\r\n"
|
|
"DelInfFiles.%ls= 17\r\n",
|
|
oemInfFileName,
|
|
CompData->ServiceName) < 0)
|
|
{
|
|
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
|
|
MYASSERT(FALSE);
|
|
continue;
|
|
}
|
|
|
|
if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////
|
|
#endif
|
|
|
|
if ( !WriteTextmodeReplaceData(hFile) )
|
|
__leave;
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
DWORD rc = GetLastError ();
|
|
CloseHandle( hFile );
|
|
if (listServices) {
|
|
DeleteStringList (listServices);
|
|
}
|
|
SetLastError (rc);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
pIsValidService (
|
|
IN PCTSTR ServiceName
|
|
)
|
|
{
|
|
TCHAR KeyName[MAX_PATH];
|
|
HKEY key;
|
|
DWORD rc;
|
|
BOOL b = FALSE;
|
|
|
|
BuildPath (KeyName, TEXT("SYSTEM\\CurrentControlSet\\Services"), ServiceName);
|
|
//
|
|
// get an open key to the services database
|
|
//
|
|
rc = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
KeyName,
|
|
0,
|
|
KEY_READ,
|
|
&key
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
b = TRUE;
|
|
RegCloseKey (key);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WriteTextmodeClobberData (
|
|
IN LPCTSTR FileName
|
|
)
|
|
{
|
|
HANDLE hFile;
|
|
CHAR Buffer[50];
|
|
DWORD LineCount, Bytes;
|
|
TCHAR keyGuid[200];
|
|
PCTSTR guidClass;
|
|
PSTRINGLIST listServices = NULL, listLines = NULL, e;
|
|
PCTSTR service;
|
|
PTSTR upperFilters = NULL, upperFiltersNew = NULL, lowerFilters = NULL, lowerFiltersNew = NULL, line;
|
|
HKEY key;
|
|
INT i, j;
|
|
PTSTR p, q;
|
|
PSTR ansi = NULL;
|
|
DWORD rc, size, type;
|
|
BOOL modified, found;
|
|
BOOL b = FALSE;
|
|
|
|
#define S_SECTION_CHECKCLASSFILTERS TEXT("CheckClassFilters")
|
|
|
|
MYASSERT (NtcompatInf);
|
|
|
|
LineCount = InfGetSectionLineCount (NtcompatInf, S_SECTION_CHECKCLASSFILTERS);
|
|
if (LineCount == 0 || LineCount == 0xffffffff) {
|
|
return TRUE;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// first check if any data needs to be written
|
|
//
|
|
for (i = 0; i < (INT)LineCount; i++) {
|
|
guidClass = InfGetFieldByIndex (NtcompatInf, S_SECTION_CHECKCLASSFILTERS, i, 0);
|
|
if (guidClass == NULL) {
|
|
MYASSERT (FALSE);
|
|
continue;
|
|
}
|
|
BuildPath (keyGuid, TEXT("SYSTEM\\CurrentControlSet\\Control\\Class"), guidClass);
|
|
rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyGuid, 0, KEY_READ, &key);
|
|
if (rc != ERROR_SUCCESS) {
|
|
continue;
|
|
}
|
|
upperFilters = NULL;
|
|
rc = RegQueryValueEx (key, TEXT("UpperFilters"), NULL, &type, NULL, &size);
|
|
if (rc == ERROR_SUCCESS && type == REG_MULTI_SZ) {
|
|
MYASSERT (size >= 2);
|
|
upperFilters = MALLOC (size);
|
|
upperFiltersNew = MALLOC (size * 2);
|
|
if (!upperFilters || !upperFiltersNew) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
rc = RegQueryValueEx (key, TEXT("UpperFilters"), NULL, NULL, (LPBYTE)upperFilters, &size);
|
|
if (rc != ERROR_SUCCESS) {
|
|
FREE (upperFilters);
|
|
upperFilters = NULL;
|
|
FREE (upperFiltersNew);
|
|
upperFiltersNew = NULL;
|
|
}
|
|
}
|
|
lowerFilters = NULL;
|
|
rc = RegQueryValueEx (key, TEXT("LowerFilters"), NULL, &type, NULL, &size);
|
|
if (rc == ERROR_SUCCESS && type == REG_MULTI_SZ) {
|
|
MYASSERT (size >= 2);
|
|
lowerFilters = MALLOC (size);
|
|
lowerFiltersNew = MALLOC (size * 2);
|
|
if (!lowerFilters || !lowerFiltersNew) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
rc = RegQueryValueEx (key, TEXT("LowerFilters"), NULL, NULL, (LPBYTE)lowerFilters, &size);
|
|
if (rc != ERROR_SUCCESS) {
|
|
FREE (lowerFilters);
|
|
lowerFilters = NULL;
|
|
FREE (lowerFiltersNew);
|
|
lowerFiltersNew = NULL;
|
|
}
|
|
}
|
|
|
|
RegCloseKey (key);
|
|
|
|
if (!(upperFilters || lowerFilters)) {
|
|
continue;
|
|
}
|
|
|
|
j = 1;
|
|
do {
|
|
service = InfGetFieldByIndex (NtcompatInf, S_SECTION_CHECKCLASSFILTERS, i, j++);
|
|
if (service && *service) {
|
|
if (!InsertList (
|
|
(PGENERIC_LIST*)&listServices,
|
|
(PGENERIC_LIST)CreateStringCell (service)
|
|
)) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
}
|
|
} while (service);
|
|
|
|
if (upperFilters) {
|
|
modified = FALSE;
|
|
*upperFiltersNew = 0;
|
|
for (p = upperFilters, q = upperFiltersNew; *p; p = _tcschr (p, 0) + 1) {
|
|
if (listServices) {
|
|
found = FindStringCell (listServices, p, FALSE);
|
|
} else {
|
|
found = !pIsValidService (p);
|
|
}
|
|
if (found) {
|
|
DebugLog (
|
|
Winnt32LogInformation,
|
|
TEXT("NTCOMPAT: Removing \"%1\" from %2 of %3"),
|
|
0,
|
|
p,
|
|
TEXT("UpperFilters"),
|
|
guidClass
|
|
);
|
|
modified = TRUE;
|
|
} else {
|
|
q = q + wsprintf (q, TEXT(",\"%s\""), p);
|
|
}
|
|
}
|
|
if (modified) {
|
|
//
|
|
// tell textmode setup to overwrite this value
|
|
//
|
|
line = MALLOC (
|
|
sizeof (TCHAR) *
|
|
(1 +
|
|
sizeof("HKLM,\"%s\",\"%s\",0x%08x%s\r\n") - 1 +
|
|
lstrlen (keyGuid) +
|
|
sizeof ("UpperFilters") - 1 +
|
|
2 + 8 +
|
|
lstrlen (upperFiltersNew)
|
|
));
|
|
if (!line) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
wsprintf (
|
|
line,
|
|
TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n"),
|
|
keyGuid,
|
|
TEXT("UpperFilters"),
|
|
FLG_ADDREG_TYPE_MULTI_SZ,
|
|
upperFiltersNew
|
|
);
|
|
if (!InsertList (
|
|
(PGENERIC_LIST*)&listLines,
|
|
(PGENERIC_LIST)CreateStringCell (line)
|
|
)) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
FREE (line);
|
|
line = NULL;
|
|
}
|
|
}
|
|
|
|
if (lowerFilters) {
|
|
modified = FALSE;
|
|
*lowerFiltersNew = 0;
|
|
for (p = lowerFilters, q = lowerFiltersNew; *p; p = _tcschr (p, 0) + 1) {
|
|
if (listServices) {
|
|
found = FindStringCell (listServices, p, FALSE);
|
|
} else {
|
|
found = !pIsValidService (p);
|
|
}
|
|
if (found) {
|
|
DebugLog (
|
|
Winnt32LogInformation,
|
|
TEXT("NTCOMPAT: Removing \"%1\" from %2 of %3"),
|
|
0,
|
|
p,
|
|
TEXT("LowerFilters"),
|
|
guidClass
|
|
);
|
|
modified = TRUE;
|
|
} else {
|
|
q = q + wsprintf (q, TEXT(",\"%s\""), p);
|
|
}
|
|
}
|
|
if (modified) {
|
|
//
|
|
// tell textmode setup to overwrite this value
|
|
//
|
|
line = MALLOC (
|
|
sizeof (TCHAR) *
|
|
(1 +
|
|
sizeof("HKLM,\"%s\",\"%s\",0x%08x%s\r\n") - 1 +
|
|
lstrlen (keyGuid) +
|
|
sizeof ("LowerFilters") - 1 +
|
|
2 + 8 +
|
|
lstrlen (lowerFiltersNew)
|
|
));
|
|
if (!line) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
wsprintf (
|
|
line,
|
|
TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n"),
|
|
keyGuid,
|
|
TEXT("LowerFilters"),
|
|
FLG_ADDREG_TYPE_MULTI_SZ,
|
|
lowerFiltersNew
|
|
);
|
|
if (!InsertList (
|
|
(PGENERIC_LIST*)&listLines,
|
|
(PGENERIC_LIST)CreateStringCell (line)
|
|
)) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
FREE (line);
|
|
line = NULL;
|
|
}
|
|
}
|
|
if (listServices) {
|
|
DeleteStringList (listServices);
|
|
listServices = NULL;
|
|
}
|
|
if (upperFilters) {
|
|
FREE (upperFilters);
|
|
upperFilters = NULL;
|
|
}
|
|
if (upperFiltersNew) {
|
|
FREE (upperFiltersNew);
|
|
upperFiltersNew = NULL;
|
|
}
|
|
if (lowerFilters) {
|
|
FREE (lowerFilters);
|
|
lowerFilters = NULL;
|
|
}
|
|
if (lowerFiltersNew) {
|
|
FREE (lowerFiltersNew);
|
|
lowerFiltersNew = NULL;
|
|
}
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
rc = GetLastError ();
|
|
if (listServices) {
|
|
DeleteStringList (listServices);
|
|
}
|
|
if (upperFilters) {
|
|
FREE (upperFilters);
|
|
}
|
|
if (upperFiltersNew) {
|
|
FREE (upperFiltersNew);
|
|
}
|
|
if (lowerFilters) {
|
|
FREE (lowerFilters);
|
|
}
|
|
if (lowerFiltersNew) {
|
|
FREE (lowerFiltersNew);
|
|
}
|
|
if (!b) {
|
|
if (listLines) {
|
|
DeleteStringList (listLines);
|
|
listLines = NULL;
|
|
}
|
|
}
|
|
SetLastError (rc);
|
|
}
|
|
|
|
if (listLines) {
|
|
|
|
b = FALSE;
|
|
|
|
__try {
|
|
|
|
hFile = CreateFile(
|
|
FileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
|
|
SetFilePointer (hFile, 0, 0, FILE_END);
|
|
|
|
sprintf (Buffer, "\r\n[%s]\r\n", WINNT_COMPATIBILITY_A);
|
|
if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
|
|
__leave;
|
|
}
|
|
|
|
for (e = listLines; e; e = e->Next) {
|
|
#ifdef UNICODE
|
|
ansi = MALLOC ((lstrlen (e->String) + 1) * 2);
|
|
if (!ansi) {
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
__leave;
|
|
}
|
|
if (!WideCharToMultiByte (
|
|
CP_ACP,
|
|
0,
|
|
e->String,
|
|
-1,
|
|
ansi,
|
|
lstrlen (e->String) + 1,
|
|
NULL,
|
|
NULL
|
|
)) {
|
|
__leave;
|
|
}
|
|
if (!WriteFile (hFile, (LPBYTE)ansi, strlen(ansi), &Bytes, NULL)) {
|
|
__leave;
|
|
}
|
|
FREE (ansi);
|
|
ansi = NULL;
|
|
#else
|
|
if (!WriteFile (hFile, (LPBYTE)e->String, strlen(e->String), &Bytes, NULL)) {
|
|
__leave;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
DWORD rc = GetLastError ();
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (hFile);
|
|
}
|
|
if (ansi) {
|
|
FREE (ansi);
|
|
}
|
|
DeleteStringList (listLines);
|
|
SetLastError (rc);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
SaveCompatibilityData(
|
|
IN LPCTSTR FileName,
|
|
IN BOOL IncludeHiddenItems
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We call this function when the user has asked us to save the
|
|
contents of the Compatibility page to a file.
|
|
|
|
Arguments:
|
|
|
|
FileName - supplies filename of file to be used for our output.
|
|
IncludeHiddenItems - if set, hidden items are also saved
|
|
|
|
Return Value:
|
|
|
|
Boolean value indicating whether we succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
#define WRITE_TEXT( s ) { strcpy( AnsiMessage, s ); \
|
|
WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL ); }
|
|
|
|
HANDLE hFile;
|
|
CHAR AnsiMessage[5000];
|
|
DWORD Written;
|
|
PLIST_ENTRY Next;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
DWORD i;
|
|
TCHAR FullPath[MAX_PATH+8], *t;
|
|
PVOID textDescription;
|
|
BOOL bUnicode;
|
|
BOOL bEmpty = TRUE;
|
|
|
|
//
|
|
// Open the file. NOTE THAT WE DON'T APPEND.
|
|
//
|
|
hFile = CreateFile( FileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL );
|
|
if(hFile == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Header...
|
|
//
|
|
|
|
WRITE_TEXT( "\r\n********************************************************************\r\n\r\n" );
|
|
|
|
LoadStringA(hInst,IDS_COMPAT_REPORTHEADER,AnsiMessage,(sizeof(AnsiMessage)/sizeof(CHAR)));
|
|
WRITE_TEXT( AnsiMessage );
|
|
|
|
WRITE_TEXT( "\r\n\r\n********************************************************************\r\n\r\n" );
|
|
|
|
//
|
|
// Body...
|
|
//
|
|
Next = CompatibilityData.Flink;
|
|
if (Next) {
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
|
|
CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
|
|
Next = CompData->ListEntry.Flink;
|
|
|
|
|
|
if( CompData->Flags & COMPFLAG_HIDE )
|
|
continue;
|
|
|
|
if( !ProcessLine(CompData->Flags))
|
|
continue;
|
|
|
|
|
|
//
|
|
// Convert the description to ANSI and write it.
|
|
//
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
CompData->Description,
|
|
-1,
|
|
AnsiMessage,
|
|
sizeof(AnsiMessage),
|
|
NULL,
|
|
NULL );
|
|
#else
|
|
lstrcpyn(AnsiMessage,CompData->Description, 5000);
|
|
#endif
|
|
strcat( AnsiMessage, "\r\n" );
|
|
WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
|
|
|
|
//
|
|
// Underline the description.
|
|
//
|
|
Written = strlen( AnsiMessage );
|
|
AnsiMessage[0] = 0;
|
|
for( i = 0; i < (Written-2); i++ ) {
|
|
strcat( AnsiMessage, "=" );
|
|
}
|
|
strcat( AnsiMessage, "\r\n\r\n" );
|
|
WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
|
|
|
|
//
|
|
// Append the text file that this entry points to.
|
|
//
|
|
if (pGetText (CompData->TextName, &textDescription, &bUnicode)) {
|
|
if (bUnicode) {
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
textDescription,
|
|
-1,
|
|
AnsiMessage,
|
|
sizeof(AnsiMessage),
|
|
NULL,
|
|
NULL );
|
|
#else
|
|
lstrcpyn(AnsiMessage, textDescription, 5000);
|
|
#endif
|
|
WriteFile (hFile, AnsiMessage, lstrlenA (AnsiMessage), &Written, NULL );
|
|
|
|
} else {
|
|
WriteFile (hFile, textDescription, lstrlenA (textDescription), &Written, NULL );
|
|
}
|
|
|
|
FREE (textDescription);
|
|
}
|
|
|
|
//
|
|
// Buffer space...
|
|
//
|
|
WRITE_TEXT( "\r\n\r\n\r\n" );
|
|
|
|
bEmpty = FALSE;
|
|
}
|
|
}
|
|
|
|
if (IncludeHiddenItems) {
|
|
//
|
|
// Hidden Items Header...
|
|
//
|
|
|
|
|
|
//
|
|
// Body...
|
|
//
|
|
Next = CompatibilityData.Flink;
|
|
if (Next) {
|
|
BOOL bFirst = TRUE;
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
|
|
CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
|
|
Next = CompData->ListEntry.Flink;
|
|
|
|
if (!(CompData->Flags & COMPFLAG_HIDE ))
|
|
continue;
|
|
|
|
if( !ProcessLine(CompData->Flags))
|
|
continue;
|
|
|
|
if (bFirst) {
|
|
WRITE_TEXT( "\r\n--------------------------------------------------------------------\r\n\r\n" );
|
|
bFirst = FALSE;
|
|
}
|
|
|
|
//
|
|
// Convert the description to ANSI and write it.
|
|
//
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
CompData->Description,
|
|
-1,
|
|
AnsiMessage,
|
|
sizeof(AnsiMessage),
|
|
NULL,
|
|
NULL );
|
|
#else
|
|
lstrcpy(AnsiMessage,CompData->Description);
|
|
#endif
|
|
strcat( AnsiMessage, "\r\n" );
|
|
WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
|
|
|
|
//
|
|
// Underline the description.
|
|
//
|
|
Written = strlen( AnsiMessage );
|
|
AnsiMessage[0] = 0;
|
|
for( i = 0; i < (Written-2); i++ ) {
|
|
strcat( AnsiMessage, "=" );
|
|
}
|
|
strcat( AnsiMessage, "\r\n\r\n" );
|
|
WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
|
|
|
|
//
|
|
// Append the text file that this entry points to.
|
|
//
|
|
if( (CompData->TextName) && *(CompData->TextName) ) {
|
|
if (FindPathToWinnt32File (CompData->TextName, FullPath, MAX_PATH)) {
|
|
ConcatenateFile( hFile, FullPath );
|
|
} else {
|
|
DebugLog (Winnt32LogError,
|
|
TEXT("Compatibility data file \"%1\" not found"),
|
|
0,
|
|
CompData->TextName
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Buffer space...
|
|
//
|
|
WRITE_TEXT( "\r\n\r\n\r\n" );
|
|
|
|
bEmpty = FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (bEmpty) {
|
|
if (LoadStringA (hInst, IDS_COMPAT_NOPROBLEMS, AnsiMessage, (sizeof(AnsiMessage)))) {
|
|
strcat (AnsiMessage, "\r\n");
|
|
WriteFile (hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL);
|
|
}
|
|
}
|
|
|
|
CloseHandle( hFile );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
WriteGUIModeInfOperations(
|
|
IN LPCTSTR FileName
|
|
)
|
|
{
|
|
PLIST_ENTRY Next_Link;
|
|
PCOMPATIBILITY_DATA CompData;
|
|
BOOLEAN FirstTime = TRUE;
|
|
TCHAR Text[MAX_PATH*2], Temp[MAX_PATH];
|
|
CHAR Buffer[MAX_PATH*2];
|
|
DWORD Bytes;
|
|
HANDLE hFile;
|
|
PCTSTR p;
|
|
|
|
|
|
hFile = CreateFile(
|
|
FileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if(hFile == INVALID_HANDLE_VALUE) {
|
|
return;
|
|
}
|
|
|
|
SetFilePointer( hFile, 0, 0, FILE_END );
|
|
|
|
|
|
Next_Link = CompatibilityData.Flink;
|
|
|
|
if( Next_Link ){
|
|
|
|
while ((ULONG_PTR)Next_Link != (ULONG_PTR)&CompatibilityData) {
|
|
|
|
CompData = CONTAINING_RECORD( Next_Link, COMPATIBILITY_DATA, ListEntry );
|
|
Next_Link = CompData->ListEntry.Flink;
|
|
|
|
if( FirstTime ){
|
|
sprintf( Buffer, "[%s]\r\n", WINNT_COMPATIBILITYINFSECTION_A );
|
|
WriteFile( hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL );
|
|
FirstTime = FALSE;
|
|
}
|
|
|
|
if(CompData->InfName && CompData->InfSection && *CompData->InfName && *CompData->InfSection){
|
|
|
|
|
|
//Add the information for GUI setup.
|
|
|
|
#ifdef _X86_
|
|
lstrcpy( Temp, LocalBootDirectory );
|
|
#else
|
|
lstrcpy( Temp, LocalSourceWithPlatform );
|
|
#endif
|
|
p = _tcsrchr (CompData->InfName, TEXT('\\'));
|
|
if (p) {
|
|
p++;
|
|
} else {
|
|
p = CompData->InfName;
|
|
}
|
|
ConcatenatePaths( Temp, p, MAX_PATH );
|
|
|
|
wsprintf( Text, TEXT("%s,%s\r\n"), Temp, CompData->InfSection );
|
|
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
Text,
|
|
-1,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
NULL,
|
|
NULL
|
|
);
|
|
WriteFile( hFile, Buffer, strlen(Buffer), &Bytes, NULL );
|
|
#else
|
|
WriteFile( hFile, Text, strlen(Text), &Bytes, NULL );
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
if (CompData->ServiceName
|
|
&& (CompData->Flags & COMPFLAG_DELETE_INF))
|
|
{
|
|
TCHAR oemInfFileName[MAX_PATH];
|
|
|
|
if (pIsOEMService(CompData->ServiceName, oemInfFileName, ARRAYSIZE(oemInfFileName)))
|
|
{
|
|
if(_snprintf(Buffer, ARRAYSIZE(Buffer),
|
|
"%ls, DelInf.%ls\r\n",
|
|
WINNT_GUI_FILE_W,
|
|
CompData->ServiceName) < 0)
|
|
{
|
|
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
|
|
MYASSERT(FALSE);
|
|
continue;
|
|
}
|
|
|
|
if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
|
|
MYASSERT(FALSE);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
CloseHandle( hFile );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsIE4Installed(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
IsIE3Installed(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
ServerWizPage(
|
|
IN HWND hdlg,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine notifies the user about the existance of the
|
|
ever-so-official-sounding "Directory of Applications for Windows 2000".
|
|
|
|
Note that we'll only run this page on server installs/upgrades.
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
TCHAR FullPath[1024];
|
|
LPWSTR Url;
|
|
DWORD i;
|
|
BOOL b;
|
|
|
|
|
|
switch(msg) {
|
|
|
|
|
|
|
|
|
|
case WM_INITDIALOG:
|
|
//
|
|
// Nothing to do here.
|
|
//
|
|
b = FALSE;
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WMX_ACTIVATEPAGE:
|
|
|
|
if (Winnt32Restarted ()) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// We're going to skip this page if we're installing
|
|
// a PROFESSIONAL product.
|
|
//
|
|
if( !Server ) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Don't do this if we're on OSR2 because it
|
|
// will AV sometimes when we fire IE3 w/o an internet
|
|
// connection.
|
|
//
|
|
if( !ISNT() ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If we don't have IE, skip this page.
|
|
//
|
|
b = (IsIE4Installed() || IsIE3Installed());
|
|
SetForegroundWindow(hdlg);
|
|
if( !b ) {
|
|
return FALSE;
|
|
}
|
|
b = TRUE;
|
|
|
|
//
|
|
// If we're unattended, skip this page.
|
|
//
|
|
if( UnattendedOperation ) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if(wParam) {
|
|
}
|
|
b = TRUE;
|
|
// Stop the bill board and show the wizard again.
|
|
SendMessage(GetParent (hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
if ((LOWORD(wParam) == IDC_DIRECTORY) && (HIWORD(wParam) == BN_CLICKED)) {
|
|
|
|
//
|
|
// The user wants to go look at the directory.
|
|
// Fire IE.
|
|
//
|
|
|
|
//
|
|
// Depending on which flavor we're upgrading to, we need
|
|
// to go to a different page.
|
|
//
|
|
|
|
b = TRUE; // silence PREfix. Not relevant, but presumably,
|
|
// if the directory is being opened, it must exist.
|
|
// So we return TRUE.
|
|
if( Server ) {
|
|
if( !LoadString(hInst,IDS_SRV_APP_DIRECTORY,FullPath,sizeof(FullPath)/sizeof(TCHAR)))
|
|
break;
|
|
} else {
|
|
if( !LoadString(hInst,IDS_PRO_APP_DIRECTORY,FullPath,sizeof(FullPath)/sizeof(TCHAR)))
|
|
break;
|
|
}
|
|
|
|
|
|
i = _tcslen( FullPath );
|
|
Url = (LPWSTR)SysAllocStringLen( NULL, i );
|
|
|
|
if(Url) {
|
|
#ifdef UNICODE
|
|
wcscpy( Url, FullPath );
|
|
#else
|
|
MultiByteToWideChar( CP_ACP, 0, FullPath, -1, Url, i );
|
|
#endif
|
|
|
|
if (!LaunchIE4Instance(Url)) {
|
|
if (!LaunchIE3Instance(Url)) {
|
|
//
|
|
// Sniff... the user doesn't have IE
|
|
// on his machine. Quietly move on.
|
|
//
|
|
}
|
|
}
|
|
|
|
SysFreeString( Url );
|
|
}
|
|
}
|
|
else
|
|
b = FALSE;
|
|
break;
|
|
|
|
case WMX_I_AM_VISIBLE:
|
|
|
|
b = TRUE;
|
|
break;
|
|
|
|
|
|
default:
|
|
b = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
AnyBlockingCompatibilityItems (
|
|
VOID
|
|
)
|
|
{
|
|
PLIST_ENTRY Next = CompatibilityData.Flink;
|
|
|
|
if (Next) {
|
|
while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
|
|
PCOMPATIBILITY_DATA CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
|
|
Next = CompData->ListEntry.Flink;
|
|
if ((!(CompData->Flags & COMPFLAG_HIDE)) && ProcessLine( CompData->Flags)) {
|
|
if( CompData->Flags & COMPFLAG_STOPINSTALL ) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|