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

4226 lines
126 KiB

#include "precomp.h"
#pragma hdrstop
#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('*')
#define S_QFE_TARGET_FILENAME TEXT("qfelist.htm")
#define S_QFE_TEMPLATE_FILE TEXT("compdata\\qfelist.htm")
#ifdef UNICODE
#define S_SP_TEMPLATE \
"<P><B>%S</B></P>\r\n"
#define S_QFE_LINK_TEMPLATE \
"<P>"\
"<A HREF=\"http://support.microsoft.com/support/misc/kblookup.asp?id=%lu\" TARGET=\"_new\">"\
"%S</A>"\
"</P>\r\n"
#else
#define S_SP_TEMPLATE \
"<P><B>%s</B></P>\r\n"
#define S_QFE_LINK_TEMPLATE \
"<P>"\
"<A HREF=\"http://support.microsoft.com/support/misc/kblookup.asp?id=%lu\" TARGET=\"_new\">"\
"%s</A>"\
"</P>\r\n"
#endif
typedef struct {
PVOID Text;
BOOL Unicode;
} COMPAT_TEXT_PARAMS, *PCOMPAT_TEXT_PARAMS;
LIST_ENTRY CompatibilityData;
DWORD CompatibilityCount;
DWORD IncompatibilityStopsInstallation = FALSE;
DWORD GlobalCompFlags;
//
// 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)) {
if(_sntprintf (UrlName, UrlChars, TEXT("mk:@msitstore:%s::/%s"), filePath, Source + 1) < 0){
UrlName[UrlChars - 1] = '\0';
DebugLog(Winnt32LogError,
TEXT("pGetDisplayInfo: UrlName(%s) has been truncated."),
0,
UrlName);
}
} else {
DebugLog (Winnt32LogError,
TEXT("Compatibility data file \"%1\" not found"),
0,
S_APPCOMPAT_DATABASE_FILE
);
b = FALSE;
}
} else {
if (FindPathToWinnt32File (Source, filePath, MAX_PATH)) {
if(_sntprintf (UrlName, UrlChars, TEXT("file://%s"), filePath) < 0){
UrlName[UrlChars - 1] = '\0';
DebugLog(Winnt32LogError,
TEXT("pGetDisplayInfo: UrlName(%s) has been truncated."),
0,
UrlName);
}
} 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;
INT 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);
MYASSERT(size >= 0);
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 = NULL;
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, ARRAYSIZE(Caption))){
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;
MYASSERT(textDescription);
params.Text = textDescription;
params.Unicode = bUnicode;
DialogBoxParam(
hInst,
MAKEINTRESOURCE(IDD_COMPATIBILITY_TEXT),
NULL,
CompatibilityTextDlgProc,
(LPARAM)&params
);
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, ARRAYSIZE(Heading))) {
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( 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 (!ISNT()) {
break;
}
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, ARRAYSIZE(Desc_String))){
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 + ARRAYSIZE(TEXT(".txt"))] = {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 = ARRAYSIZE(Buffer);
if(!LoadString(hInst, IDS_DEFAULT_COMPATIBILITY_REPORT_NAME, Buffer, ARRAYSIZE(Buffer))){
Buffer[0] = '\0';
MYASSERT(FALSE);
}
if(LoadString(hInst, IDS_FILE_MASK_TYPES, File_Type, ARRAYSIZE(File_Type))){
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;
}
else{
File_Type[0] = '\0';
MYASSERT(FALSE);
}
// 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);
if(_sntprintf(FullPath,
ARRAYSIZE(FullPath),
TEXT("%s\\%s"),
Buffer1,
S_DEFAULT_NT_COMPAT_FILENAME) < 0){
FullPath[ARRAYSIZE(FullPath) - 1] = '\0';
DebugLog(Winnt32LogError,
TEXT("CompatibilityWizPage: FullPath(%s) has been truncated."),
0,
FullPath);
}
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] = {'\0'};
int iResult = 1;
//
// 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) ) {
iResult = LoadString(hInst, IDS_COMPAT_CHECKUPGRADE, Text, ARRAYSIZE(Text));
} else if( (WarningsPresent == TRUE) && (ErrorsPresent == TRUE) ) {
iResult = LoadString(hInst, IDS_COMPAT_ERR_WRN, Text, ARRAYSIZE(Text));
} else if( WarningsPresent == TRUE ) {
iResult = LoadString(hInst, IDS_COMPAT_WRN, Text, ARRAYSIZE(Text));
} else if( ErrorsPresent == TRUE ) {
iResult = LoadString(hInst, IDS_COMPAT_ERR, Text, ARRAYSIZE(Text));
}
MYASSERT(iResult);
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;
if (ISNT()) {
//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));
case 502: // version 5.2
return ( !(CompatFlags & COMPFLAG_SKIPNT52CHECK));
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;
}
}
//
// 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] = {'\0'};
CHAR HaveDiskEntryPoint[MAX_PATH] = {'\0'};
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, ARRAYSIZE(Buffer))) {
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
if(lstrlen(CompCheckEntryPointW) < ARRAYSIZE(CompCheckEntryPoint)){
lstrcpy( CompCheckEntryPoint, CompCheckEntryPointW );
}
else{
MYASSERT(FALSE);
}
if (HaveDiskEntryPointW && lstrlen(HaveDiskEntryPointW) < ARRAYSIZE(HaveDiskEntryPoint)) {
lstrcpy( HaveDiskEntryPoint, HaveDiskEntryPointW );
}
else{
MYASSERT(lstrlen(HaveDiskEntryPointW) < ARRAYSIZE(HaveDiskEntryPoint));
}
#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);
}
}
VOID
pSetWarningFlag (
VOID
)
{
LONG Error;
HKEY setupKey;
Error = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"),
0,
KEY_ALL_ACCESS,
&setupKey
);
RegSetValueEx (
setupKey,
S_WINNT32_WARNING,
0,
REG_SZ,
(PBYTE) TEXT(""), // value is all that matters, data is irrelevant
sizeof (TCHAR)
);
RegCloseKey (setupKey);
Error = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
0,
KEY_ALL_ACCESS,
&setupKey
);
RegSetValueEx (
setupKey,
S_WINNT32_WARNING,
0,
REG_SZ,
(PBYTE) TEXT(""),
sizeof (TEXT(""))
);
RegCloseKey (setupKey);
}
BOOL
pRebootAfterWarning (
VOID
)
{
LONG Error;
HKEY hKey;
HKEY setupKey;
DWORD dataSize;
TCHAR textBuffer[512];
BOOL result = FALSE;
//
// Did we provide a warning?
//
Error = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"),
0,
KEY_ALL_ACCESS,
&setupKey
);
if (Error != ERROR_SUCCESS) {
return FALSE;
}
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.
//
Error = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
0,
KEY_ALL_ACCESS,
&hKey
);
if (Error == ERROR_SUCCESS) {
dataSize = sizeof (textBuffer);
Error = RegQueryValueEx (
hKey,
S_WINNT32_WARNING,
NULL,
NULL,
(PBYTE) textBuffer,
&dataSize
);
if (Error != ERROR_SUCCESS) {
//
// yes, they did reboot, our value is gone from RunOnce
//
result = TRUE;
//
// also clean up the other value
//
RegDeleteValue (setupKey, S_WINNT32_WARNING);
}
RegCloseKey (hKey);
}
}
RegCloseKey (setupKey);
return result;
}
BOOL
pCheckForPendingRunOnce (
VOID
)
{
LONG Error;
HKEY hKey = NULL;
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;
}
//
// 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 = ARRAYSIZE(textBuffer);
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 (!foundValues) {
__leave;
}
//
// Otherwise, provide the warning, and write Winnt32Warning to the Setup
// key and RunOnce key.
//
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);
}
result = TRUE;
}
__finally {
if (hKey) {
RegCloseKey (hKey);
}
}
return result;
}
#ifdef UNICODE
BOOL
pCheckForPendingFileRename (
VOID
)
{
LONG Error;
HKEY smKey;
DWORD dataSize;
BOOL result = FALSE;
DWORD type;
Error = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager"),
0,
KEY_ALL_ACCESS,
&smKey
);
if (Error == ERROR_SUCCESS) {
dataSize = 0;
Error = RegQueryValueEx (
smKey,
TEXT("PendingFileRenameOperations"),
NULL,
&type,
NULL,
&dataSize
);
if (Error == ERROR_SUCCESS && type == REG_MULTI_SZ && dataSize > 0) {
result = TRUE;
}
RegCloseKey (smKey);
}
return result;
}
VOID
pCleanFileRenames (
VOID
)
{
LONG Error;
HKEY smKey;
Error = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager"),
0,
KEY_ALL_ACCESS,
&smKey
);
if (Error == ERROR_SUCCESS) {
RegDeleteValue (smKey, TEXT("PendingFileRenameOperations"));
RegCloseKey (smKey);
}
}
#else
//
// not implemented on ANSI platforms
//
#define pCheckForPendingFileRename() (FALSE)
#define pCleanFileRenames()
#endif
BOOL
ProcessCompatibilityData(
HWND hDlg
)
{
DWORD Count;
PCOMPATIBILITY_DATA CompData;
TCHAR textBuffer[512];
BOOL runOnce;
BOOL fileRenames;
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) ) {
//
// on NT upgrades check PendingFileRenameOperations value as well
// [RAID# 713484]
//
runOnce = pCheckForPendingRunOnce();
fileRenames = pCheckForPendingFileRename();
if (runOnce || fileRenames) {
if (pRebootAfterWarning ()) {
//
// they did reboot, but bogus software left traces behind;
// clean it before continuing
//
if (fileRenames) {
pCleanFileRenames();
}
} else {
CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
if (CompData) {
ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
if(!LoadString(hInst, IDS_COMPAT_PENDING_REBOOT, textBuffer, ARRAYSIZE(textBuffer))) {
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 );
CompatibilityCount++;
IncompatibilityStopsInstallation = TRUE;
pSetWarningFlag ();
}
}
}
}
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);
#pragma prefast(suppress:53, the result of _snprintf is tested)
if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_OVERWRITE_EXISTING_A) < 0){
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
MYASSERT(FALSE);
}
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.
//
#pragma prefast(suppress:53, the result of _snprintf is tested)
if(_snprintf(
Buffer,
ARRAYSIZE(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) < 0){
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
MYASSERT(FALSE);
}
//
// 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);
#pragma prefast(suppress:53, the result of _snprintf is tested)
if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_COMPATIBILITY_A) < 0){
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
MYASSERT(FALSE);
}
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)) {
if(_sntprintf(Text,
ARRAYSIZE(Text),
TEXT("HKLM,\"%s\",\"%s\",0x%08x,%d\r\n"),
CompData->RegKeyName, CompData->RegValName,
FLG_ADDREG_TYPE_DWORD,
*(LPDWORD)CompData->RegValData) < 0){
Text[ARRAYSIZE(Text) - 1] = '\0';
MYASSERT(FALSE);
}
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 {
if(_sntprintf(Text,
ARRAYSIZE(Text),
TEXT("HKLM,\"%s\",\"%s\",0x%08x,\"%s\"\r\n"),
CompData->RegKeyName,
CompData->RegValName,
FLG_ADDREG_TYPE_SZ,
(LPTSTR)CompData->RegValData) < 0){
Text[ARRAYSIZE(Text) - 1] = '\0';
MYASSERT(FALSE);
}
}
#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) {
#pragma prefast(suppress:53, the result of _snprintf is tested)
if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_SERVICESTODISABLE_A) < 0){
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
MYASSERT(FALSE);
}
if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
__leave;
}
for (p = listServices; p; p = p->Next) {
#pragma prefast(suppress:53, the result of _snprintf is tested)
if(_snprintf(Buffer,
ARRAYSIZE(Buffer),
#ifdef UNICODE
"\"%ls\"\r\n",
#else
"\"%s\"\r\n",
#endif
p->String) < 0){
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
MYASSERT(FALSE);
}
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;
PSTRINGLIST listLines = NULL;
PSTRINGLIST e;
PCTSTR service;
PTSTR upperFilters = NULL;
PTSTR upperFiltersNew = NULL;
PTSTR lowerFilters = NULL;
PTSTR lowerFiltersNew = NULL;
PTSTR 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(TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n")) - 1 +
lstrlen (keyGuid) +
sizeof (TEXT("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(TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n")) - 1 +
lstrlen (keyGuid) +
sizeof (TEXT("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);
#pragma prefast(suppress:53, the result of _snprintf is tested)
if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_COMPATIBILITY_A)){
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
MYASSERT(FALSE);
}
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) * 2,
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 ) if(!WriteFile(hFile, s, lstrlenA(s), &Written, NULL)){MYASSERT(FALSE);}
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" );
if(!LoadStringA(hInst, IDS_COMPAT_REPORTHEADER, AnsiMessage, ARRAYSIZE(AnsiMessage))){
WRITE_TEXT( "Report Header" );
}
else{
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) - 2 * sizeof(AnsiMessage[0])/*\r\n*/,
NULL,
NULL );
#else
lstrcpyn(AnsiMessage, CompData->Description, ARRAYSIZE(AnsiMessage) - 2/*\r\n*/);
#endif
strcat( AnsiMessage, "\r\n" );
WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
//
// Underline the description.
//
Written = strlen( AnsiMessage );
if(Written >= (ARRAYSIZE(AnsiMessage) - 2/*\r\n*/)){
Written = ARRAYSIZE(AnsiMessage) - 3/*\r\n\0*/;
}
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, ARRAYSIZE(AnsiMessage));
#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) - 2 * sizeof(AnsiMessage[0])/*\r\n*/,
NULL,
NULL );
#else
lstrcpyn(AnsiMessage, CompData->Description, ARRAYSIZE(AnsiMessage) - 2/*\r\n*/);
#endif
strcat( AnsiMessage, "\r\n" );
WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
//
// Underline the description.
//
Written = strlen( AnsiMessage );
if(Written >= (ARRAYSIZE(AnsiMessage) - 2/*\r\n*/)){
Written = ARRAYSIZE(AnsiMessage) - 3/*\r\n\0*/;
}
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, ARRAYSIZE(AnsiMessage) - 2/*\r\n*/)) {
strcat (AnsiMessage, "\r\n");
WriteFile (hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL);
}
else{
MYASSERT(FALSE);
}
}
CloseHandle( hFile );
return TRUE;
}
VOID
WriteGUIModeInfOperations(
IN LPCTSTR FileName
)
{
PLIST_ENTRY Next_Link;
PCOMPATIBILITY_DATA CompData;
BOOLEAN FirstTime = TRUE;
TCHAR Text[MAX_PATH*2];
TCHAR 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 ){
#pragma prefast(suppress:53, the result of _snprintf is tested)
if(_snprintf(Buffer,
ARRAYSIZE(Buffer),
"[%s]\r\n",
WINNT_COMPATIBILITYINFSECTION_A) < 0){
Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
MYASSERT(FALSE);
}
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.
#if defined(_AMD64_) || defined(_X86_)
lstrcpyn(Temp, LocalBootDirectory, ARRAYSIZE(Temp));
#else
lstrcpyn(Temp, LocalSourceWithPlatform, ARRAYSIZE(Temp));
#endif
p = _tcsrchr (CompData->InfName, TEXT('\\'));
if (p) {
p++;
} else {
p = CompData->InfName;
}
if(!ConcatenatePaths(Temp, p, MAX_PATH)){
MYASSERT(FALSE);
}
if(_sntprintf(Text,
ARRAYSIZE(Text),
TEXT("%s,%s\r\n"),
Temp,
CompData->InfSection) < 0){
Text[ARRAYSIZE(Text) - 1] = '\0';
MYASSERT(FALSE);
}
#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
);
#if 0
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, ARRAYSIZE(FullPath))){
MYASSERT(FALSE);
break;
}
} else {
if(!LoadString(hInst, IDS_PRO_APP_DIRECTORY, FullPath, ARRAYSIZE(FullPath))){
MYASSERT(FALSE);
break;
}
}
i = _tcslen( FullPath );
Url = (LPWSTR)MALLOC((i + 1/*\0*/) * sizeof(WCHAR));
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.
//
}
}
FREE(Url);
}
}
else
b = FALSE;
break;
case WMX_I_AM_VISIBLE:
b = TRUE;
break;
default:
b = FALSE;
break;
}
return b;
}
#endif
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;
}
DWORD
pGetQFEsInstalled (
OUT PTSTR* SpQfeList,
OUT PDWORD StringCount,
OUT PDWORD TotalStringsLen
)
/*++
Routine Description:
Gets the list of currently installed ServicePacks/QFEs.
Arguments:
SpQfeList - Receives the multi-sz list
Return Value:
TRUE if detection was successful, FALSE otherwise
--*/
{
DWORD rc;
HKEY key, subKey;
DWORD subkeys, index;
DWORD maxSubKeyLen;
DWORD type, installed, size;
PTSTR list = NULL, crt = NULL;
DWORD count, len, totalLen;
*SpQfeList = NULL;
if (StringCount) {
*StringCount = 0;
}
if (TotalStringsLen) {
*TotalStringsLen = 0;
}
rc = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\HotFix"),
0,
KEY_READ,
&key
);
if (rc != ERROR_SUCCESS) {
return rc == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : rc;
}
__try {
rc = RegQueryInfoKey (
key,
NULL,
NULL,
NULL,
&subkeys,
&maxSubKeyLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
if (rc != ERROR_SUCCESS) {
__leave;
}
if (subkeys > 0) {
maxSubKeyLen++;
list = MALLOC ((subkeys * maxSubKeyLen + 1) * sizeof (TCHAR));
if (!list) {
rc = ERROR_NOT_ENOUGH_MEMORY;
__leave;
}
crt = list;
count = totalLen = 0;
for (index = 0; index < subkeys; index++) {
rc = RegEnumKey (key, index, crt, maxSubKeyLen);
if (rc != ERROR_SUCCESS) {
break;
}
if (_tcsicmp (crt, TEXT("Q147222")) == 0) {
continue;
}
rc = RegOpenKeyEx (
key,
crt,
0,
KEY_READ,
&subKey
);
if (rc != ERROR_SUCCESS) {
__leave;
}
size = sizeof (installed);
rc = RegQueryValueEx (
subKey,
TEXT("Installed"),
NULL,
&type,
(LPBYTE)&installed,
&size
);
RegCloseKey (subKey);
if (rc != ERROR_SUCCESS) {
__leave;
}
if (type != REG_DWORD || !installed) {
continue;
}
len = _tcslen (crt);
count++;
totalLen += len;
crt += len + 1;
*crt = 0;
}
if (rc == ERROR_NO_MORE_ITEMS) {
rc = ERROR_SUCCESS;
}
if (rc == ERROR_SUCCESS) {
if (totalLen == 0) {
FREE (list);
list = NULL;
}
}
}
}
__finally {
if (rc == ERROR_SUCCESS) {
*SpQfeList = list;
if (StringCount) {
*StringCount = count;
}
if (TotalStringsLen) {
*TotalStringsLen = totalLen;
}
} else {
if (list) {
FREE (list);
}
}
RegCloseKey (key);
}
return rc;
}
BOOL
pDumpQfeListToFile (
IN PCTSTR SPVersion, OPTIONAL
IN PCTSTR List, OPTIONAL
IN DWORD Count, OPTIONAL
IN DWORD TotalLen OPTIONAL
)
{
TCHAR qfeTemplatePath[MAX_PATH];
TCHAR qfeListPath[MAX_PATH];
PSTR ansiFile = NULL;
DWORD size;
DWORD spSize, qfeListSize;
PSTR qfeList = NULL;
PSTR dest, end;
PCTSTR src, p;
DWORD len;
DWORD qfeID;
DWORD fileSize;
HANDLE fileHandle;
HANDLE mappingHandle;
PVOID baseAddress;
INT bytes;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD written;
BOOL b = FALSE;
if (!FindPathToWinnt32File (S_QFE_TEMPLATE_FILE, qfeTemplatePath, ARRAYSIZE(qfeTemplatePath))) {
return b;
}
if (MapFileForRead (qfeTemplatePath, &fileSize, &fileHandle, &mappingHandle, &baseAddress) != ERROR_SUCCESS) {
return b;
}
__try {
spSize = SPVersion ? sizeof (S_SP_TEMPLATE) + lstrlen (SPVersion) : 0;
qfeListSize = Count ? Count * (sizeof (S_QFE_LINK_TEMPLATE) + 10) + TotalLen + 1 : 0;
size = fileSize + spSize + qfeListSize;
ansiFile = (PSTR) MALLOC (size);
if (!ansiFile) {
__leave;
}
qfeList = (PSTR) MALLOC (qfeListSize);
if (!qfeList) {
__leave;
}
if (List) {
for (src = List, dest = qfeList; *src; src = _tcschr (src, 0) + 1) {
for (p = src; !_istdigit ((TCHAR)_tcsnextc (p)); p = _tcsinc (p)) {
//
// nothing
//
}
qfeID = _ttol (p);
#pragma prefast(suppress:53, the result of _snprintf is tested)
bytes = _snprintf (dest, qfeListSize - (dest - qfeList), S_QFE_LINK_TEMPLATE, qfeID, src);
if (bytes < 0) {
__leave;
}
dest += bytes;
}
}
dest = ansiFile;
end = ansiFile + size;
if (SPVersion) {
#pragma prefast(suppress:53, the result of _snprintf is tested)
bytes = _snprintf (dest, end - dest, S_SP_TEMPLATE, SPVersion);
if (bytes < 0) {
MYASSERT (FALSE);
__leave;
}
} else {
bytes = 0;
}
dest += bytes;
if (List) {
#pragma prefast(suppress:53, the result of _snprintf is tested)
bytes = _snprintf (dest, end - dest, baseAddress, qfeList);
if (bytes < 0) {
MYASSERT (FALSE);
__leave;
}
} else {
bytes = 0;
}
dest += bytes;
if (!MyGetWindowsDirectory (qfeListPath, ARRAYSIZE(qfeListPath))) {
__leave;
}
ConcatenatePaths (qfeListPath, S_QFE_TARGET_FILENAME, ARRAYSIZE(qfeListPath));
handle = CreateFile (
qfeListPath,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (handle == INVALID_HANDLE_VALUE) {
__leave;
}
if (!WriteFile (
handle,
ansiFile,
(DWORD)(dest - ansiFile),
&written,
NULL) ||
(INT)written != dest - ansiFile
) {
__leave;
}
b = TRUE;
}
__finally {
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle (handle);
}
if (ansiFile) {
FREE (ansiFile);
}
if (qfeList) {
FREE (qfeList);
}
UnmapFile (mappingHandle, baseAddress);
CloseHandle (fileHandle);
}
return b;
}
BOOL
pReplaceEnvVars (
IN PCTSTR CompdataTemplate,
OUT PTSTR TargetPath,
IN INT CchTargetPath
)
{
TCHAR templatePath[MAX_PATH];
PSTR targetBuf = NULL;
PCTSTR filename;
DWORD reqChars;
DWORD fileSize;
HANDLE fileHandle;
HANDLE mappingHandle;
PVOID baseAddress;
INT bytes;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD written;
BOOL b = FALSE;
if (!MyGetWindowsDirectory (TargetPath, CchTargetPath)) {
return b;
}
if (!FindPathToWinnt32File (CompdataTemplate, templatePath, ARRAYSIZE(templatePath))) {
return b;
}
if (MapFileForRead (templatePath, &fileSize, &fileHandle, &mappingHandle, &baseAddress) != ERROR_SUCCESS) {
return b;
}
__try {
reqChars = ExpandEnvironmentStringsA ((PCSTR)baseAddress, NULL, 0);
if (!reqChars) {
__leave;
}
filename = _tcsrchr (CompdataTemplate, TEXT('\\'));
if (!filename) {
filename = CompdataTemplate;
}
ConcatenatePaths (TargetPath, filename, CchTargetPath);
handle = CreateFile (
TargetPath,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (handle == INVALID_HANDLE_VALUE) {
__leave;
}
targetBuf = MALLOC (reqChars * sizeof (CHAR));
if (!targetBuf) {
__leave;
}
reqChars = ExpandEnvironmentStringsA ((PCSTR)baseAddress, targetBuf, reqChars);
if (!reqChars) {
__leave;
}
if (!WriteFile (
handle,
targetBuf,
reqChars * sizeof (CHAR),
&written,
NULL) ||
(INT)written != reqChars * sizeof (CHAR)
) {
__leave;
}
b = TRUE;
}
__finally {
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle (handle);
}
if (targetBuf) {
FREE (targetBuf);
}
UnmapFile (mappingHandle, baseAddress);
CloseHandle (fileHandle);
}
return b;
}
BOOL
QFECheck (
PCOMPAIBILITYCALLBACK CompatibilityCallback,
LPVOID Context
)
/*++
Routine Description:
Checks if any ServicePacks/QFEs are currently installed.
Arguments:
CompatibilityCallback - pointer to call back function
Context - context pointer
Return Value:
Returns always TRUE.
--*/
{
COMPATIBILITY_ENTRY CompEntry;
PTSTR list;
TCHAR text[512];
TCHAR htmTarget[MAX_PATH];
DWORD count = 0, totalLen;
//
// only do this check on identical builds
//
if (OsVersion.dwBuildNumber != VER_PRODUCTBUILD) {
return FALSE;
}
if (pGetQFEsInstalled (&list, &count, &totalLen) != ERROR_SUCCESS) {
return FALSE;
}
if (OsVersion.szCSDVersion[0] || list) {
MYASSERT (!list || *list && count && totalLen);
if (pDumpQfeListToFile (
OsVersion.szCSDVersion[0] ? OsVersion.szCSDVersion : NULL,
list,
count,
totalLen
)) {
if (!pReplaceEnvVars (TEXT("compdata\\svcpack.htm"), htmTarget, ARRAYSIZE(htmTarget))) {
//
// failed, just use the template
//
lstrcpyn (htmTarget, TEXT("compdata\\svcpack.htm"), ARRAYSIZE(htmTarget));
}
if (LoadString (hInst, IDS_DESCRIPTION_SERVICEPACKS, text, ARRAYSIZE(text))) {
ZeroMemory (&CompEntry, sizeof (CompEntry));
CompEntry.Description = text;
CompEntry.HtmlName = htmTarget;
CompEntry.TextName = TEXT("compdata\\svcpack.txt");
if (!CompatibilityCallback (&CompEntry, Context)){
MYASSERT (FALSE);
}
} else {
MYASSERT (FALSE);
}
}
FREE (list);
}
return TRUE;
}