BOOL
InstallLegacyDevices(
IN HWND hwndParent,
IN HWND ProgressWindow,
IN ULONG StartAtPercent,
IN ULONG StopAtPercent,
IN PVOID DevicesInstalledStringTable OPTIONAL
)
{
ULONG Index;
SP_DEVINFO_DATA DeviceInfoData;
ULONG Error;
WCHAR GUIDString[ 64 ];
BOOL b = TRUE;
HSPFILEQ FileQ = INVALID_HANDLE_VALUE;
LPGUID GuidList = NULL;
ULONG GuidCount = 32;
ULONG GuidIndex;
ULONG LastBatchedDetect;
ULONG GuidLB, GuidUB;
HDEVINFO* InfoSetArray = NULL;
BOOL AlwaysFalse = FALSE;
UINT GaugeRange;
HANDLE ThreadHandle = NULL;
DWORD ThreadId;
PPNP_PHASE1_LEGACY_DEV_THREAD_PARAMS Phase1Context;
PPNP_PHASE2_LEGACY_DEV_THREAD_PARAMS Phase2Context;
WCHAR PnpLogPath[ MAX_PATH + 1 ];
WCHAR LoggedDescription[ LINE_LEN + 1 ];
DWORD ScanQueueResult;
SP_DRVINFO_DATA DriverInfoData;
ULONG PnPFlags;
DWORD Result;
SetupDebugPrint( L"SETUP: Entering InstallLegacyDevices()" );
//
// Build path to pnp log file
//
Result = GetWindowsDirectory( PnpLogPath, sizeof(PnpLogPath)/sizeof(WCHAR) );
if( Result == 0) {
MYASSERT(FALSE);
return FALSE;
}
if (!pSetupConcatenatePaths( PnpLogPath,
szPnpLogFile,
sizeof(PnpLogPath)/sizeof(WCHAR),
NULL )) {
MYASSERT(FALSE);
return FALSE;
}
//
// Do the migration of legacy devices.
// This is a quick operation and doesn't need to use the progress window.
//
// This is now performed before installation of true PnP devices
//
// PnPInitializationThread(NULL);
GuidList = ( LPGUID )MyMalloc( sizeof( GUID ) * GuidCount );
if( !GuidList ) {
return( FALSE );
}
if ( !SetupDiBuildClassInfoList( 0,
GuidList,
GuidCount,
&GuidCount ) ) {
Error = GetLastError();
if( Error != ERROR_INSUFFICIENT_BUFFER ) {
SetupDebugPrint1( L"SETUP: SetupDiBuildClassInfoList() failed. Error = %d", Error );
MyFree( GuidList );
//
// Fill the gauge up to the end of the area reserved for legacy devices.
//
GaugeRange = 100;
SendMessage(ProgressWindow,PBM_SETRANGE,0,MAKELPARAM(0,GaugeRange));
SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StopAtPercent/100,0);
SetupDebugPrint( L"SETUP: Leaving InstallLegacyDevices()" );
return( FALSE );
}
GuidList = ( LPGUID )MyRealloc( GuidList, sizeof( GUID ) * GuidCount );
if( !SetupDiBuildClassInfoList( 0,
GuidList,
GuidCount,
&GuidCount ) ) {
第二部分:
chenghao@chenghaodeiMac ntsetup % grep "SetupDiBuildClassInfoList" -nr ../pnp|grep -v "inary"
../pnp/tools/devcon2/setupclasses.cpp:382: if(SetupDiBuildClassInfoListEx(0,NULL,0,&nClasses,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
../pnp/tools/devcon2/setupclasses.cpp:393: if(SetupDiBuildClassInfoListEx(0,pList,nClasses,&nClasses2,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
../pnp/tools/devcon/cmds.cpp:147: if(!SetupDiBuildClassInfoListEx(0,guids,reqGuids,&numGuids,Machine,NULL)) {
../pnp/tools/devcon/cmds.cpp:158: } while(!SetupDiBuildClassInfoListEx(0,guids,reqGuids,&numGuids,Machine,NULL));
../pnp/tools/devcon/devcon.htm:34:<p>This command demonstrates the use of SetupDiBuildClassInfoListEx to enumerate
../pnp/setupapi/devicon.c:1665: SetupDiBuildClassInfoListEx(0,
../pnp/setupapi/devicon.c:1686: SetupDiBuildClassInfoListEx(
../pnp/setupapi/devclass.c:1314:SetupDiBuildClassInfoList(
../pnp/setupapi/devclass.c:1324: See SetupDiBuildClassInfoListEx for details.
../pnp/setupapi/devclass.c:1337: SetupDiBuildClassInfoListEx(Flags,
../pnp/setupapi/devclass.c:1359:SetupDiBuildClassInfoListExA(
../pnp/setupapi/devclass.c:1381: SetupDiBuildClassInfoListExW(Flags,
../pnp/setupapi/devclass.c:1404:SetupDiBuildClassInfoListEx(
第三部分:
BOOL
WINAPI
SetupDiBuildClassInfoList(
IN DWORD Flags,
OUT LPGUID ClassGuidList,
IN DWORD ClassGuidListSize,
OUT PDWORD RequiredSize
)
/*++
Routine Description:
See SetupDiBuildClassInfoListEx for details.
--*/
{
DWORD Err;
//
// Wrap call in try/except to catch stack overflow
//
try {
Err = GLE_FN_CALL(FALSE,
SetupDiBuildClassInfoListEx(Flags,
ClassGuidList,
ClassGuidListSize,
RequiredSize,
NULL,
NULL)
);
} except(pSetupExceptionFilter(GetExceptionCode())) {
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
}
SetLastError(Err);
return (Err == NO_ERROR);
}
第四部分:
BOOL
WINAPI
SetupDiBuildClassInfoListEx(
IN DWORD Flags,
OUT LPGUID ClassGuidList,
IN DWORD ClassGuidListSize,
OUT PDWORD RequiredSize,
IN PCTSTR MachineName, OPTIONAL
IN PVOID Reserved
)
/*++
Routine Description:
This routine returns a list of class GUIDs representing every class installed
on the user's system. (NOTE: Classes that have a 'NoUseClass' value entry in
their registry branch will be excluded from this list.)
Arguments:
Flags - Supplies flags used to control exclusion of classes from the list. If
no flags are specified, then all classes are included. The flags may be a
combination of the following:
DIBCI_NOINSTALLCLASS - Exclude a class if it has the value entry
'NoInstallClass' in its registry key.
DIBCI_NODISPLAYCLASS - Exclude a class if it has the value entry
'NoDisplayClass' in its registry key.
ClassGuidList - Supplies the address of an array of GUIDs that will receive the
GUID list.
ClassGuidListSize - Supplies the number of GUIDs in the ClassGuidList array.
RequiredSize - Supplies the address of a variable that will receive the number
of GUIDs returned. If this number is greater than the size of the ClassGuidList,
then this number will specify how large the array needs to be in order to contain
the list.
MachineName - Optionally, supplies the name of a remote machine to retrieve installed
classes from. If this parameter is not specified, the local machine is used.
Reserved - Reserved for future use--must be NULL.
Return Value:
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. To get extended error
information, call GetLastError.
--*/
{
DWORD Err, ClassGuidCount = 0;
CONFIGRET cr;
BOOL MoreToEnum;
ULONG i;
HKEY hk = INVALID_HANDLE_VALUE;
GUID CurClassGuid;
HMACHINE hMachine = NULL;
try {
//
// Make sure the caller didn't pass us anything in the Reserved parameter.
//
if(Reserved) {
Err = ERROR_INVALID_PARAMETER;
leave;
}
//
// If the caller specified a remote machine name, connect to that machine now.
//
if(MachineName) {
cr = CM_Connect_Machine(MachineName, &hMachine);
if(cr != CR_SUCCESS) {
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
hMachine = NULL; // don't assume this was left untouched
leave;
}
}
Err = NO_ERROR;
//
// Enumerate through the list of all installed classes.
//
for(i = 0, MoreToEnum = TRUE; MoreToEnum; i++) {
cr = CM_Enumerate_Classes_Ex(i,
&CurClassGuid,
0,
hMachine
);
if(cr != CR_SUCCESS) {
//
// For any failure other than no-more-to-enum (or some kind of RPC error),
// we simply want to go on to the next class.
//
switch(cr) {
case CR_INVALID_MACHINENAME :
case CR_REMOTE_COMM_FAILURE :
case CR_MACHINE_UNAVAILABLE :
case CR_NO_CM_SERVICES :
case CR_ACCESS_DENIED :
case CR_CALL_NOT_IMPLEMENTED :
case CR_REGISTRY_ERROR :
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
//
// Fall through to 'no more values' case to terminate loop.
//
case CR_NO_SUCH_VALUE :
MoreToEnum = FALSE;
break;
default :
//
// Nothing to do.
//
break;
}
continue;
}
//
// Open the key for this class.
//
if(CM_Open_Class_Key_Ex(&CurClassGuid,
NULL,
KEY_READ,
RegDisposition_OpenExisting,
&hk,
CM_OPEN_CLASS_KEY_INSTALLER,
hMachine) != CR_SUCCESS) {
hk = INVALID_HANDLE_VALUE;
continue;
}
//
// First, check for the presence of the value entry "NoUseClass"
// If this value is present, then we will skip this class.
//
if(RegQueryValueEx(hk, pszNoUseClass, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
goto LoopNext;
}
//
// Check for special exclusion flags.
//
if(Flags & DIBCI_NOINSTALLCLASS) {
if(RegQueryValueEx(hk, pszNoInstallClass, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
goto LoopNext;
}
}
if(Flags & DIBCI_NODISPLAYCLASS) {
if(RegQueryValueEx(hk, pszNoDisplayClass, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
goto LoopNext;
}
}
if(ClassGuidCount < ClassGuidListSize) {
CopyMemory(&(ClassGuidList[ClassGuidCount]), &CurClassGuid, sizeof(GUID));
}
ClassGuidCount++;
LoopNext:
RegCloseKey(hk);
hk = INVALID_HANDLE_VALUE;
}
if(Err == NO_ERROR) {
*RequiredSize = ClassGuidCount;
if(ClassGuidCount > ClassGuidListSize) {
Err = ERROR_INSUFFICIENT_BUFFER;
}
}
} except(pSetupExceptionFilter(GetExceptionCode())) {
pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
}
if(hk != INVALID_HANDLE_VALUE) {
RegCloseKey(hk);
}
if(hMachine) {
CM_Disconnect_Machine(hMachine);
}
SetLastError(Err);
return (Err == NO_ERROR);
}