Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cmconfig.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1990, 1991 Microsoft Corporation 00004 00005 00006 Module Name: 00007 00008 cmconfig.c 00009 00010 Abstract: 00011 00012 This module is responsible to build the hardware tree of the 00013 registry data base. 00014 00015 Author: 00016 00017 Shie-Lin Tzong (shielint) 23-Jan-1992 00018 00019 00020 Environment: 00021 00022 Kernel mode. 00023 00024 Revision History: 00025 00026 --*/ 00027 00028 #include "cmp.h" 00029 00030 // 00031 // Title Index - Never used for Product 1, set to 0 for now. 00032 // 00033 00034 #define TITLE_INDEX_VALUE 0 00035 00036 00037 extern ULONG CmpTypeCount[]; 00038 00039 00040 #define EISA_ADAPTER_INDEX EisaAdapter 00041 #define TURBOCHANNEL_ADAPTER_INDEX TcAdapter 00042 00043 // 00044 // The following variables are used to cross-reference multifunction 00045 // adapters to their corresponding NT interface type. 00046 // 00047 00048 extern struct { 00049 PUCHAR AscString; 00050 USHORT InterfaceType; 00051 USHORT Count; 00052 } CmpMultifunctionTypes[]; 00053 00054 extern USHORT CmpUnknownBusCount; 00055 00056 00057 // 00058 // CmpConfigurationData - A pointer to the area reserved for the purpose 00059 // of reconstructing Configuration Data. 00060 // 00061 // CmpConfigurationAreaSize - Record the size of the Configuration Data 00062 // area. 00063 00064 extern ULONG CmpConfigurationAreaSize; 00065 extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData; 00066 00067 // 00068 // Function prototypes for internal erferences 00069 // 00070 00071 NTSTATUS 00072 CmpSetupConfigurationTree( 00073 IN PCONFIGURATION_COMPONENT_DATA CurrentEntry, 00074 IN HANDLE ParentHandle, 00075 IN INTERFACE_TYPE InterfaceType, 00076 IN ULONG BusNumber 00077 ); 00078 00079 #ifdef ALLOC_PRAGMA 00080 #pragma alloc_text(INIT,CmpInitializeHardwareConfiguration) 00081 #pragma alloc_text(INIT,CmpSetupConfigurationTree) 00082 #pragma alloc_text(INIT,CmpInitializeRegistryNode) 00083 #endif 00084 00085 00086 NTSTATUS 00087 CmpInitializeHardwareConfiguration( 00088 IN PLOADER_PARAMETER_BLOCK LoaderBlock 00089 ) 00090 /*++ 00091 00092 Routine Description: 00093 00094 This routine creates \\Registry\Machine\Hardware node in 00095 the registry and calls SetupTree routine to put the hardware 00096 information to the registry. 00097 00098 Arguments: 00099 00100 LoaderBlock - supplies a pointer to the LoaderBlock passed in from the 00101 OS Loader. 00102 00103 Returns: 00104 00105 NTSTATUS code for sucess or reason of failure. 00106 00107 --*/ 00108 { 00109 NTSTATUS Status; 00110 OBJECT_ATTRIBUTES ObjectAttributes; 00111 HANDLE BaseHandle; 00112 PCONFIGURATION_COMPONENT_DATA ConfigurationRoot; 00113 ULONG Disposition; 00114 00115 ConfigurationRoot = (PCONFIGURATION_COMPONENT_DATA)LoaderBlock->ConfigurationRoot; 00116 if (ConfigurationRoot) { 00117 00118 #ifdef _X86_ 00119 00120 // 00121 // The following strings found in the registry identify obscure, 00122 // yet market dominant, non PC/AT compatible i386 machine in Japan. 00123 // 00124 00125 #define MACHINE_TYPE_FUJITSU_FMR_NAME_A "FUJITSU FMR-" 00126 #define MACHINE_TYPE_NEC_PC98_NAME_A "NEC PC-98" 00127 00128 { 00129 PCONFIGURATION_COMPONENT_DATA SystemNode; 00130 ULONG JapanMachineId; 00131 00132 // 00133 // For Japan, we have to special case some non PC/AT machines, so 00134 // determine at this time what kind of platform we are on: 00135 // 00136 // NEC PC9800 Compatibles/Fujitsu FM-R Compatibles/IBM PC/AT Compatibles 00137 // 00138 // Default is PC/AT compatible. 00139 // 00140 00141 JapanMachineId = MACHINE_TYPE_PC_AT_COMPATIBLE; 00142 00143 // 00144 // Find the hardware description node 00145 // 00146 00147 SystemNode = KeFindConfigurationEntry(ConfigurationRoot, 00148 SystemClass, 00149 MaximumType, 00150 NULL); 00151 00152 // 00153 // Did we find something? 00154 // 00155 00156 if (SystemNode) { 00157 00158 // 00159 // Check platform from identifier string 00160 // 00161 00162 if (RtlCompareMemory(SystemNode->ComponentEntry.Identifier, 00163 MACHINE_TYPE_NEC_PC98_NAME_A, 00164 sizeof(MACHINE_TYPE_NEC_PC98_NAME_A) - 1) == 00165 sizeof(MACHINE_TYPE_NEC_PC98_NAME_A) - 1) { 00166 00167 // 00168 // we are running on NEC PC-9800 comaptibles. 00169 // 00170 00171 JapanMachineId = MACHINE_TYPE_PC_9800_COMPATIBLE; 00172 SetNEC_98; 00173 00174 } else if (RtlCompareMemory(SystemNode->ComponentEntry.Identifier, 00175 MACHINE_TYPE_FUJITSU_FMR_NAME_A, 00176 sizeof(MACHINE_TYPE_FUJITSU_FMR_NAME_A) - 1) == 00177 sizeof(MACHINE_TYPE_FUJITSU_FMR_NAME_A) - 1) { 00178 00179 // 00180 // we are running on Fujitsu FMR comaptibles. 00181 // 00182 00183 JapanMachineId = MACHINE_TYPE_FMR_COMPATIBLE; 00184 } 00185 } 00186 00187 // 00188 // Now 'or' this value into the kernel global. 00189 // 00190 00191 KeI386MachineType |= JapanMachineId; 00192 } 00193 #endif //_X86_ 00194 00195 // 00196 // Create \\Registry\Machine\Hardware\DeviceMap 00197 // 00198 00199 InitializeObjectAttributes( 00200 &ObjectAttributes, 00201 &CmRegistryMachineHardwareDeviceMapName, 00202 0, 00203 (HANDLE)NULL, 00204 NULL 00205 ); 00206 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; 00207 00208 Status = NtCreateKey( // Paht may already exist 00209 &BaseHandle, 00210 KEY_READ | KEY_WRITE, 00211 &ObjectAttributes, 00212 TITLE_INDEX_VALUE, 00213 NULL, 00214 0, 00215 &Disposition 00216 ); 00217 00218 if (!NT_SUCCESS(Status)) { 00219 return(Status); 00220 } 00221 00222 NtClose(BaseHandle); 00223 00224 ASSERT(Disposition == REG_CREATED_NEW_KEY); 00225 00226 // 00227 // Create \\Registry\Machine\Hardware\Description and use the 00228 // returned handle as the BaseHandle to build the hardware tree. 00229 // 00230 00231 InitializeObjectAttributes( 00232 &ObjectAttributes, 00233 &CmRegistryMachineHardwareDescriptionName, 00234 0, 00235 (HANDLE)NULL, 00236 NULL 00237 ); 00238 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; 00239 00240 Status = NtCreateKey( // Path may already exist 00241 &BaseHandle, 00242 KEY_READ | KEY_WRITE, 00243 &ObjectAttributes, 00244 TITLE_INDEX_VALUE, 00245 NULL, 00246 0, 00247 &Disposition 00248 ); 00249 00250 if (!NT_SUCCESS(Status)) { 00251 return(Status); 00252 } 00253 00254 ASSERT(Disposition == REG_CREATED_NEW_KEY); 00255 00256 // 00257 // Allocate 16K bytes memory from paged pool for constructing 00258 // configuration data for controller component. 00259 // NOTE: The configuration Data for controller component 00260 // usually takes less than 100 bytes. But on EISA machine, the 00261 // EISA configuration information takes more than 10K and up to 00262 // 64K. I believe 16K is the reasonable number to handler 99.9% 00263 // of the machines. Therefore, 16K is the initial value. 00264 // 00265 00266 CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool( 00267 PagedPool, 00268 CmpConfigurationAreaSize 00269 ); 00270 00271 if (CmpConfigurationData == NULL) { 00272 return(STATUS_INSUFFICIENT_RESOURCES); 00273 } 00274 00275 // 00276 // Call SetupConfigurationTree routine to go over each component 00277 // of the tree and add component information to registry database. 00278 // 00279 00280 Status = CmpSetupConfigurationTree(ConfigurationRoot, 00281 BaseHandle, 00282 -1, 00283 (ULONG)-1 00284 ); 00285 ExFreePool((PVOID)CmpConfigurationData); 00286 NtClose(BaseHandle); 00287 return(Status); 00288 } else { 00289 return(STATUS_SUCCESS); 00290 } 00291 } 00292 00293 NTSTATUS 00294 CmpSetupConfigurationTree( 00295 IN PCONFIGURATION_COMPONENT_DATA CurrentEntry, 00296 IN HANDLE ParentHandle, 00297 IN INTERFACE_TYPE InterfaceType, 00298 IN ULONG BusNumber 00299 ) 00300 /*++ 00301 00302 Routine Description: 00303 00304 This routine traverses loader configuration tree and register 00305 the hardware information to the registry data base. 00306 00307 Note to reduce the stack usage on machines with large number of PCI buses, 00308 we do not recursively process the sibling nodes. We only recursively 00309 process the child trees. 00310 00311 Arguments: 00312 00313 CurrentEntry - Supplies a pointer to a loader configuration 00314 tree or subtree. 00315 00316 ParentHandle - Supplies the parent handle of CurrentEntry node. 00317 00318 InterfaceType - Specify the Interface type of the bus that the 00319 CurrentEntry component resides. 00320 00321 BusNumber - Specify the Bus Number of the bus that the CurrentEntry 00322 component resides. If Bus number is -1, it means InterfaceType 00323 and BusNumber are meaningless for this component. 00324 00325 Returns: 00326 00327 None. 00328 00329 --*/ 00330 { 00331 NTSTATUS Status; 00332 HANDLE NewHandle; 00333 USHORT i; 00334 CONFIGURATION_COMPONENT *Component; 00335 INTERFACE_TYPE LocalInterfaceType = InterfaceType; 00336 ULONG LocalBusNumber = BusNumber; 00337 USHORT DeviceIndexTable[NUMBER_TYPES]; 00338 00339 for (i = 0; i < NUMBER_TYPES; i++) { 00340 DeviceIndexTable[i] = 0; 00341 } 00342 00343 // 00344 // Process current entry and its siblings 00345 // 00346 00347 while (CurrentEntry) { 00348 00349 // 00350 // Register current entry first before going down to its children 00351 // 00352 00353 Component = &CurrentEntry->ComponentEntry; 00354 00355 // 00356 // If the current component is a bus component, we will set up 00357 // its bus number and Interface type and use them to initialize 00358 // its subtree. 00359 // 00360 00361 if (Component->Class == AdapterClass && 00362 CurrentEntry->Parent->ComponentEntry.Class == SystemClass) { 00363 00364 switch (Component->Type) { 00365 00366 case EisaAdapter: 00367 LocalInterfaceType = Eisa; 00368 LocalBusNumber = CmpTypeCount[EISA_ADAPTER_INDEX]++; 00369 break; 00370 case TcAdapter: 00371 LocalInterfaceType = TurboChannel; 00372 LocalBusNumber = CmpTypeCount[TURBOCHANNEL_ADAPTER_INDEX]++; 00373 break; 00374 case MultiFunctionAdapter: 00375 00376 // 00377 // Here we try to distinguish if the Multifunction adapter is 00378 // Isa, Mca, Internal bus and assign BusNumber based on 00379 // its interface type (bus type.) 00380 // 00381 00382 if (Component->Identifier) { 00383 for (i=0; CmpMultifunctionTypes[i].AscString; i++) { 00384 if (_stricmp(CmpMultifunctionTypes[i].AscString, 00385 Component->Identifier) == 0) { 00386 break; 00387 } 00388 } 00389 00390 LocalInterfaceType = CmpMultifunctionTypes[i].InterfaceType; 00391 LocalBusNumber = CmpMultifunctionTypes[i].Count++; 00392 } 00393 break; 00394 00395 case ScsiAdapter: 00396 00397 // 00398 // Set the bus type to internal. 00399 // 00400 00401 LocalInterfaceType = Internal; 00402 LocalBusNumber = CmpTypeCount[ScsiAdapter]++; 00403 break; 00404 00405 default: 00406 LocalInterfaceType = -1; 00407 LocalBusNumber = CmpUnknownBusCount++; 00408 break; 00409 } 00410 } 00411 00412 // 00413 // Initialize and copy current component to hardware registry 00414 // 00415 00416 Status = CmpInitializeRegistryNode( 00417 CurrentEntry, 00418 ParentHandle, 00419 &NewHandle, 00420 LocalInterfaceType, 00421 LocalBusNumber, 00422 DeviceIndexTable 00423 ); 00424 00425 if (!NT_SUCCESS(Status)) { 00426 return(Status); 00427 } 00428 00429 // 00430 // Once we are going one level down, we need to clear the TypeCount 00431 // table for everything under the current component class ... 00432 // 00433 00434 if (CurrentEntry->Child) { 00435 00436 // 00437 // Process the child entry of current entry 00438 // 00439 00440 Status = CmpSetupConfigurationTree(CurrentEntry->Child, 00441 NewHandle, 00442 LocalInterfaceType, 00443 LocalBusNumber 00444 ); 00445 if (!NT_SUCCESS(Status)) { 00446 NtClose(NewHandle); 00447 return(Status); 00448 } 00449 } 00450 NtClose(NewHandle); 00451 CurrentEntry = CurrentEntry->Sibling; 00452 } 00453 return(STATUS_SUCCESS); 00454 } 00455 00456 00457 NTSTATUS 00458 CmpInitializeRegistryNode( 00459 IN PCONFIGURATION_COMPONENT_DATA CurrentEntry, 00460 IN HANDLE ParentHandle, 00461 OUT PHANDLE NewHandle, 00462 IN INTERFACE_TYPE InterfaceType, 00463 IN ULONG BusNumber, 00464 IN PUSHORT DeviceIndexTable 00465 ) 00466 00467 /*++ 00468 00469 Routine Description: 00470 00471 This routine creates a node for the current firmware component 00472 and puts component data to the data part of the node. 00473 00474 Arguments: 00475 00476 CurrentEntry - Supplies a pointer to a configuration component. 00477 00478 Handle - Supplies the parent handle of CurrentEntry node. 00479 00480 NewHandle - Suppiles a pointer to a HANDLE to receive the handle of 00481 the newly created node. 00482 00483 InterfaceType - Specify the Interface type of the bus that the 00484 CurrentEntry component resides. (See BusNumber also) 00485 00486 BusNumber - Specify the Bus Number of the bus that the CurrentEntry 00487 component resides on. If Bus number is -1, it means InterfaceType 00488 and BusNumber are meaningless for this component. 00489 00490 Returns: 00491 00492 None. 00493 00494 --*/ 00495 { 00496 00497 NTSTATUS Status; 00498 OBJECT_ATTRIBUTES ObjectAttributes; 00499 UNICODE_STRING KeyName; 00500 UNICODE_STRING ValueName; 00501 UNICODE_STRING ValueData; 00502 HANDLE Handle; 00503 HANDLE OldHandle; 00504 ANSI_STRING AnsiString; 00505 UCHAR Buffer[12]; 00506 WCHAR UnicodeBuffer[12]; 00507 CONFIGURATION_COMPONENT *Component; 00508 ULONG Disposition; 00509 ULONG ConfigurationDataLength; 00510 PCM_FULL_RESOURCE_DESCRIPTOR NewArea; 00511 00512 Component = &CurrentEntry->ComponentEntry; 00513 00514 // 00515 // If the component class is SystemClass, we set its Type to be 00516 // ArcSystem. The reason is because the detection code sets 00517 // its type to MaximumType to indicate it is NOT ARC compatible. 00518 // Here, we are only interested in building a System Node. So we 00519 // change its Type to ArcSystem to ease the setup. 00520 // 00521 00522 if (Component->Class == SystemClass) { 00523 Component->Type = ArcSystem; 00524 } 00525 00526 // 00527 // Create a new key to describe the Component. 00528 // 00529 // The type of the component will be used as the keyname of the 00530 // registry node. The class is the class of the component. 00531 // 00532 00533 InitializeObjectAttributes( 00534 &ObjectAttributes, 00535 &(CmTypeName[Component->Type]), 00536 0, 00537 ParentHandle, 00538 NULL 00539 ); 00540 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; 00541 00542 Status = NtCreateKey( // Paht may already exist 00543 &Handle, 00544 KEY_READ | KEY_WRITE, 00545 &ObjectAttributes, 00546 TITLE_INDEX_VALUE, 00547 &(CmClassName[Component->Class]), 00548 0, 00549 &Disposition 00550 ); 00551 00552 if (!NT_SUCCESS(Status)) { 00553 return(Status); 00554 } 00555 00556 // 00557 // If this component is NOT a SystemClass component, we will 00558 // create a subkey to identify the component's ordering. 00559 // 00560 00561 if (Component->Class != SystemClass) { 00562 00563 RtlIntegerToChar( 00564 DeviceIndexTable[Component->Type]++, 00565 10, 00566 12, 00567 Buffer 00568 ); 00569 00570 RtlInitAnsiString( 00571 &AnsiString, 00572 Buffer 00573 ); 00574 00575 KeyName.Buffer = (PWSTR)UnicodeBuffer; 00576 KeyName.Length = 0; 00577 KeyName.MaximumLength = sizeof(UnicodeBuffer); 00578 00579 RtlAnsiStringToUnicodeString( 00580 &KeyName, 00581 &AnsiString, 00582 FALSE 00583 ); 00584 00585 OldHandle = Handle; 00586 00587 InitializeObjectAttributes( 00588 &ObjectAttributes, 00589 &KeyName, 00590 0, 00591 OldHandle, 00592 NULL 00593 ); 00594 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; 00595 00596 Status = NtCreateKey( 00597 &Handle, 00598 KEY_READ | KEY_WRITE, 00599 &ObjectAttributes, 00600 TITLE_INDEX_VALUE, 00601 &(CmClassName[Component->Class]), 00602 0, 00603 &Disposition 00604 ); 00605 00606 NtClose(OldHandle); 00607 00608 if (!NT_SUCCESS(Status)) { 00609 return(Status); 00610 } 00611 00612 ASSERT(Disposition == REG_CREATED_NEW_KEY); 00613 } 00614 00615 // 00616 // Create a value which describes the following component information: 00617 // Flags, Cersion, Key, AffinityMask. 00618 // 00619 00620 RtlInitUnicodeString( 00621 &ValueName, 00622 L"Component Information" 00623 ); 00624 00625 Status = NtSetValueKey( 00626 Handle, 00627 &ValueName, 00628 TITLE_INDEX_VALUE, 00629 REG_BINARY, 00630 &Component->Flags, 00631 FIELD_OFFSET(CONFIGURATION_COMPONENT, ConfigurationDataLength) - 00632 FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags) 00633 ); 00634 00635 if (!NT_SUCCESS(Status)) { 00636 NtClose(Handle); 00637 return(Status); 00638 } 00639 00640 // 00641 // Create a value which describes the component identifier, if any. 00642 // 00643 00644 if (Component->IdentifierLength) { 00645 00646 RtlInitUnicodeString( 00647 &ValueName, 00648 L"Identifier" 00649 ); 00650 00651 RtlInitAnsiString( 00652 &AnsiString, 00653 Component->Identifier 00654 ); 00655 00656 RtlAnsiStringToUnicodeString( 00657 &ValueData, 00658 &AnsiString, 00659 TRUE 00660 ); 00661 00662 Status = NtSetValueKey( 00663 Handle, 00664 &ValueName, 00665 TITLE_INDEX_VALUE, 00666 REG_SZ, 00667 ValueData.Buffer, 00668 ValueData.Length + sizeof( UNICODE_NULL ) 00669 ); 00670 00671 RtlFreeUnicodeString(&ValueData); 00672 00673 if (!NT_SUCCESS(Status)) { 00674 NtClose(Handle); 00675 return(Status); 00676 } 00677 } 00678 00679 // 00680 // Create a value entry for component configuration data. 00681 // 00682 00683 RtlInitUnicodeString( 00684 &ValueName, 00685 L"Configuration Data" 00686 ); 00687 00688 // 00689 // Create the configuration data based on CM_FULL_RESOURCE_DESCRIPTOR. 00690 // 00691 // Note the configuration data in firmware tree may be in the form of 00692 // CM_PARTIAL_RESOURCE_LIST or nothing. In both cases, we need to 00693 // set up the registry configuration data to be in the form of 00694 // CM_FULL_RESOURCE_DESCRIPTOR. 00695 // 00696 00697 if (CurrentEntry->ConfigurationData) { 00698 00699 // 00700 // This component has configuration data, we copy the data 00701 // to our work area, add some more data items and copy the new 00702 // configuration data to the registry. 00703 // 00704 00705 ConfigurationDataLength = Component->ConfigurationDataLength + 00706 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, 00707 PartialResourceList); 00708 00709 // 00710 // Make sure our reserved area is big enough to hold the data. 00711 // 00712 00713 if (ConfigurationDataLength > CmpConfigurationAreaSize) { 00714 00715 // 00716 // If reserved area is not big enough, we resize our reserved 00717 // area. If, unfortunately, the reallocation fails, we simply 00718 // loss the configuration data of this particular component. 00719 // 00720 00721 NewArea = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool( 00722 PagedPool, 00723 ConfigurationDataLength 00724 ); 00725 00726 if (NewArea) { 00727 CmpConfigurationAreaSize = ConfigurationDataLength; 00728 ExFreePool(CmpConfigurationData); 00729 CmpConfigurationData = NewArea; 00730 RtlMoveMemory( 00731 (PUCHAR)&CmpConfigurationData->PartialResourceList.Version, 00732 CurrentEntry->ConfigurationData, 00733 Component->ConfigurationDataLength 00734 ); 00735 } else { 00736 Component->ConfigurationDataLength = 0; 00737 CurrentEntry->ConfigurationData = NULL; 00738 } 00739 } else { 00740 RtlMoveMemory( 00741 (PUCHAR)&CmpConfigurationData->PartialResourceList.Version, 00742 CurrentEntry->ConfigurationData, 00743 Component->ConfigurationDataLength 00744 ); 00745 } 00746 00747 } 00748 00749 if (CurrentEntry->ConfigurationData == NULL) { 00750 00751 // 00752 // This component has NO configuration data (or we can't resize 00753 // our reserved area to hold the data), we simple add whatever 00754 // is required to set up a CM_FULL_RESOURCE_LIST. 00755 // 00756 00757 CmpConfigurationData->PartialResourceList.Version = 0; 00758 CmpConfigurationData->PartialResourceList.Revision = 0; 00759 CmpConfigurationData->PartialResourceList.Count = 0; 00760 ConfigurationDataLength = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, 00761 PartialResourceList) + 00762 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, 00763 PartialDescriptors); 00764 } 00765 00766 // 00767 // Set up InterfaceType and BusNumber for the component. 00768 // 00769 00770 CmpConfigurationData->InterfaceType = InterfaceType; 00771 CmpConfigurationData->BusNumber = BusNumber; 00772 00773 // 00774 // Write the newly constructed configuration data to the hardware registry 00775 // 00776 00777 Status = NtSetValueKey( 00778 Handle, 00779 &ValueName, 00780 TITLE_INDEX_VALUE, 00781 REG_FULL_RESOURCE_DESCRIPTOR, 00782 CmpConfigurationData, 00783 ConfigurationDataLength 00784 ); 00785 00786 if (!NT_SUCCESS(Status)) { 00787 NtClose(Handle); 00788 return(Status); 00789 } 00790 00791 *NewHandle = Handle; 00792 return(STATUS_SUCCESS); 00793 00794 }

Generated on Sat May 15 19:39:26 2004 for test by doxygen 1.3.7