WindowsXP-SP1/base/wmi/core/krnlmode.c
2020-09-30 16:53:49 +02:00

897 lines
27 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
krnlmode.c
Abstract:
WMI interface to Kernel mode data providers
Author:
16-Jan-1997 AlanWar
Revision History:
--*/
#include "wmiump.h"
extern HANDLE WmipKMHandle;
PTCHAR WmipRegistryToImagePath(
PTCHAR ImagePath,
PTCHAR RegistryPath,
UINT_PTR ProviderId
)
/*++
Routine Description:
This routine will determine the location of the device driver's image file
from its registry path
Arguments:
RegistryPath is a pointer to the driver's registry path
ImagePath is buffer of length MAX_PATH and returns the image path
Return Value:
pointer to Image path of driver or NULL if image path is unavailable
--*/
{
#define SystemRoot TEXT("\\SystemRoot\\")
#ifdef MEMPHIS
#define SystemRootDirectory TEXT("%WinDir%\\")
#else
#define SystemRootDirectory TEXT("%SystemRoot%\\")
#endif
#define SystemRootCharSize (( sizeof(SystemRoot) / sizeof(WCHAR) ) - 1)
#define DriversDirectory TEXT("\\System32\\Drivers\\")
#define NdisDriversDirectory TEXT("\\System\\")
#define QuestionPrefix TEXT("\\??\\")
#define QuestionPrefixSize (( sizeof(QuestionPrefix) / sizeof(WCHAR) ) - 1)
#define RegistryPrefix TEXT("\\Registry")
HKEY RegKey;
PTCHAR ImagePathPtr = NULL;
ULONG ValueType;
ULONG Size;
TCHAR Buffer[MAX_PATH];
TCHAR Buffer2[MAX_PATH];
TCHAR FullRegistryPath[MAX_PATH];
PTCHAR DriverName;
ULONG Len;
BOOLEAN DefaultImageName;
PTCHAR DriversDirectoryPath;
// CONSIDER: Do some grovelling around directories in case we don't find
// the image.
#ifdef MEMPHIS
//
// On memphis the registry path could point to two places
// \Registry\Machine\System\CurrentControlSet\Services\Driver (Legacy)
// System\CurrentControlSet\Services\Class\USB\0001
if (_tcsnicmp(RegistryPath, RegistryPrefix, sizeof(RegistryPrefix)-1) != 0)
{
//
// This is a non legacy type registry path.
if (RegOpenKey(HKEY_LOCAL_MACHINE,
RegistryPath,
&RegKey) == ERROR_SUCCESS)
{
DriverName = Buffer2;
Size = MAX_PATH * sizeof(WCHAR);
if (RegQueryValueEx(RegKey,
TEXT("NTMPDriver"),
NULL,
&ValueType,
DriverName,
&Size) == ERROR_SUCCESS)
{
DriversDirectoryPath = DriversDirectory;
} else if (RegQueryValueEx(RegKey,
TEXT("DeviceVxDs"),
NULL,
&ValueType,
DriverName,
&Size) == ERROR_SUCCESS)
{
DriversDirectoryPath = NdisDriversDirectory;
} else {
DriversDirectoryPath = NULL;
}
if ((DriversDirectoryPath != NULL) && (ValueType == REG_SZ))
{
Size = GetWindowsDirectory(Buffer, MAX_PATH);
if ((Size != 0) &&
(Size <= (MAX_PATH - _tcslen(DriverName) - sizeof(DriversDirectory) - 1)))
{
if (Buffer[Size-1] == TEXT('\\'))
{
Buffer[Size-1] = 0;
}
_tcscpy(ImagePath, Buffer);
_tcscat(ImagePath, DriversDirectoryPath);
_tcscat(ImagePath, DriverName);
ImagePathPtr = ImagePath;
RegCloseKey(RegKey);
return(ImagePathPtr);
}
}
RegCloseKey(RegKey);
}
}
#endif
//
// Get the driver file name or the MOF image path from the KM
// registry path. Here are the rules:
//
// 1. First check the MofImagePath value in the registry in case the
// mof resource is in a different file from the driver.
// 2. Next check the ImagePath value since the mof resource is assumed
// to be part of the driver image.
// 3. If no MofImagePath or ImagePath values then assume the mof resource
// is in the driver file and compose the driver file name as
// %SystemRoot%\System32\driver.sys.
// 4. If MofImagePath or ImagePath was specified then
// - Check first char for % or second character for :, or prefix
// of \??\ and if so use ExpandEnvironmentStrings
// - Check first part of path for \SystemRoot\, if so rebuild string
// as %SystemRoot%\ and use ExpandEnvironementStrings
// - Assume format D below and prepend %SystemRoot%\ and use
// ExpandEnvironmentStrings
// If MofImagePath or ImagePath value is present and it is a REG_EXPAND_SZ
// then it is used to locate the file that holds the mof resource. It
// can be in one of the following formats:
// Format A - %SystemRoot%\System32\Foo.Dll
// Format B -C:\WINNT\SYSTEM32\Drivers\Foo.SYS
// Format C - \SystemRoot\System32\Drivers\Foo.SYS
// Format D - System32\Drivers\Foo.Sys
// Format E - \??\c:\foo.sys
Len = _tcslen(RegistryPath);
if (Len > 0)
{
DriverName = RegistryPath + Len;
while ((*(--DriverName) != '\\') && (--Len > 0)) ;
}
if (Len == 0)
{
WmipReportEventLog(EVENT_WMI_INVALID_REGPATH,
EVENTLOG_WARNING_TYPE,
0,
sizeof(UINT_PTR),
&ProviderId,
1,
RegistryPath);
WmipDebugPrint(("WMI: Badly formed registry path %ws\n", RegistryPath));
return(NULL);
}
DriverName++;
_tcscpy(FullRegistryPath, TEXT("System\\CurrentControlSet\\Services\\"));
_tcscat(FullRegistryPath, DriverName);
DefaultImageName = TRUE;
if (RegOpenKey(HKEY_LOCAL_MACHINE,
FullRegistryPath,
&RegKey) == ERROR_SUCCESS)
{
Size = MAX_PATH * sizeof(WCHAR);
if (RegQueryValueEx(RegKey,
TEXT("MofImagePath"),
NULL,
&ValueType,
(PBYTE)ImagePath,
&Size) == ERROR_SUCCESS)
{
DefaultImageName = FALSE;
} else {
Size = MAX_PATH * sizeof(WCHAR);
if (RegQueryValueEx(RegKey,
TEXT("ImagePath"),
NULL,
&ValueType,
(PBYTE)ImagePath,
&Size) == ERROR_SUCCESS)
{
DefaultImageName = FALSE;
}
}
RegCloseKey(RegKey);
}
if ((DefaultImageName) ||
((ValueType != REG_EXPAND_SZ) && (ValueType != REG_SZ)) ||
(Size < (2 * sizeof(WCHAR))))
{
//
// No special ImagePath or MofImagePath so assume image file is
// %SystemRoot%\System32\Drivers\Driver.Sys
#ifdef MEMPHIS
_tcscpy(Buffer, TEXT("%WinDir%\\System32\\Drivers\\"));
#else
_tcscpy(Buffer, TEXT("%SystemRoot%\\System32\\Drivers\\"));
#endif
_tcscat(Buffer, DriverName);
_tcscat(Buffer, TEXT(".SYS"));
} else {
if (_tcsnicmp(ImagePath,
SystemRoot,
SystemRootCharSize) == 0)
{
//
// Looks like format C
_tcscpy(Buffer, SystemRootDirectory);
_tcscat(Buffer, &ImagePath[SystemRootCharSize]);
} else if ((*ImagePath == '%') ||
( (Size > 3*sizeof(WCHAR)) && ImagePath[1] == TEXT(':')) )
{
//
// Looks like format B or format A
_tcscpy(Buffer, ImagePath);
} else if (_tcsnicmp(ImagePath,
QuestionPrefix,
QuestionPrefixSize) == 0)
{
//
// Looks like format E
_tcscpy(Buffer, ImagePath+QuestionPrefixSize);
} else {
//
// Assume format D
_tcscpy(Buffer, SystemRootDirectory);
_tcscat(Buffer, ImagePath);
}
}
Size = ExpandEnvironmentStrings(Buffer,
ImagePath,
MAX_PATH);
#ifdef MEMPHIS
WmipDebugPrint(("WMI: %s has mof in %s\n",
DriverName, ImagePath));
#else
WmipDebugPrint(("WMI: %ws has mof in %ws\n",
DriverName, ImagePath));
#endif
return(ImagePath);
}
ULONG WmipGetKmRegInfo(
HANDLE WmiKMHandle,
PKMREGINFO KMRegInfo,
BOOLEAN UpdateInfo,
PBYTE *RegistrationInfo,
ULONG RegInfoSize,
ULONG *RetSize
)
/*++
Routine Description:
This routine calls into the wmi device to query for new or updated
registration information.
Arguments:
WmiKMHandle is the WMI kernel mode service device handle
KMRegInfo is a pointer to the KM registration info
UpdateInfo is TRUE if caller is looking for update information or
FALSE if caller is looking for new registration information.
*RegistrationInfo on entry has a buffer that can be filled with registration
information. If this buffer is not large enough then a new buffer
is allocated and is returned in *RegInfo
RegInfoSize has the number of bytes available in *RegInfo on entry
*RetSize returns with the number of bytes returned from the IOCTL
Return Value:
ERROR_SUCCESS or an error code
--*/
{
OVERLAPPED Overlapped;
BOOL IoctlSuccess;
PBYTE RegInfo = *RegistrationInfo;
ULONG Status;
ULONG RetryCount = 0;
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (Overlapped.hEvent == NULL)
{
Status = GetLastError();
WmipDebugPrint(("WMI: Couldn't create event for RegInfo IOCTL %d\n",
Status));
return(Status);
}
KMRegInfo->Flags = UpdateInfo ? REGENTRY_FLAG_UPDREGINFO :
REGENTRY_FLAG_NEWREGINFO;
do
{
IoctlSuccess = DeviceIoControl(WmiKMHandle,
IOCTL_WMI_GET_REGINFO,
KMRegInfo,
sizeof(KMREGINFO),
RegInfo,
RegInfoSize,
RetSize,
&Overlapped);
if (GetLastError() == ERROR_IO_PENDING)
{
IoctlSuccess = GetOverlappedResult(WmiKMHandle,
&Overlapped,
RetSize,
TRUE);
}
if (IoctlSuccess)
{
Status = ERROR_SUCCESS;
if (*RetSize == sizeof(ULONG))
{
RegInfoSize = *((ULONG *)RegInfo);
if (RegInfo != *RegistrationInfo)
{
WmipFree(RegInfo);
}
RegInfo = WmipAlloc(RegInfoSize);
if (RegInfo == NULL)
{
Status = ERROR_NOT_ENOUGH_MEMORY;
}
}
} else {
Status = GetLastError();
}
} while (( (Status == ERROR_SUCCESS) &&
(*RetSize == sizeof(ULONG)) &&
(RetryCount++ < 4) ) ||
(Status == ERROR_WMI_TRY_AGAIN));
if ((Status == ERROR_SUCCESS) && (*RetSize == sizeof(ULONG)))
{
Status = ERROR_INSUFFICIENT_BUFFER;
}
*RegistrationInfo = RegInfo;
CloseHandle(Overlapped.hEvent);
return(Status);
}
void WmipUpdateKm(
HANDLE WmiKMHandle,
PKMREGINFO KMRegInfo
)
/*++
Routine Description:
This routine will query the KM data provider for its registration info
and then call to register it in the WMI data structures.
Arguments:
WmiKMHandle is the WMI kernel mode service device handle
KMRegInfo is a pointer to the KM registration info
Return Value:
--*/
{
BYTE RegInfoBuffer[INITIALREGINFOSIZE];
PBYTE RegInfo;
PBYTE RegInfoBase;
ULONG_PTR ProviderId;
WCHAR *RegistryPathPtr;
TCHAR *ImagePathPtr;
WCHAR RegistryPath[MAX_PATH];
TCHAR ImagePath[MAX_PATH];
PWMIREGINFOW WmiRegInfo;
ULONG RegistryPathSize;
ULONG Status;
ULONG RegistryPathOffset;
#ifdef MEMPHIS
PCHAR RegistryPathAnsi;
#endif
ULONG RetSizeLeft;
ULONG RetSize;
RegInfo = RegInfoBuffer;
Status = WmipGetKmRegInfo(WmiKMHandle,
KMRegInfo,
TRUE,
&RegInfo,
INITIALREGINFOSIZE,
&RetSize);
RegInfoBase = RegInfo;
if (Status == ERROR_SUCCESS)
{
ProviderId = KMRegInfo->ProviderId;
RetSizeLeft = RetSize;
do
{
WmiRegInfo = (PWMIREGINFOW)RegInfo;
if (WmiRegInfo->BufferSize > RetSizeLeft)
{
//
// If there not enough room left in the buffer for what the
// driver says is there then reject the buffer
WmipDebugPrint(("WMI: Invalid buffer size for registration info\n"));
goto Cleanup;
}
WmipUpdateDataSource(ProviderId,
WmiRegInfo,
RetSizeLeft);
if (WmiRegInfo->NextWmiRegInfo > RetSizeLeft)
{
WmipDebugPrint(("WMI: NextWmiRegInfo pointer is out of range\n"));
goto Cleanup;
}
RegInfo += WmiRegInfo->NextWmiRegInfo;
RetSizeLeft -= WmiRegInfo->NextWmiRegInfo;
} while (WmiRegInfo->NextWmiRegInfo != 0);
}
Cleanup:
if ((RegInfoBase != NULL) && (RegInfoBase != RegInfoBuffer))
{
WmipFree(RegInfoBase);
}
}
void WmipRegisterKm(
HANDLE WmiKMHandle,
PKMREGINFO KMRegInfo
)
/*++
Routine Description:
This routine will query the KM data provider for its registration info
and then call to register it in the WMI data structures.
Arguments:
WmiKMHandle is the WMI kernel mode service device handle
KMRegInfo is a pointer to the KM registration info
Return Value:
--*/
{
BYTE RegInfoBuffer[INITIALREGINFOSIZE];
PBYTE RegInfo;
PBYTE RegInfoBase;
ULONG_PTR ProviderId;
WCHAR *RegistryPathPtr;
TCHAR *ImagePathPtr;
WCHAR RegistryPath[MAX_PATH];
TCHAR ImagePath[MAX_PATH];
PWMIREGINFOW WmiRegInfo;
ULONG RegistryPathSize;
ULONG Status;
ULONG RegistryPathOffset;
#ifdef MEMPHIS
PCHAR RegistryPathAnsi;
#endif
ULONG RetSizeLeft;
ULONG RetSize;
RegInfo = RegInfoBuffer;
Status = WmipGetKmRegInfo(WmiKMHandle,
KMRegInfo,
FALSE,
&RegInfo,
INITIALREGINFOSIZE,
&RetSize);
RegInfoBase = RegInfo;
if (Status == ERROR_SUCCESS)
{
ProviderId = KMRegInfo->ProviderId;
RetSizeLeft = RetSize;
do
{
WmiRegInfo = (PWMIREGINFOW)RegInfo;
if (WmiRegInfo->BufferSize > RetSizeLeft)
{
//
// If there not enough room left in the buffer for what the
// driver says is there then reject the buffer
WmipDebugPrint(("WMI: Invalid buffer size for registration info\n"));
goto Cleanup;
}
ImagePathPtr = NULL;
RegistryPathOffset = WmiRegInfo->RegistryPath;
if (RegistryPathOffset > RetSize)
{
WmipDebugPrint(("WMI: Bogus KM RegInfo for %x\n",
KMRegInfo->ProviderId));
goto Cleanup;
}
if (RegistryPathOffset != 0)
{
RegistryPathPtr = (PWCHAR)OffsetToPtr(RegInfo, WmiRegInfo->RegistryPath);
RegistryPathSize = *RegistryPathPtr;
if (WmipValidateCountedString(RegistryPathPtr))
{
if ((RegistryPathSize < sizeof(RegistryPath)) &&
(RegistryPathSize != 0))
{
RegistryPathSize /= sizeof(WCHAR);
wcsncpy(RegistryPath, RegistryPathPtr+1, RegistryPathSize);
RegistryPath[RegistryPathSize] = UNICODE_NULL;
#ifdef MEMPHIS
RegistryPathAnsi = NULL;
Status = UnicodeToAnsi(RegistryPath,
&RegistryPathAnsi,
NULL);
if (Status != ERROR_SUCCESS)
{
WmipDebugPrint(("WMI: Error converting Registrypath to ansi\n"));
}
ImagePathPtr = WmipRegistryToImagePath(
ImagePath,
RegistryPathAnsi,
ProviderId);
if (RegistryPathAnsi != NULL)
{
WmipFree(RegistryPathAnsi);
}
#else
ImagePathPtr = WmipRegistryToImagePath(
ImagePath,
RegistryPath,
ProviderId);
#endif
} else {
WmipReportEventLog(EVENT_WMI_INVALID_REGPATH,
EVENTLOG_WARNING_TYPE,
0,
sizeof(UINT_PTR),
&ProviderId,
1,
RegistryPathPtr);
WmipDebugPrint(("WMI: Specified registry path is empty or too long %x\n",
RegistryPathPtr));
}
}
}
WmipAddDataSource(NULL,
0,
0,
ImagePathPtr,
WmiRegInfo,
RetSizeLeft,
&ProviderId,
FALSE);
if (WmiRegInfo->NextWmiRegInfo > RetSizeLeft)
{
WmipDebugPrint(("WMI: NextWmiRegInfo pointer is out of range\n"));
goto Cleanup;
}
RegInfo += WmiRegInfo->NextWmiRegInfo;
RetSizeLeft -= WmiRegInfo->NextWmiRegInfo;
} while (WmiRegInfo->NextWmiRegInfo != 0);
} else {
// Put something in eventlog
}
Cleanup:
if ((RegInfoBase != NULL) && (RegInfoBase != RegInfoBuffer))
{
WmipFree(RegInfoBase);
}
}
ULONG WmipInitializeKM(
HANDLE *WmiKMHandle
)
/*++
Routine Description:
Initialize access to kernel mode. Open the service device and query for
all registered KM drivers then query each driver for its registration
info and then try to register each driver in the user mode cache.
Arguments:
WmiKMHandle is the WMI kernel mode service device handle
KMRegInfo is a pointer to the KM registration info
Return Value:
--*/
{
ULONG i;
ULONG Status;
KMREGINFO KmRegInfoStatic[1];
PKMREGINFO KmRegInfo = KmRegInfoStatic;
ULONG KmRegInfoSize, KmRegInfoCount;
BOOL IoctlSuccess;
ULONG RetSize;
OVERLAPPED Overlapped;
//
// Open up the WMI service device
*WmiKMHandle = CreateFile(
WMIServiceDeviceName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
);
Status = GetLastError();
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (Overlapped.hEvent == NULL)
{
return(GetLastError());
}
KmRegInfoSize = sizeof(KmRegInfoStatic);
if (*WmiKMHandle != (HANDLE)-1)
{
//
// Loop querying the WMI device for registration info until we hit
// upon the right number of KMREGINFO
do
{
IoctlSuccess = DeviceIoControl(*WmiKMHandle,
IOCTL_WMI_GET_ALL_REGISTRANT,
NULL,
0,
KmRegInfo,
KmRegInfoSize,
&RetSize,
&Overlapped);
if (GetLastError() == ERROR_IO_PENDING)
{
IoctlSuccess = GetOverlappedResult(*WmiKMHandle,
&Overlapped,
&RetSize,
TRUE);
}
//
// If this succeeds, but only returns a ULONG then our buffer was
// too small and the ULONG has the size that we need
if (IoctlSuccess && (RetSize == sizeof(ULONG)))
{
KmRegInfoSize = *((ULONG *)KmRegInfo);
if (KmRegInfo != KmRegInfoStatic)
{
WmipFree(KmRegInfo);
}
KmRegInfo = WmipAlloc(KmRegInfoSize);
if (KmRegInfo == NULL)
{
WmipDebugPrint(("WMI: Couldn't alloc memory for KmRegInfo\n"));
CloseHandle(Overlapped.hEvent);
return(ERROR_NOT_ENOUGH_MEMORY);
}
} else {
break;
}
} while (TRUE);
if (IoctlSuccess)
{
//
// We have got the registration list, so process all of the
// registered drivers
KmRegInfoCount = RetSize / sizeof(KMREGINFO);
for (i = 0; i < KmRegInfoCount; i++)
{
WmipAssert(KmRegInfo[i].ProviderId != 0);
WmipRegisterKm(*WmiKMHandle, &KmRegInfo[i]);
}
Status = ERROR_SUCCESS;
} else {
Status = GetLastError();
WmipDebugPrint(("WMI: IOCTL_WMI_GET_ALL_REGISTRANT failed %x\n", Status));
CloseHandle(*WmiKMHandle);
*WmiKMHandle = (HANDLE)-1;
}
if (KmRegInfo != KmRegInfoStatic)
{
WmipFree(KmRegInfo);
}
} else {
WmipReportEventLog(EVENT_WMI_CANT_OPEN_DEVICE,
EVENTLOG_ERROR_TYPE,
0,
sizeof(ULONG),
&Status,
0);
WmipDebugPrint(("WMI: open service device failed %x\n", Status));
}
CloseHandle(Overlapped.hEvent);
return(Status);
}
void WmipKMNonEventNotification(
HANDLE WmiKMHandle,
PWNODE_HEADER Wnode
)
{
PKMREGINFO KMRegInfo;
//
// Is the buffer size correct ?
//
if (Wnode->BufferSize == INTERNALNOTIFICATIONSIZE)
{
//
// Make sure that correct notification type bits are set and only
// those bits are set
//
WmipAssert((Wnode->Version &
NOTIFICATIONSLOT_MASK_NOTIFICATIONTYPES) != 0);
WmipAssert((Wnode->Version &
~NOTIFICATIONSLOT_MASK_NOTIFICATIONTYPES) == 0)
//
// Registration notifications need to handled in a specific order.
// RegistrationDelete is always handled first and any other are
// ignored. If a device is unregistering we can ignore any updates.
// A RegistrationAdd is handled before a RegistrationUpdate.
//
KMRegInfo = (PKMREGINFO)((PCHAR)Wnode + sizeof(WNODE_HEADER));
if (Wnode->Version & RegistrationDelete)
{
WmipRemoveDataSource(KMRegInfo->ProviderId);
} else {
if (Wnode->Version & RegistrationAdd)
{
WmipRegisterKm(WmiKMHandle, KMRegInfo);
}
if (Wnode->Version & RegistrationUpdate)
{
WmipUpdateKm(WmiKMHandle, KMRegInfo);
}
}
} else {
WmipDebugPrint(("WMI: Invalid non event notification buffer %x\n",
Wnode));
}
}
#ifndef MEMPHIS
ULONG WmipSendWmiKMRequest(
ULONG Ioctl,
PVOID Buffer,
ULONG InBufferSize,
PVOID OutBuffer,
ULONG MaxBufferSize,
ULONG *ReturnSize
)
/*+++
Routine Description:
This routine does the work of sending WMI requests to the WMI kernel
mode service device. Any retry errors returned by the WMI device are
handled in this routine.
Arguments:
Ioctl is the IOCTL code to send to the WMI device
Buffer is the input and output buffer for the call to the WMI device
InBufferSize is the size of the buffer passed to the device
MaxBufferSize is the maximum number of bytes that can be written
into the buffer
*ReturnSize on return has the actual number of bytes written in buffer
Return Value:
ERROR_SUCCESS or an error code
---*/
{
OVERLAPPED Overlapped;
ULONG Status;
BOOL IoctlSuccess;
WmipAssert(WmipKMHandle != NULL);
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (Overlapped.hEvent == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
do
{
IoctlSuccess = DeviceIoControl(WmipKMHandle,
Ioctl,
Buffer,
InBufferSize,
OutBuffer,
MaxBufferSize,
ReturnSize,
&Overlapped);
if (GetLastError() == ERROR_IO_PENDING)
{
IoctlSuccess = GetOverlappedResult(WmipKMHandle,
&Overlapped,
ReturnSize,
TRUE);
}
if (! IoctlSuccess)
{
Status = GetLastError();
} else {
Status = ERROR_SUCCESS;
}
} while (Status == ERROR_WMI_TRY_AGAIN);
CloseHandle(Overlapped.hEvent);
return(Status);
}
#endif