1418 lines
36 KiB
C
1418 lines
36 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
condmsg.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Win95upg.inf has a section named [Conditional Incompatibilities] where the
|
|||
|
lines in the section have the following syntax:
|
|||
|
|
|||
|
%group%, %subgroup%, %object%, %msg% [,<function>[,<argument>]]
|
|||
|
|
|||
|
%group% - A predefined root group number
|
|||
|
|
|||
|
%subgroup% - A localized subgroup displayed in the UI
|
|||
|
|
|||
|
%object% - The file, directory or registry location in which the message
|
|||
|
is associated with
|
|||
|
|
|||
|
%msg% - A localized message
|
|||
|
|
|||
|
<function> - A function that determines if the message should be added to the
|
|||
|
incompatible report
|
|||
|
|
|||
|
<argument> - An optional string parameter that is passed to <function.>
|
|||
|
|
|||
|
The code below implements the functions that are used in Win95upg.inf.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Marc Whitten (marcw) 3-Apr-1997
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
marcw 21-Jan-1999 Stale Beta messages removed.
|
|||
|
marcw 10-Sep-1997 OSR2 beta warning added.
|
|||
|
jimschm 06-Jul-1997 Added "object" to everything
|
|||
|
jimschm 25-Jun-1997 Protocols warning
|
|||
|
jimschm 28-May-1997 Hardware Profile warning
|
|||
|
marcw 25-Apr-1997 <argument> ability passed.
|
|||
|
jimschm 08-Apr-1997 Generalized
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
#include "sysmigp.h"
|
|||
|
#include "hwcomp.h"
|
|||
|
|
|||
|
//
|
|||
|
// Function type declaration
|
|||
|
//
|
|||
|
|
|||
|
typedef BOOL (TEST_FUNCTION_PROTOTYPE)(PCTSTR Object,
|
|||
|
PCTSTR GroupBase,
|
|||
|
PCTSTR Description,
|
|||
|
PCTSTR Argument
|
|||
|
);
|
|||
|
|
|||
|
typedef TEST_FUNCTION_PROTOTYPE * TEST_FUNCTION;
|
|||
|
|
|||
|
//
|
|||
|
// Array of supported functions
|
|||
|
//
|
|||
|
|
|||
|
#define FUNCTION_LIST \
|
|||
|
DECLARATION_MACRO(SysAgentExtension) \
|
|||
|
DECLARATION_MACRO(ArePasswordProvidersPresent) \
|
|||
|
DECLARATION_MACRO(DoesRegKeyExist) \
|
|||
|
DECLARATION_MACRO(DoRegKeyValuesExist) \
|
|||
|
DECLARATION_MACRO(IsWin95Osr2) \
|
|||
|
DECLARATION_MACRO(IsMSNInstalled) \
|
|||
|
DECLARATION_MACRO(IsRasServerEnabled) \
|
|||
|
DECLARATION_MACRO(IsDefValueEqual) \
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Declare the function prototypes
|
|||
|
//
|
|||
|
|
|||
|
#define DECLARATION_MACRO(x) BOOL x (PCTSTR Object, \
|
|||
|
PCTSTR GroupBase, \
|
|||
|
PCTSTR Description, \
|
|||
|
PCTSTR Argument \
|
|||
|
);
|
|||
|
|
|||
|
FUNCTION_LIST
|
|||
|
|
|||
|
#undef DECLARATION_MACRO
|
|||
|
|
|||
|
//
|
|||
|
// Create a lookup array
|
|||
|
//
|
|||
|
|
|||
|
typedef struct {
|
|||
|
PCTSTR Name;
|
|||
|
TEST_FUNCTION Proc;
|
|||
|
} FUNCTION_LIST_ELEMENT,*PFUNCTION_LIST_ELEMENT;
|
|||
|
|
|||
|
#define DECLARATION_MACRO(x) {#x, x},
|
|||
|
|
|||
|
FUNCTION_LIST_ELEMENT g_TestFunctionList[] = {
|
|||
|
FUNCTION_LIST /*,*/
|
|||
|
{NULL, NULL}
|
|||
|
};
|
|||
|
|
|||
|
#undef DECLARATION_MACRO
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Function to locate Proc given a string
|
|||
|
//
|
|||
|
|
|||
|
TEST_FUNCTION
|
|||
|
pFindTestFunction (
|
|||
|
IN PCTSTR FunctionStr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
pFindTestFunction searches the test function table declared above for
|
|||
|
a specified function name and returns a pointer to the actual function
|
|||
|
or NULL if the function does not exist.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FunctionStr - Specifies the name of function to find.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the corresponding code, or NULL if the function does not exist.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
INT Index;
|
|||
|
|
|||
|
for (Index = 0 ; g_TestFunctionList[Index].Name ; Index++) {
|
|||
|
|
|||
|
if (StringIMatch (g_TestFunctionList[Index].Name, FunctionStr)) {
|
|||
|
return g_TestFunctionList[Index].Proc;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DEBUGMSG ((DBG_ERROR,"SysMig: %s is not a valid test function.", FunctionStr));
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PTSTR
|
|||
|
pGetFieldUsingPool (
|
|||
|
IN OUT POOLHANDLE Pool,
|
|||
|
IN INFCONTEXT *pic,
|
|||
|
IN INT Field
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function retrieves a string field using the Setup APIs but uses
|
|||
|
PoolMem for allocation.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pool - Specifies a handle to a valid pool (from PoolMemInitPool). Memory
|
|||
|
is allocated from this pool.
|
|||
|
|
|||
|
pic - Specifies the INF section and line being queried.
|
|||
|
|
|||
|
Field - Specifies the field to retrieve.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the field text, allocated in Pool, or NULL if the field was
|
|||
|
not found or an error is encountered.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD SizeNeeded;
|
|||
|
PTSTR String;
|
|||
|
|
|||
|
if (!SetupGetStringField (pic, Field, NULL, 0, &SizeNeeded)) {
|
|||
|
DEBUGMSG ((DBG_ERROR, "SysMig: SetupGetStringField failed for field %u.", Field));
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
String = PoolMemCreateString (Pool, SizeNeeded);
|
|||
|
|
|||
|
if (!SetupGetStringField (pic, Field, String, SizeNeeded, NULL)) {
|
|||
|
DEBUGMSG ((DBG_ERROR,"SysMig: SetupGetStringField failed for field %u.", Field));
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
return String;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PCTSTR
|
|||
|
pTranslateGroupString (
|
|||
|
IN POOLHANDLE AllocPool,
|
|||
|
IN UINT GroupId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
pTranslateGroupString converts a standard group number (1-based) into a
|
|||
|
message ID, then loads the string resource. The group string is then
|
|||
|
copied into the specified pool.
|
|||
|
|
|||
|
In win95upg.txt, the list is defined as:
|
|||
|
|
|||
|
1 - Hardware That Does Not Support Windows NT 5.0
|
|||
|
2 - General Information
|
|||
|
3 - Settings That Will Not Be Upgraded
|
|||
|
4 - Software That Does Not Support Windows NT 5.0
|
|||
|
5 - Software That Will Require Reinstallation
|
|||
|
6 - Software with Minor Incompatibilities
|
|||
|
7 - Software to Be Uninstalled by Setup
|
|||
|
8 - Upgrade Pack Information
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AllocPool - Specifies the pool to allocate the return string from
|
|||
|
GroupId - Specifies a one-based ID that identifies the group. The
|
|||
|
definition of the ID is hard-coded here.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the string, or NULL if an invalid group was specified.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCTSTR ResStr;
|
|||
|
PCTSTR ResSubStr;
|
|||
|
PTSTR ReturnStr = NULL;
|
|||
|
UINT SubGroupId = 0;
|
|||
|
|
|||
|
switch (GroupId) {
|
|||
|
case 0:
|
|||
|
GroupId = MSG_BLOCKING_ITEMS_ROOT;
|
|||
|
break;
|
|||
|
|
|||
|
case 1:
|
|||
|
GroupId = MSG_INCOMPATIBLE_HARDWARE_ROOT;
|
|||
|
break;
|
|||
|
|
|||
|
case 2:
|
|||
|
GroupId = MSG_INSTALL_NOTES_ROOT;
|
|||
|
break;
|
|||
|
|
|||
|
case 3:
|
|||
|
GroupId = MSG_LOSTSETTINGS_ROOT;
|
|||
|
break;
|
|||
|
|
|||
|
case 4:
|
|||
|
GroupId = MSG_INCOMPATIBLE_ROOT;
|
|||
|
SubGroupId = MSG_INCOMPATIBLE_DETAIL_SUBGROUP;
|
|||
|
break;
|
|||
|
|
|||
|
case 5:
|
|||
|
GroupId = MSG_REINSTALL_ROOT;
|
|||
|
SubGroupId = MSG_REINSTALL_DETAIL_SUBGROUP;
|
|||
|
break;
|
|||
|
|
|||
|
case 6:
|
|||
|
GroupId = MSG_MINOR_PROBLEM_ROOT;
|
|||
|
break;
|
|||
|
|
|||
|
case 7:
|
|||
|
GroupId = MSG_INCOMPATIBLE_ROOT;
|
|||
|
SubGroupId = MSG_AUTO_UNINSTALL_SUBGROUP;
|
|||
|
break;
|
|||
|
|
|||
|
case 8:
|
|||
|
GroupId = MSG_MIGDLL_ROOT;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
ResStr = GetStringResource (GroupId);
|
|||
|
|
|||
|
if (ResStr) {
|
|||
|
|
|||
|
if (SubGroupId) {
|
|||
|
|
|||
|
ResSubStr = GetStringResource (SubGroupId);
|
|||
|
|
|||
|
if (ResSubStr) {
|
|||
|
|
|||
|
//
|
|||
|
// We count the nul twice, assuming the nul is the same
|
|||
|
// size as a backslash.
|
|||
|
//
|
|||
|
|
|||
|
ReturnStr = PoolMemGetAlignedMemory (
|
|||
|
AllocPool,
|
|||
|
SizeOfString (ResStr) + SizeOfString (ResSubStr)
|
|||
|
);
|
|||
|
|
|||
|
wsprintf (ReturnStr, TEXT("%s\\%s"), ResStr, ResSubStr);
|
|||
|
|
|||
|
FreeStringResource (ResSubStr);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ReturnStr = PoolMemDuplicateString (AllocPool, ResStr);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
FreeStringResource (ResStr);
|
|||
|
}
|
|||
|
|
|||
|
return ReturnStr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
pConditionalIncompatibilities (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Processes the Conditional Incompatibilities section of WIN95UPG.INF, and does
|
|||
|
other conditional incompatibility processing. Incompatibilities are added
|
|||
|
via the API in w95upg\ui.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
INFCONTEXT context;
|
|||
|
POOLHANDLE aPool;
|
|||
|
PTSTR descriptionString;
|
|||
|
PTSTR functionString;
|
|||
|
PTSTR argumentString;
|
|||
|
TCHAR buffer[32];
|
|||
|
static INT msgId = 0;
|
|||
|
PCTSTR objectString;
|
|||
|
PTSTR completeString;
|
|||
|
TEST_FUNCTION Proc;
|
|||
|
PCTSTR SubGroupString;
|
|||
|
PCTSTR GroupString;
|
|||
|
UINT GroupId;
|
|||
|
BOOL fr;
|
|||
|
BOOL negate;
|
|||
|
|
|||
|
aPool = PoolMemInitNamedPool ("Conditional Incompatibilities");
|
|||
|
|
|||
|
if (aPool) {
|
|||
|
|
|||
|
if (SetupFindFirstLine (
|
|||
|
g_Win95UpgInf,
|
|||
|
S_CONDITIONAL_INCOMPATIBILITIES,
|
|||
|
NULL,
|
|||
|
&context
|
|||
|
)
|
|||
|
) {
|
|||
|
|
|||
|
//
|
|||
|
// Load in the standard group name
|
|||
|
//
|
|||
|
|
|||
|
do {
|
|||
|
//
|
|||
|
// Get the group number
|
|||
|
//
|
|||
|
|
|||
|
GroupString = pGetFieldUsingPool (aPool, &context, 1);
|
|||
|
if (!GroupString) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
GroupId = _tcstoul (GroupString, NULL, 10);
|
|||
|
GroupString = pTranslateGroupString (aPool, GroupId);
|
|||
|
|
|||
|
if (!GroupString) {
|
|||
|
DEBUGMSG ((DBG_WHOOPS, "Invalid group ID: %u", GroupId));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the subgroup string
|
|||
|
//
|
|||
|
|
|||
|
SubGroupString = pGetFieldUsingPool (aPool, &context, 2);
|
|||
|
if (!SubGroupString) {
|
|||
|
DEBUGMSG ((DBG_WHOOPS, "Field 2 required in conditional message lines"));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (*SubGroupString) {
|
|||
|
completeString = (PTSTR) PoolMemGetMemory (
|
|||
|
aPool,
|
|||
|
SizeOfString (GroupString) +
|
|||
|
SizeOfString (SubGroupString) +
|
|||
|
2 * sizeof (TCHAR)
|
|||
|
);
|
|||
|
|
|||
|
StringCopy (completeString, GroupString);
|
|||
|
StringCopy (AppendWack (completeString), SubGroupString);
|
|||
|
} else {
|
|||
|
completeString = (PTSTR) GroupString;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the object string
|
|||
|
//
|
|||
|
|
|||
|
objectString = pGetFieldUsingPool (aPool, &context, 3);
|
|||
|
if (!objectString) {
|
|||
|
DEBUGMSG ((DBG_WHOOPS, "Field 3 required in conditional message lines"));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the description
|
|||
|
//
|
|||
|
|
|||
|
descriptionString = pGetFieldUsingPool (aPool, &context, 4);
|
|||
|
if (!descriptionString) {
|
|||
|
DEBUGMSG ((DBG_WHOOPS, "Field 4 required in conditional message lines"));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the field count is greater than two, there is a
|
|||
|
// function string..
|
|||
|
//
|
|||
|
|
|||
|
if (SetupGetFieldCount (&context) > 4) {
|
|||
|
|
|||
|
argumentString = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Read in the functionString..
|
|||
|
//
|
|||
|
|
|||
|
functionString = pGetFieldUsingPool (aPool, &context, 5);
|
|||
|
if (!functionString) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
negate = *functionString == TEXT('!');
|
|||
|
if (negate) {
|
|||
|
functionString++;
|
|||
|
}
|
|||
|
|
|||
|
if (SetupGetFieldCount(&context) > 5) {
|
|||
|
|
|||
|
//
|
|||
|
// Read in the argument string.
|
|||
|
//
|
|||
|
argumentString = pGetFieldUsingPool(aPool,&context, 6);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the function to call..
|
|||
|
//
|
|||
|
Proc = pFindTestFunction (functionString);
|
|||
|
if (!Proc) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
fr = Proc (objectString, completeString, descriptionString,argumentString);
|
|||
|
if (!negate && !fr || negate && fr) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!objectString[0]) {
|
|||
|
DEBUGMSG ((DBG_WARNING, "Manufacturing an object for %s message", completeString));
|
|||
|
objectString = buffer;
|
|||
|
msgId++;
|
|||
|
wsprintf (buffer, "msg%u", msgId);
|
|||
|
}
|
|||
|
|
|||
|
MsgMgr_ObjectMsg_Add (objectString, completeString, descriptionString);
|
|||
|
|
|||
|
} while (SetupFindNextLine (&context,&context));
|
|||
|
}
|
|||
|
else {
|
|||
|
DEBUGMSG ((DBG_VERBOSE,"SysMig: %s not found in win95upg.inf.", S_CONDITIONAL_INCOMPATIBILITIES));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PoolMemDestroyPool(aPool);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ConditionalIncompatibilities (
|
|||
|
IN DWORD Request
|
|||
|
)
|
|||
|
{
|
|||
|
switch (Request) {
|
|||
|
case REQUEST_QUERYTICKS:
|
|||
|
return TICKS_CONDITIONAL_INCOMPATIBILITIES;
|
|||
|
case REQUEST_RUN:
|
|||
|
pConditionalIncompatibilities ();
|
|||
|
return ERROR_SUCCESS;
|
|||
|
default:
|
|||
|
DEBUGMSG ((DBG_ERROR, "Bad parameter in ConditionalIncompatibilities"));
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
pIsDefaultSystemAgent (
|
|||
|
PCTSTR SageSubKey
|
|||
|
)
|
|||
|
{
|
|||
|
INFCONTEXT context;
|
|||
|
|
|||
|
if (SetupFindFirstLine (
|
|||
|
g_Win95UpgInf,
|
|||
|
S_SAGE_EXCLUSIONS,
|
|||
|
SageSubKey,
|
|||
|
&context
|
|||
|
)) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SysAgentExtension (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Produces conditional incompatibilities based on the presense of the
|
|||
|
system agent extension, which is part of the Win95 plus pack but
|
|||
|
not supported by NT.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Object - Unused
|
|||
|
|
|||
|
GroupBase - A WIN95UPG.INF-specified group name that is used
|
|||
|
as the base of the message. The actual group name
|
|||
|
stored in the registry is appended for the UI.
|
|||
|
|
|||
|
Description - A WIN95UPG.INF-specified description
|
|||
|
|
|||
|
Argument - Unused
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE, because we add the incompatibility message ourself.
|
|||
|
|
|||
|
Comments:
|
|||
|
|
|||
|
SAGE-aware programs declare themselves as such by creating a key in
|
|||
|
HKLM\Software\Microsoft\Plus!\System Agent\SAGE. The name of the key
|
|||
|
can be anything the program wants, but it should contain the following
|
|||
|
values:
|
|||
|
|
|||
|
Program= Name of the program's .EXE file. This must be the same
|
|||
|
.EXE name under which the program's PerApp path is
|
|||
|
registered. You may append a command line parameter
|
|||
|
indicating unattended operation (see Settings=,
|
|||
|
below).
|
|||
|
|
|||
|
Friendly Name= Display name that System Agent will use in populating
|
|||
|
the drop-down list in its "Schedule a program" dialog
|
|||
|
box.
|
|||
|
Settings= 1-bit binary field indicating whether program has a
|
|||
|
Settings dialog box. If "Settings = "Settings = 0",
|
|||
|
but the application supports an interactive mode, then
|
|||
|
the "Program=" value should contain a command-line
|
|||
|
parameter that tells your program it's being run by
|
|||
|
SAGE, so that it knows to run in an unattended
|
|||
|
fashion, for example, "DRVSPACE.EXE /noprompt" or
|
|||
|
"MyApp.EXE /SAGERUN".
|
|||
|
Result Codes Optional key containing a set of value pairs mapping
|
|||
|
an exit code to a string describing the meaning of
|
|||
|
that exit code. For example, for SCANDSKW, the
|
|||
|
Result Codes key may contain a value such as:
|
|||
|
0="ScanDisk completed successfully; no errors were
|
|||
|
found." This is to allow SAGE to keep a
|
|||
|
human-comprehensible log of the results of the
|
|||
|
programs it runs. In addition to the value pairs,
|
|||
|
this key should also contain a String value named
|
|||
|
"Success", which indicates the highest value for an
|
|||
|
exit code that designates that the program completed
|
|||
|
successfully. The value names should be string
|
|||
|
values, specified in decimal; the allowable range is
|
|||
|
0<EFBFBD>32767.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
REGKEY_ENUM e;
|
|||
|
PCTSTR Data;
|
|||
|
PCTSTR Module;
|
|||
|
TCHAR FullKey[MAX_REGISTRY_KEY];
|
|||
|
PCTSTR Group;
|
|||
|
PCTSTR FullPathKeyStr;
|
|||
|
PCTSTR FullPath;
|
|||
|
|
|||
|
HKEY ExtensionKey;
|
|||
|
HKEY AppPathsKey;
|
|||
|
|
|||
|
//
|
|||
|
// Scan HKLM\Software\Microsoft\Plus!\System Agent\SAGE for
|
|||
|
// subkeys, then throw messages out for each friendly name.
|
|||
|
//
|
|||
|
|
|||
|
if (EnumFirstRegKeyStr (&e, S_SAGE)) {
|
|||
|
do {
|
|||
|
ExtensionKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
|
|||
|
if (ExtensionKey) {
|
|||
|
Data = GetRegValueData (ExtensionKey, S_SAGE_FRIENDLY_NAME);
|
|||
|
if (Data && *Data) {
|
|||
|
// Create full object string
|
|||
|
wsprintf (FullKey, TEXT("%s\\%s"), S_SAGE, e.SubKeyName);
|
|||
|
|
|||
|
// Test win95upg.inf to see if this is a standard agent
|
|||
|
if (!pIsDefaultSystemAgent (e.SubKeyName)) {
|
|||
|
|
|||
|
// Generate group string
|
|||
|
Group = JoinPaths (GroupBase, Data);
|
|||
|
|
|||
|
// Get the full path for this EXE
|
|||
|
|
|||
|
FullPath = NULL;
|
|||
|
Module = GetRegValueData (ExtensionKey, S_SAGE_PROGRAM);
|
|||
|
|
|||
|
if (Module && *Module) {
|
|||
|
|
|||
|
FullPathKeyStr = JoinPaths (S_SKEY_APP_PATHS, Module);
|
|||
|
AppPathsKey = OpenRegKeyStr (FullPathKeyStr);
|
|||
|
|
|||
|
if (AppPathsKey) {
|
|||
|
FullPath = GetRegValueData (AppPathsKey, S_EMPTY);
|
|||
|
if (!(*FullPath)) {
|
|||
|
MemFree (g_hHeap, 0, FullPath);
|
|||
|
FullPath = NULL;
|
|||
|
}
|
|||
|
CloseRegKey (AppPathsKey);
|
|||
|
}
|
|||
|
|
|||
|
FreePathString (FullPathKeyStr);
|
|||
|
MemFree (g_hHeap, 0, Module);
|
|||
|
}
|
|||
|
|
|||
|
// Add message
|
|||
|
if ((!FullPath) || (!IsFileMarkedForAnnounce (FullPath))) {
|
|||
|
MsgMgr_ObjectMsg_Add (FullPath?FullPath:FullKey, Group, Description);
|
|||
|
}
|
|||
|
|
|||
|
// Cleanup
|
|||
|
FreePathString (Group);
|
|||
|
|
|||
|
if (FullPath) {
|
|||
|
MemFree (g_hHeap, 0 , FullPath);
|
|||
|
FullPath = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MemFree (g_hHeap, 0, Data);
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (ExtensionKey);
|
|||
|
}
|
|||
|
} while (EnumNextRegKey (&e));
|
|||
|
}
|
|||
|
|
|||
|
return FALSE; // pretend like it's not installed
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DoesRegKeyExist (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns TRUE if the registry key specified in Argument exists,
|
|||
|
forcing an incompatibility message to be generated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Object - Specifies the registry key to examine
|
|||
|
|
|||
|
GroupBase - A WIN95UPG.INF-specified group name
|
|||
|
|
|||
|
Description - A WIN95UPG.INF-specified description
|
|||
|
|
|||
|
Argument - Unused
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the registry key exists, or FALSE if it is not. TRUE
|
|||
|
forces the message to be added to the report.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL rKeyExists = FALSE;
|
|||
|
HKEY key = NULL;
|
|||
|
|
|||
|
if (Object) {
|
|||
|
key = OpenRegKeyStr (Object);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (key) {
|
|||
|
rKeyExists = TRUE;
|
|||
|
CloseRegKey (key);
|
|||
|
}
|
|||
|
|
|||
|
return rKeyExists;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DoRegKeyValuesExist (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns TRUE if the registry key specified in Argument exists,
|
|||
|
and has at least one named value, forcing an incompatibility
|
|||
|
message to be generated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Object - A WIN95UPG.INF-specified registry key
|
|||
|
|
|||
|
GroupBase - A WIN95UPG.INF-specified group name
|
|||
|
|
|||
|
Description - A WIN95UPG.INF-specified description
|
|||
|
|
|||
|
Argument - Unused
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the registry key exists, or FALSE if it is not. TRUE
|
|||
|
forces the message to be added to the report.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL ValuesExists = FALSE;
|
|||
|
HKEY key = NULL;
|
|||
|
REGVALUE_ENUM e;
|
|||
|
|
|||
|
if (Argument) {
|
|||
|
key = OpenRegKeyStr (Argument);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (key) {
|
|||
|
if (EnumFirstRegValue (&e, key)) {
|
|||
|
do {
|
|||
|
if (e.ValueName[0]) {
|
|||
|
ValuesExists = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
} while (EnumNextRegValue (&e));
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (key);
|
|||
|
}
|
|||
|
|
|||
|
return ValuesExists;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
IsWin95Osr2 (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
return ISWIN95_OSR2();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
IsMSNInstalled (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
{
|
|||
|
HKEY key = NULL;
|
|||
|
PCTSTR Data = NULL;
|
|||
|
BOOL installed = FALSE;
|
|||
|
|
|||
|
if (Object) {
|
|||
|
key = OpenRegKeyStr (Object);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (key) {
|
|||
|
|
|||
|
Data = (PCTSTR) GetRegKeyData (key, S_EMPTY);
|
|||
|
|
|||
|
if (Data) {
|
|||
|
if (DoesFileExist (Data)) {
|
|||
|
installed = TRUE;
|
|||
|
}
|
|||
|
MemFree (g_hHeap, 0, Data);
|
|||
|
}
|
|||
|
CloseRegKey (key);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Special cases
|
|||
|
//
|
|||
|
|
|||
|
if (installed) {
|
|||
|
//
|
|||
|
// Win98 -- make sure setup GUID was deleted
|
|||
|
//
|
|||
|
|
|||
|
key = OpenRegKeyStr (TEXT("HKLM\\Software\\Classes\\CLSID\\{4b876a40-11d1-811e-00c04fb98eec}"));
|
|||
|
|
|||
|
if (key) {
|
|||
|
installed = FALSE;
|
|||
|
CloseRegKey (key);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (installed) {
|
|||
|
//
|
|||
|
// Win95 -- make sure SignUpDone flag is written
|
|||
|
//
|
|||
|
|
|||
|
key = OpenRegKeyStr (TEXT("HKLM\\Software\\Microsoft\\MOS\\SoftwareInstalled"));
|
|||
|
|
|||
|
if (key) {
|
|||
|
CloseRegKey (key);
|
|||
|
} else {
|
|||
|
installed = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return installed;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
IsRasServerEnabled (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
{
|
|||
|
BOOL rAddMessage = FALSE;
|
|||
|
HKEY key;
|
|||
|
PBYTE data;
|
|||
|
|
|||
|
if (!Object) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
key = OpenRegKeyStr (Object);
|
|||
|
|
|||
|
if (key) {
|
|||
|
|
|||
|
data = GetRegValueData (key, TEXT("Enabled"));
|
|||
|
|
|||
|
if (data) {
|
|||
|
|
|||
|
if ((*(PDWORD)data) == 1) {
|
|||
|
rAddMessage = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
MemFree (g_hHeap, 0, data);
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (key);
|
|||
|
}
|
|||
|
|
|||
|
return rAddMessage;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
ArePasswordProvidersPresent (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds incompatibility messages for all password providers, excluding
|
|||
|
password providers of known components such as the Microsoft
|
|||
|
Networking Client or the Microsoft Client for NetWare.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Object - Unused
|
|||
|
|
|||
|
GroupBase - A WIN95UPG.INF-specified group name
|
|||
|
|
|||
|
Description - A WIN95UPG.INF-specified description
|
|||
|
|
|||
|
Argument - Unused
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Always FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
REGKEY_ENUM e;
|
|||
|
PCTSTR data;
|
|||
|
HKEY key;
|
|||
|
INFCONTEXT ic;
|
|||
|
TCHAR FullKey[MAX_REGISTRY_KEY];
|
|||
|
PCTSTR FullGroup;
|
|||
|
PCTSTR IncompatibleSoftware;
|
|||
|
|
|||
|
IncompatibleSoftware = GetStringResource (MSG_INCOMPATIBLE_ROOT);
|
|||
|
if (!IncompatibleSoftware) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (EnumFirstRegKeyStr (&e, S_PASSWORDPROVIDER)) {
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// See if this is a known password provider.
|
|||
|
//
|
|||
|
|
|||
|
if (SetupFindFirstLine (
|
|||
|
g_Win95UpgInf,
|
|||
|
S_SUPPORTED_PASSWORD_PROVIDERS,
|
|||
|
e.SubKeyName,
|
|||
|
&ic
|
|||
|
)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is an unsupported password provider key. Add a message.
|
|||
|
//
|
|||
|
key = OpenRegKey (e.KeyHandle, e.SubKeyName);
|
|||
|
if (key) {
|
|||
|
data = GetRegValueData (key, S_PASSWORDPROVIDER_DESCRIPTION);
|
|||
|
if (data) {
|
|||
|
wsprintf (FullKey, TEXT("%s\\%s"), S_PASSWORDPROVIDER, e.SubKeyName);
|
|||
|
FullGroup = JoinPaths (IncompatibleSoftware, data);
|
|||
|
|
|||
|
MsgMgr_ObjectMsg_Add(
|
|||
|
FullKey, // Object name
|
|||
|
FullGroup, // Message title
|
|||
|
Description // Message text
|
|||
|
);
|
|||
|
|
|||
|
FreePathString (FullGroup);
|
|||
|
|
|||
|
MemFree (g_hHeap, 0, data);
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (key);
|
|||
|
}
|
|||
|
} while (EnumNextRegKey (&e));
|
|||
|
}
|
|||
|
|
|||
|
FreeStringResource (IncompatibleSoftware);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Since we build the message ourselves, just return FALSE. This will
|
|||
|
// keep the ConditionalMessage function from adding this twice.
|
|||
|
//
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
IsDefValueEqual (
|
|||
|
IN PCTSTR Object,
|
|||
|
IN PCTSTR GroupBase,
|
|||
|
IN PCTSTR Description,
|
|||
|
IN PCTSTR Argument
|
|||
|
)
|
|||
|
{
|
|||
|
HKEY key = NULL;
|
|||
|
PCTSTR Data = NULL;
|
|||
|
BOOL equal = FALSE;
|
|||
|
|
|||
|
if (Object) {
|
|||
|
key = OpenRegKeyStr (Object);
|
|||
|
}
|
|||
|
|
|||
|
if (key) {
|
|||
|
|
|||
|
Data = (PCTSTR) GetRegKeyData (key, S_EMPTY);
|
|||
|
|
|||
|
if (Data) {
|
|||
|
if (StringIMatch (Data, Argument)) {
|
|||
|
equal = TRUE;
|
|||
|
}
|
|||
|
MemFree (g_hHeap, 0, Data);
|
|||
|
}
|
|||
|
CloseRegKey (key);
|
|||
|
}
|
|||
|
|
|||
|
return equal;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
pHardwareProfileWarning (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Produces incompatibility messages for all hardware profiles that
|
|||
|
have different hardware configurations. The upgrade cannot maintain
|
|||
|
the list of disabled hardware in a hardware profile, so a warning
|
|||
|
is generated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
REGKEY_ENUM e;
|
|||
|
REGKEY_ENUM e2;
|
|||
|
HKEY ProfileKey;
|
|||
|
HKEY EnumKey;
|
|||
|
HKEY ConfigDbKey;
|
|||
|
DWORD Config;
|
|||
|
TCHAR FriendlyName[MAX_PATH];
|
|||
|
PCTSTR MsgGroup;
|
|||
|
PCTSTR RootGroup;
|
|||
|
PCTSTR HwProfiles;
|
|||
|
PCTSTR Data;
|
|||
|
TCHAR FullKey[MAX_REGISTRY_KEY];
|
|||
|
UINT Profiles;
|
|||
|
|
|||
|
//
|
|||
|
// How many hardware profiles? If just one, don't give a warning.
|
|||
|
//
|
|||
|
|
|||
|
Profiles = 0;
|
|||
|
if (EnumFirstRegKeyStr (&e, S_CONFIG_KEY)) {
|
|||
|
do {
|
|||
|
Profiles++;
|
|||
|
} while (EnumNextRegKey (&e));
|
|||
|
}
|
|||
|
|
|||
|
if (Profiles < 2) {
|
|||
|
DEBUGMSG ((DBG_VERBOSE, "Hardware profiles: %u, suppressed all warnings", Profiles));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate the hardware profiles in HKLM\Config
|
|||
|
//
|
|||
|
|
|||
|
if (EnumFirstRegKeyStr (&e, S_CONFIG_KEY)) {
|
|||
|
do {
|
|||
|
//
|
|||
|
// Determine if profile has an Enum key
|
|||
|
//
|
|||
|
|
|||
|
ProfileKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
|
|||
|
|
|||
|
if (ProfileKey) {
|
|||
|
EnumKey = OpenRegKey (ProfileKey, S_ENUM_SUBKEY);
|
|||
|
|
|||
|
if (EnumKey) {
|
|||
|
//
|
|||
|
// Determine if Enum key is empty
|
|||
|
//
|
|||
|
|
|||
|
if (EnumFirstRegKey (&e2, EnumKey)) {
|
|||
|
AbortRegKeyEnum (&e2);
|
|||
|
|
|||
|
//
|
|||
|
// Obtain friendly name for config
|
|||
|
//
|
|||
|
|
|||
|
ConfigDbKey = OpenRegKeyStr (S_FRIENDLYNAME_KEY);
|
|||
|
if (ConfigDbKey) {
|
|||
|
|
|||
|
Config = _ttoi (e.SubKeyName);
|
|||
|
|
|||
|
wsprintf (FriendlyName, S_FRIENDLYNAME_SPRINTF, Config);
|
|||
|
|
|||
|
Data = GetRegValueData (ConfigDbKey, FriendlyName);
|
|||
|
if (Data) {
|
|||
|
//
|
|||
|
// Put message in incompatibility report
|
|||
|
//
|
|||
|
wsprintf (FullKey, TEXT("%s\\%s"), S_CONFIG_KEY, e.SubKeyName);
|
|||
|
|
|||
|
//
|
|||
|
// Generate Msg and MsgGroup
|
|||
|
//
|
|||
|
|
|||
|
RootGroup = GetStringResource (MSG_INSTALL_NOTES_ROOT);
|
|||
|
MYASSERT (RootGroup);
|
|||
|
|
|||
|
HwProfiles = GetStringResource (MSG_HWPROFILES_SUBGROUP);
|
|||
|
MYASSERT (HwProfiles);
|
|||
|
|
|||
|
MsgGroup = JoinPaths (RootGroup, HwProfiles);
|
|||
|
MYASSERT (MsgGroup);
|
|||
|
|
|||
|
FreeStringResource (RootGroup);
|
|||
|
FreeStringResource (HwProfiles);
|
|||
|
|
|||
|
RootGroup = MsgGroup;
|
|||
|
MsgGroup = JoinPaths (RootGroup, Data);
|
|||
|
MYASSERT (MsgGroup);
|
|||
|
|
|||
|
FreePathString (RootGroup);
|
|||
|
|
|||
|
//
|
|||
|
// Add the message and clean up
|
|||
|
//
|
|||
|
|
|||
|
MsgMgr_ObjectMsg_Add (FullKey, MsgGroup, S_EMPTY);
|
|||
|
|
|||
|
FreePathString (MsgGroup);
|
|||
|
MemFree (g_hHeap, 0, Data);
|
|||
|
}
|
|||
|
ELSE_DEBUGMSG ((DBG_ERROR, "Hardware profile lacks friendly name"));
|
|||
|
|
|||
|
|
|||
|
CloseRegKey (ConfigDbKey);
|
|||
|
}
|
|||
|
ELSE_DEBUGMSG ((DBG_ERROR, "Hardware profile lacks config DB key"));
|
|||
|
|
|||
|
if (!ConfigDbKey) {
|
|||
|
LOG ((LOG_ERROR, "Hardware profile lacks config DB key"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (EnumKey);
|
|||
|
}
|
|||
|
CloseRegKey (ProfileKey);
|
|||
|
}
|
|||
|
|
|||
|
} while (EnumNextRegKey (&e));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
HardwareProfileWarning (
|
|||
|
IN DWORD Request
|
|||
|
)
|
|||
|
{
|
|||
|
switch (Request) {
|
|||
|
case REQUEST_QUERYTICKS:
|
|||
|
return TICKS_HARDWARE_PROFILE_WARNING;
|
|||
|
case REQUEST_RUN:
|
|||
|
pHardwareProfileWarning ();
|
|||
|
return ERROR_SUCCESS;
|
|||
|
default:
|
|||
|
DEBUGMSG ((DBG_ERROR, "Bad parameter in HardwareProfileWarning"));
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
pUnsupportedProtocolsWarning (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Produces incompatibility messages for network protocols that
|
|||
|
do not ship with equivalent versions on NT.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCTSTR NetworkProtocols;
|
|||
|
PCTSTR Message;
|
|||
|
PCTSTR ArgArray[2];
|
|||
|
REGKEY_ENUM e;
|
|||
|
HKEY ProtocolKey, BindingKey, DriverKey;
|
|||
|
REGKEY_ENUM ProtocolEnum;
|
|||
|
INFCONTEXT ic;
|
|||
|
PCTSTR Driver, DriverDesc, Mfg;
|
|||
|
DWORD MsgId;
|
|||
|
TCHAR DriverKeyStr[MAX_REGISTRY_KEY];
|
|||
|
TCHAR FullKey[MAX_REGISTRY_KEY];
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate the HKLM\Enum\Network key
|
|||
|
//
|
|||
|
|
|||
|
if (EnumFirstRegKeyStr (&e, S_ENUM_NETWORK_KEY)) {
|
|||
|
do {
|
|||
|
//
|
|||
|
// Check win95upg.inf to see if the network protocol is known
|
|||
|
//
|
|||
|
|
|||
|
if (SetupFindFirstLine (
|
|||
|
g_Win95UpgInf,
|
|||
|
S_SUPPORTED_PROTOCOLS,
|
|||
|
e.SubKeyName,
|
|||
|
&ic
|
|||
|
)) {
|
|||
|
// It is, skip to next protocol
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// A warning message must be generated. We must take the first
|
|||
|
// subkey of the protocol, query its Driver value, and look up
|
|||
|
// the DriverDesc in HKLM\System\CCS\Services\Class\<driver>.
|
|||
|
//
|
|||
|
|
|||
|
ProtocolKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
|
|||
|
|
|||
|
if (ProtocolKey) {
|
|||
|
if (EnumFirstRegKey (&ProtocolEnum, ProtocolKey)) {
|
|||
|
BindingKey = OpenRegKey (ProtocolKey, ProtocolEnum.SubKeyName);
|
|||
|
if (BindingKey) {
|
|||
|
Driver = (PCTSTR) GetRegValueDataOfType (
|
|||
|
BindingKey,
|
|||
|
S_DRIVER,
|
|||
|
REG_SZ
|
|||
|
);
|
|||
|
if (Driver) {
|
|||
|
//
|
|||
|
// We now know the driver... let's get the
|
|||
|
// driver description.
|
|||
|
//
|
|||
|
|
|||
|
wsprintf (DriverKeyStr, S_CLASS_KEY TEXT("\\%s"), Driver);
|
|||
|
MemFree (g_hHeap, 0, Driver);
|
|||
|
|
|||
|
DriverKey = OpenRegKeyStr (DriverKeyStr);
|
|||
|
if (DriverKey) {
|
|||
|
DriverDesc = (PCTSTR) GetRegValueDataOfType (
|
|||
|
DriverKey,
|
|||
|
S_DRIVERDESC,
|
|||
|
REG_SZ
|
|||
|
);
|
|||
|
|
|||
|
if (DriverDesc) {
|
|||
|
//
|
|||
|
// Obtain the manufacturer for use in message.
|
|||
|
// If the manufacturer is not known, display
|
|||
|
// a generic message.
|
|||
|
//
|
|||
|
|
|||
|
Mfg = (PCTSTR) GetRegValueDataOfType (
|
|||
|
BindingKey,
|
|||
|
S_MFG,
|
|||
|
REG_SZ
|
|||
|
);
|
|||
|
|
|||
|
if (!Mfg) {
|
|||
|
MsgId = MSG_UNSUPPORTED_PROTOCOL;
|
|||
|
} else {
|
|||
|
MsgId = MSG_UNSUPPORTED_PROTOCOL_KNOWN_MFG;
|
|||
|
}
|
|||
|
|
|||
|
ArgArray[0] = DriverDesc;
|
|||
|
ArgArray[1] = Mfg;
|
|||
|
|
|||
|
NetworkProtocols = ParseMessageID (MSG_NETWORK_PROTOCOLS, ArgArray);
|
|||
|
|
|||
|
if(Mfg && StringIMatch(Mfg, TEXT("Microsoft"))){
|
|||
|
Message = ParseMessageID (MSG_UNSUPPORTED_PROTOCOL_FROM_MICROSOFT, ArgArray);
|
|||
|
}
|
|||
|
else {
|
|||
|
Message = ParseMessageID (MsgId, ArgArray);
|
|||
|
}
|
|||
|
|
|||
|
MYASSERT (NetworkProtocols && Message);
|
|||
|
|
|||
|
wsprintf (FullKey, TEXT("%s\\%s"), S_ENUM_NETWORK_KEY, e.SubKeyName);
|
|||
|
|
|||
|
MsgMgr_ObjectMsg_Add (FullKey, NetworkProtocols, Message);
|
|||
|
|
|||
|
if (Mfg) {
|
|||
|
MemFree (g_hHeap, 0, Mfg);
|
|||
|
}
|
|||
|
|
|||
|
MemFree (g_hHeap, 0, DriverDesc);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (DriverKey);
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (BindingKey);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CloseRegKey (ProtocolKey);
|
|||
|
}
|
|||
|
} while (EnumNextRegKey (&e));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
UnsupportedProtocolsWarning (
|
|||
|
IN DWORD Request
|
|||
|
)
|
|||
|
{
|
|||
|
switch (Request) {
|
|||
|
case REQUEST_QUERYTICKS:
|
|||
|
return TICKS_UNSUPPORTED_PROTOCOLS_WARNING;
|
|||
|
case REQUEST_RUN:
|
|||
|
pUnsupportedProtocolsWarning ();
|
|||
|
return ERROR_SUCCESS;
|
|||
|
default:
|
|||
|
DEBUGMSG ((DBG_ERROR, "Bad parameter in UnsupportedProtocolWarning"));
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|