/*++ Copyright (c) 1997-1999 Microsoft Corporation Module Name: mofapi.c Abstract: WMI MOF access apis Author: 16-Jan-1997 AlanWar Revision History: --*/ #include "wmiump.h" ULONG WMIAPI WmiMofEnumerateResourcesA( IN MOFHANDLE MofResourceHandle, OUT ULONG *MofResourceCount, OUT PMOFRESOURCEINFOA *MofResourceInfo ) /*++ Routine Description: ANSI thunk to WMIMofEnumerateResourcesA --*/ { ULONG Status; PMOFRESOURCEINFOW MofResourceInfoUnicode; PMOFRESOURCEINFOA MofResourceInfoAnsi; PCHAR AnsiPtr; PCHAR Ansi; ULONG i, AnsiSize, AnsiStructureSize; ULONG MofResourceCountUnicode; ULONG AnsiLen; ULONG AnsiImagePathSize; ULONG AnsiResourceNameSize; WmipInitProcessHeap(); Status = WmiMofEnumerateResourcesW(MofResourceHandle, &MofResourceCountUnicode, &MofResourceInfoUnicode); if (Status == ERROR_SUCCESS) { // // Walk the unicode MOFRESOURCEINFOW to determine the ansi size needed // for all of the ansi MOFRESOURCEINFOA structures and strings. We // determine the entire size and allocate a single block that holds // all of it since that is what WMIMofEnumerateResourceInfoW does. AnsiStructureSize = MofResourceCountUnicode * sizeof(MOFRESOURCEINFOA); AnsiSize = AnsiStructureSize; for (i = 0; i < MofResourceCountUnicode; i++) { Status = AnsiSizeForUnicodeString(MofResourceInfoUnicode[i].ImagePath, &AnsiImagePathSize); if (Status != ERROR_SUCCESS) { goto Done; } Status = AnsiSizeForUnicodeString(MofResourceInfoUnicode[i].ResourceName, &AnsiResourceNameSize); if (Status != ERROR_SUCCESS) { goto Done; } AnsiSize += AnsiImagePathSize + AnsiResourceNameSize; } MofResourceInfoAnsi = WmipAlloc(AnsiSize); if (MofResourceInfoAnsi != NULL) { AnsiPtr = (PCHAR)((PUCHAR)MofResourceInfoAnsi + AnsiStructureSize); for (i = 0; i < MofResourceCountUnicode; i++) { MofResourceInfoAnsi[i].ResourceSize = MofResourceInfoUnicode[i].ResourceSize; MofResourceInfoAnsi[i].ResourceBuffer = MofResourceInfoUnicode[i].ResourceBuffer; MofResourceInfoAnsi[i].ImagePath = AnsiPtr; Status = UnicodeToAnsi(MofResourceInfoUnicode[i].ImagePath, &MofResourceInfoAnsi[i].ImagePath, &AnsiLen); if (Status != ERROR_SUCCESS) { break; } AnsiPtr += AnsiLen; MofResourceInfoAnsi[i].ResourceName = AnsiPtr; Status = UnicodeToAnsi(MofResourceInfoUnicode[i].ResourceName, &MofResourceInfoAnsi[i].ResourceName, &AnsiLen); if (Status != ERROR_SUCCESS) { break; } AnsiPtr += AnsiLen; } if (Status == ERROR_SUCCESS) { try { *MofResourceInfo = MofResourceInfoAnsi; } except(EXCEPTION_EXECUTE_HANDLER) { Status = ERROR_NOACCESS; WmipFree(MofResourceInfoAnsi); } } } else { // // Not enough memory for ansi thunking so free unicode // mof class info and return an error. Status = ERROR_NOT_ENOUGH_MEMORY; } Done: WmiFreeBuffer(MofResourceInfoUnicode); } SetLastError(Status); return(Status); } PTCHAR WmipRegistryToImagePath( PTCHAR ImagePath, PTCHAR RegistryPath ) /*++ 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; PTCHAR DriverName; ULONG Len; BOOLEAN DefaultImageName; PTCHAR DriversDirectoryPath; TCHAR *Buffer; TCHAR *FullRegistryPath; Buffer = (PTCHAR)WmipAlloc(2 * MAX_PATH * sizeof(TCHAR)); if (Buffer != NULL) { FullRegistryPath = Buffer + MAX_PATH; #ifdef MEMPHIS TCHAR Buffer2[MAX_PATH]; // // 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); WmipFree(Buffer); 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) { WmipDebugPrint(("WMI: Badly formed registry path %ws\n", RegistryPath)); WmipFree(Buffer); 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 WmipFree(Buffer); } else { ImagePath = NULL; } return(ImagePath); } typedef struct { ULONG Count; ULONG MaxCount; PWCHAR *List; } ENUMLANGCTX, *PENUMLANGCTX; BOOL EnumUILanguageCallback( LPWSTR Language, LONG_PTR Context ) { PENUMLANGCTX EnumLangCtx = (PENUMLANGCTX)Context; PWCHAR *p; PWCHAR w; ULONG NewMaxCount; if (EnumLangCtx->Count == EnumLangCtx->MaxCount) { NewMaxCount = EnumLangCtx->MaxCount * 2; p = WmipAlloc( sizeof(PWCHAR) * NewMaxCount); if (p != NULL) { memset(p, 0, sizeof(PWCHAR) * NewMaxCount); memcpy(p, EnumLangCtx->List, EnumLangCtx->Count * sizeof(PWCHAR)); WmipFree(EnumLangCtx->List); EnumLangCtx->List = p; EnumLangCtx->MaxCount = NewMaxCount; } else { return(FALSE); } } w = WmipAlloc( (wcslen(Language)+1) * sizeof(WCHAR) ); if (w != NULL) { EnumLangCtx->List[EnumLangCtx->Count++] = w; wcscpy(w, Language); } else { return(FALSE); } return(TRUE); } ULONG WmipGetLanguageList( PWCHAR **List, PULONG Count ) { ENUMLANGCTX EnumLangCtx; BOOL b; ULONG Status; *List = NULL; *Count = 0; EnumLangCtx.Count = 0; EnumLangCtx.MaxCount = 8; EnumLangCtx.List = WmipAlloc( 8 * sizeof(PWCHAR) ); if (EnumLangCtx.List != NULL) { b = EnumUILanguages(EnumUILanguageCallback, 0, (LONG_PTR)&EnumLangCtx); if (b) { *Count = EnumLangCtx.Count; *List = EnumLangCtx.List; Status = ERROR_SUCCESS; } else { if (EnumLangCtx.List != NULL) { WmipFree(EnumLangCtx.List); } Status = GetLastError(); } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } return(Status); } BOOLEAN WmipFileExists( PWCHAR FileName ) { HANDLE FindHandle; BOOLEAN Found; PWIN32_FIND_DATA FindData; FindData = (PWIN32_FIND_DATA)WmipAlloc(sizeof(WIN32_FIND_DATA)); if (FindData != NULL) { // // Now we need to make sure that the file a ctually exists // FindHandle = FindFirstFile(FileName, FindData); if (FindHandle == INVALID_HANDLE_VALUE) { Found = FALSE; } else { FindClose(FindHandle); Found = TRUE; } WmipFree(FindData); } else { Found = FALSE; } return(Found); } ULONG WmipGetWindowsDirectory( PWCHAR *s, PWCHAR Static, ULONG StaticSize ) { ULONG Size; ULONG Status = ERROR_SUCCESS; Size = GetWindowsDirectory(Static, StaticSize); if (Size > StaticSize) { Size += sizeof(UNICODE_NULL); *s = WmipAlloc(Size * sizeof(WCHAR)); if (*s != NULL) { Size = GetWindowsDirectory(*s, Size); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } } else if (Size == 0) { Status = GetLastError(); } else { *s = Static; } if (Status == ERROR_SUCCESS) { if ( (*s)[Size-1] == L'\\') { (*s)[Size-1] = 0; } } return(Status); } BOOLEAN WmipCopyMRString( PWCHAR Buffer, ULONG BufferRemaining, PULONG BufferUsed, PWCHAR SourceString ) { BOOLEAN BufferNotFull; ULONG len; len = wcslen(SourceString) + 1; if (len <= BufferRemaining) { wcscpy(Buffer, SourceString); *BufferUsed = len; BufferNotFull = TRUE; } else { BufferNotFull = FALSE; } return(BufferNotFull); } BOOLEAN WmipCopyCountedString( PUCHAR Base, PULONG Offset, PULONG BufferRemaining, PWCHAR SourceString ) { PWCHAR w; ULONG BufferUsed; ULONG BytesUsed; BOOLEAN BufferNotFull; if (*BufferRemaining > 1) { w = (PWCHAR)OffsetToPtr(Base, *Offset); (*BufferRemaining)--; BufferNotFull = WmipCopyMRString(w+1, *BufferRemaining, &BufferUsed, SourceString); if (BufferNotFull) { BytesUsed = BufferUsed * sizeof(WCHAR); *w = (USHORT)BytesUsed; (*BufferRemaining) -= BufferUsed; (*Offset) += BytesUsed + sizeof(USHORT); } } else { BufferNotFull = FALSE; } return(BufferNotFull); } ULONG WmipBuildMUIPath( PWCHAR Buffer, ULONG BufferRemaining, PULONG BufferUsed, PWCHAR EnglishPath, PWCHAR Language, PBOOLEAN BufferNotFull ) { #define FallbackDir L"\\MUI\\Fallback\\" #define MUIPath L"\\MUI\\" #define MUITail L".mui" ULONG EnglishLen; PWCHAR WinDir; PWCHAR s, p; ULONG len; ULONG Status, SizeNeeded; PWCHAR LanguagePath; PWCHAR WinDirStatic; WinDirStatic = WmipAlloc((MAX_PATH+1) * sizeof(WCHAR)); if (WinDirStatic != NULL) { Status = ERROR_FILE_NOT_FOUND; LanguagePath = Buffer; WmipDebugPrint(("WMI: Building MUI path for %ws in language %ws\n", EnglishPath, Language)); EnglishLen = wcslen(EnglishPath); p = EnglishPath + EnglishLen; len = EnglishLen; // // Work from the end of the string to try to find the last \ so // we can then slip in the language name // while ( (len != 0) && (*p != L'\\')) { len--; p--; } if (len != 0) { p++; } WmipDebugPrint(("WMI: Tail of %ws is %ws\n", EnglishPath, p)); // // First try looking in \\MUI\\ which is where 3rd // parties will install their resource only drivers. We look for // foo.sys and then foo.sys.mui. // SizeNeeded = len + wcslen(Language) + wcslen(MUIPath) + 1 + wcslen(p) + 1 + wcslen(MUITail); if (SizeNeeded <= BufferRemaining) { if (len != 0) { wcsncpy(LanguagePath, EnglishPath, len); LanguagePath[len] = 0; wcscat(LanguagePath, MUIPath); } else { LanguagePath[len] = 0; } wcscat(LanguagePath, Language); wcscat(LanguagePath, L"\\"); wcscat(LanguagePath, p); if (WmipFileExists(LanguagePath)) { *BufferUsed = wcslen(LanguagePath) + 1; *BufferNotFull = TRUE; Status = ERROR_SUCCESS; WmipDebugPrint(("WMI: #1 - Found %ws\n", LanguagePath)); } else { wcscat(LanguagePath, MUITail); if (WmipFileExists(LanguagePath)) { *BufferUsed = wcslen(LanguagePath) + 1; *BufferNotFull = TRUE; Status = ERROR_SUCCESS; WmipDebugPrint(("WMI: #2 - Found %ws\n", LanguagePath)); } } } else { *BufferNotFull = FALSE; Status = ERROR_SUCCESS; } if (Status != ERROR_SUCCESS) { // // Next lets check the fallback directory, // %windir%\MUI\Fallback\. This is where system components // are installed by default. // Status = WmipGetWindowsDirectory(&WinDir, WinDirStatic, sizeof(WinDirStatic)/ sizeof(WCHAR)); if (Status == ERROR_SUCCESS) { SizeNeeded = wcslen(WinDir) + wcslen(FallbackDir) + wcslen(Language) + 1 + wcslen(p) + 1 + wcslen(MUITail); if (SizeNeeded <= BufferRemaining) { wcscpy(LanguagePath, WinDir); wcscat(LanguagePath, FallbackDir); wcscat(LanguagePath, Language); wcscat(LanguagePath, L"\\"); wcscat(LanguagePath, p); wcscat(LanguagePath, MUITail); if ( WmipFileExists(LanguagePath)) { *BufferUsed = wcslen(LanguagePath) + 1; *BufferNotFull = TRUE; Status = ERROR_SUCCESS; WmipDebugPrint(("WMI: #3 - Found %ws\n", LanguagePath)); } else { Status = ERROR_FILE_NOT_FOUND; } } else { *BufferNotFull = FALSE; Status = ERROR_SUCCESS; } if (WinDir != WinDirStatic) { WmipFree(WinDir); } } } WmipFree(WinDirStatic); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } return(Status); } #if DBG #define MOFLISTSIZEGUESS 1 #else #define MOFLISTSIZEGUESS 10 #endif ULONG WmipGetMofResourceList( PWMIMOFLIST *MofListPtr ) { ULONG MofListSize; PWMIMOFLIST MofList; ULONG RetSize; ULONG Status; // // Make an intelligent guess as to the size needed to get all of // the MOF resources // *MofListPtr = NULL; MofListSize = MOFLISTSIZEGUESS * (sizeof(WMIMOFLIST) + (MAX_PATH + MAX_PATH) * sizeof(WCHAR)); MofList = WmipAlloc(MofListSize); if (MofList != NULL) { Status = WmipSendWmiKMRequest(NULL, IOCTL_WMI_ENUMERATE_MOF_RESOURCES, NULL, 0, MofList, MofListSize, &RetSize, NULL); if ((Status == ERROR_SUCCESS) && (RetSize == sizeof(ULONG))) { // // The buffer was too small, but we now know how much we'll // need. // MofListSize = MofList->MofListCount; WmipFree(MofList); MofList = WmipAlloc(MofListSize); if (MofList != NULL) { // // Now lets retry the query // Status = WmipSendWmiKMRequest(NULL, IOCTL_WMI_ENUMERATE_MOF_RESOURCES, NULL, 0, MofList, MofListSize, &RetSize, NULL); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } if (Status == ERROR_SUCCESS) { if (RetSize >= sizeof(WMIMOFLIST)) { *MofListPtr = MofList; } else { Status = ERROR_INVALID_PARAMETER; WmipFree(MofList); } } else if (MofList != NULL) { WmipFree(MofList); } return(Status); } ULONG WmiMofEnumerateResourcesW( IN MOFHANDLE MofResourceHandle, OUT ULONG *MofResourceCount, OUT PMOFRESOURCEINFOW *MofResourceInfo ) /*++ Routine Description: This routine will enumerate one or all of the MOF resources that are registered with WMI. Arguments: MofResourceHandle is reserved and must be 0 *MofResourceCount returns with the count of MOFRESOURCEINFO structures returned in *MofResourceInfo. *MofResourceInfo returns with a pointer to an array of MOFRESOURCEINFO structures. The caller MUST call WMIFreeBuffer with *MofResourceInfo in order to ensure that there are no memory leaks. Return Value: ERROR_SUCCESS or an error code --*/ { ULONG Status, SubStatus; PWMIMOFLIST MofList; ULONG MofListCount; ULONG MRInfoSize; ULONG MRCount; PWCHAR MRBuffer; PMOFRESOURCEINFOW MRInfo; PWCHAR RegPath, ResName, ImagePath; PWMIMOFENTRY MofEntry; ULONG i, j; PWCHAR *LanguageList; ULONG LanguageCount; BOOLEAN b; ULONG HeaderLen; ULONG MRBufferRemaining; PWCHAR ResourcePtr; ULONG BufferUsed; PWCHAR ImagePathStatic; WmipInitProcessHeap(); if (MofResourceHandle != 0) { SetLastError(ERROR_INVALID_PARAMETER); return(ERROR_INVALID_PARAMETER); } ImagePathStatic = WmipAlloc(MAX_PATH * sizeof(WCHAR)); if (ImagePathStatic != NULL) { *MofResourceInfo = NULL; Status = WmipGetMofResourceList(&MofList); if (Status == ERROR_SUCCESS) { // // Ok, we have got a valid list of mofs. Now we need to // loop over them all and convert the regpaths into image // paths // Status = WmipGetLanguageList(&LanguageList, &LanguageCount); if (Status == ERROR_SUCCESS) { MofListCount = MofList->MofListCount; // // Take a guess as to the size of the buffer needed to // satisfy the complete list of mof resources // HeaderLen = (MofListCount * (LanguageCount+1)) * sizeof(MOFRESOURCEINFOW); #if DBG MRInfoSize = HeaderLen + 2 * (MAX_PATH * sizeof(WCHAR)); #else MRInfoSize = HeaderLen + (2*MofListCount * (MAX_PATH * sizeof(WCHAR))); #endif MRInfo = NULL; do { TryAgain: if (MRInfo != NULL) { WmipDebugPrint(("WMI: MofList was too small, retry 0x%x bytes\n", MRInfoSize)); WmipFree(MRInfo); } MRInfo = WmipAlloc(MRInfoSize); if (MRInfo != NULL) { memset(MRInfo, 0, MRInfoSize); MRBuffer = (PWCHAR)OffsetToPtr(MRInfo, HeaderLen); MRBufferRemaining = (MRInfoSize - HeaderLen) / sizeof(WCHAR); MRCount = 0; for (i = 0; i < MofListCount; i++) { // // Pull out thee image path and resource names // MofEntry = &MofList->MofEntry[i]; RegPath = (PWCHAR)OffsetToPtr(MofList, MofEntry->RegPathOffset); ResName = (PWCHAR)OffsetToPtr(MofList, MofEntry->ResourceOffset); if (*ResName != 0) { if ((MofEntry->Flags & WMIMOFENTRY_FLAG_USERMODE) == 0) { ImagePath = WmipRegistryToImagePath(ImagePathStatic, RegPath); } else { ImagePath = RegPath; } if (ImagePath != NULL) { // // If we've got a valid image path then // out it and the resource name into the // output buffer // MRInfo[MRCount].ImagePath = MRBuffer; b = WmipCopyMRString(MRBuffer, MRBufferRemaining, &BufferUsed, ImagePath); if (! b) { // // The buffer was not big enough so we // double the size used and try again // MRInfoSize *= 2; goto TryAgain; } MRBuffer += BufferUsed; MRBufferRemaining -= BufferUsed; WmipDebugPrint(("WMI: Add ImagePath %p (%ws) to MRList at position %d\n", MRInfo[MRCount].ImagePath, MRInfo[MRCount].ImagePath, MRCount)); MRInfo[MRCount].ResourceName = MRBuffer; ResourcePtr = MRBuffer; WmipCopyMRString(MRBuffer, MRBufferRemaining, &BufferUsed, ResName); if (! b) { // // The buffer was not big enough so we // double the size used and try again // MRInfoSize *= 2; goto TryAgain; } MRBuffer += BufferUsed; MRBufferRemaining -= BufferUsed; WmipDebugPrint(("WMI: Add Resource %p (%ws) to MRList at position %d\n", MRInfo[MRCount].ResourceName, MRInfo[MRCount].ResourceName, MRCount)); MRCount++; for (j = 0; j < LanguageCount; j++) { MRInfo[MRCount].ImagePath = MRBuffer; SubStatus = WmipBuildMUIPath(MRBuffer, MRBufferRemaining, &BufferUsed, ImagePath, LanguageList[j], &b); if (SubStatus == ERROR_SUCCESS) { if (! b) { // // The buffer was not big enough so we // double the size used and try again // MRInfoSize *= 2; goto TryAgain; } MRBuffer += BufferUsed; MRBufferRemaining -= BufferUsed; WmipDebugPrint(("WMI: Add ImagePath %p (%ws) to MRList at position %d\n", MRInfo[MRCount].ImagePath, MRInfo[MRCount].ImagePath, MRCount)); // // We did find a MUI resource // so add it to the list // MRInfo[MRCount].ResourceName = ResourcePtr; WmipDebugPrint(("WMI: Add Resource %p (%ws) to MRList at position %d\n", MRInfo[MRCount].ResourceName, MRInfo[MRCount].ResourceName, MRCount)); MRCount++; } } } } } } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } while (FALSE); // // Free up memory used to hold the language list // for (i = 0; i < LanguageCount; i++) { WmipFree(LanguageList[i]); } WmipFree(LanguageList); *MofResourceCount = MRCount; *MofResourceInfo = MRInfo; } WmipFree(MofList); } WmipFree(ImagePathStatic); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } SetLastError(Status); return(Status); } ULONG WmipBuildMofAddRemoveEvent( IN PWNODE_SINGLE_INSTANCE WnodeSI, IN PWMIMOFLIST MofList, IN PWCHAR *LanguageList, IN ULONG LanguageCount, IN BOOLEAN IncludeNeutralLanguage, IN NOTIFICATIONCALLBACK Callback, IN ULONG_PTR DeliveryContext, IN BOOLEAN IsAnsi ) { PWNODE_ALL_DATA WnodeAD; ULONG BytesUsed, BufferUsed; BOOLEAN BufferNotFull; PWCHAR RegPath, ImagePath, ResourceName; ULONG SizeNeeded; ULONG InstanceCount, MaxInstanceCount; ULONG Status; ULONG Offset; POFFSETINSTANCEDATAANDLENGTH DataLenPtr; PWCHAR w; PULONG InstanceNamesOffsets; PWCHAR InstanceNames; ULONG BufferRemaining; ULONG i,j; PWMIMOFENTRY MofEntry; PWCHAR ImagePathStatic; WmipAssert(WnodeSI->WnodeHeader.Flags & WNODE_FLAG_SINGLE_INSTANCE); ImagePathStatic = WmipAlloc(MAX_PATH * sizeof(WCHAR)); if (ImagePathStatic != NULL) { // // Figure out how large the WNODE_ALL_DATA will need to be and // guess at how much space to allocate for the image paths and // resource names // if (IncludeNeutralLanguage) { MaxInstanceCount = (LanguageCount + 1); } else { MaxInstanceCount = LanguageCount; } MaxInstanceCount *= MofList->MofListCount; #if DBG SizeNeeded = sizeof(WNODE_ALL_DATA) + (MaxInstanceCount * (sizeof(ULONG) + // offset to instance name sizeof(USHORT) + // instance name length sizeof(OFFSETINSTANCEDATAANDLENGTH))) + 64; #else SizeNeeded = sizeof(WNODE_ALL_DATA) + (MaxInstanceCount * (sizeof(ULONG) + // offset to instance name sizeof(USHORT) + // instance name length sizeof(OFFSETINSTANCEDATAANDLENGTH))) + 0x1000; #endif WnodeAD = NULL; do { TryAgain: if (WnodeAD != NULL) { WmipFree(WnodeAD); } WnodeAD = WmipAlloc(SizeNeeded); if (WnodeAD != NULL) { // // Build up WNODE_ALL_DATA with all mof resources // memset(WnodeAD, 0, SizeNeeded); WnodeAD->WnodeHeader = WnodeSI->WnodeHeader; WnodeAD->WnodeHeader.Flags = WNODE_FLAG_ALL_DATA | WNODE_FLAG_EVENT_ITEM; WnodeAD->WnodeHeader.BufferSize = SizeNeeded; WnodeAD->WnodeHeader.Linkage = 0; // // Establish pointer to the data offset and length // structure and allocate space for all instances // Offset = FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength); DataLenPtr = (POFFSETINSTANCEDATAANDLENGTH)OffsetToPtr(WnodeAD, Offset); Offset = (Offset + (MaxInstanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH)) + 7) & ~7; // // Establish the instance name offsets and fill in // the empty instance names. Note we point them all // to the same offset which is an empty instance // name. // InstanceNamesOffsets = (PULONG)OffsetToPtr(WnodeAD, Offset); WnodeAD->OffsetInstanceNameOffsets = Offset; Offset = Offset + (MaxInstanceCount * sizeof(ULONG)); InstanceNames = (PWCHAR)OffsetToPtr(WnodeAD, Offset); *InstanceNames = 0; for (i = 0; i < MaxInstanceCount; i++) { InstanceNamesOffsets[i] = Offset; } // // Establish a pointer to the data block for all of // the instances // Offset = (Offset + (MaxInstanceCount * sizeof(USHORT)) + 7) & ~7; WnodeAD->DataBlockOffset = Offset; BufferRemaining = (SizeNeeded - Offset) / sizeof(WCHAR); InstanceCount = 0; // // Loop over all mof resources in list // for (j = 0; j < MofList->MofListCount; j++) { MofEntry = &MofList->MofEntry[j]; RegPath = (PWCHAR)OffsetToPtr(MofList, MofEntry->RegPathOffset); // // Convert regpath to image path if needed // if ((MofEntry->Flags & WMIMOFENTRY_FLAG_USERMODE) == 0) { ImagePath = WmipRegistryToImagePath(ImagePathStatic, RegPath+1); } else { ImagePath = RegPath; } if (ImagePath != NULL) { ResourceName = (PWCHAR)OffsetToPtr(MofList, MofEntry->ResourceOffset); // // Now lets go and build up the data for each // instance. First fill in the language neutral mof // if we are supposed to // if (IncludeNeutralLanguage) { DataLenPtr[InstanceCount].OffsetInstanceData = Offset; if ((! WmipCopyCountedString((PUCHAR)WnodeAD, &Offset, &BufferRemaining, ImagePath)) || (! WmipCopyCountedString((PUCHAR)WnodeAD, &Offset, &BufferRemaining, ResourceName))) { SizeNeeded *=2; goto TryAgain; } DataLenPtr[InstanceCount].LengthInstanceData = Offset - DataLenPtr[InstanceCount].OffsetInstanceData; InstanceCount++; // // We cheat here and do not align the offset on an // 8 byte boundry for the next data block since we // know the data type is a WCHAR and we know we are // on a 2 byte boundry. // } // // Now loop over and build language specific mof // resources // for (i = 0; i < LanguageCount; i++) { DataLenPtr[InstanceCount].OffsetInstanceData = Offset; if (BufferRemaining > 1) { w = (PWCHAR)OffsetToPtr(WnodeAD, Offset); Status = WmipBuildMUIPath(w+1, BufferRemaining - 1, &BufferUsed, ImagePath, LanguageList[i], &BufferNotFull); if (Status == ERROR_SUCCESS) { if (BufferNotFull) { BufferRemaining--; BytesUsed = BufferUsed * sizeof(WCHAR); *w = (USHORT)BytesUsed; BufferRemaining -= BufferUsed; Offset += (BytesUsed + sizeof(USHORT)); if (! WmipCopyCountedString((PUCHAR)WnodeAD, &Offset, &BufferRemaining, ResourceName)) { SizeNeeded *=2; goto TryAgain; } DataLenPtr[InstanceCount].LengthInstanceData = Offset - DataLenPtr[InstanceCount].OffsetInstanceData; // // We cheat here and do not align the offset on an // 8 byte boundry for the next data block since we // know the data type is a WCHAR and we know we are // on a 2 byte boundry. // InstanceCount++; } else { SizeNeeded *=2; goto TryAgain; } } } else { SizeNeeded *=2; goto TryAgain; } } } } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } } while (FALSE); if (WnodeAD != NULL) { WnodeAD->InstanceCount = InstanceCount; WmipMakeEventCallbacks((PWNODE_HEADER)WnodeAD, Callback, DeliveryContext, IsAnsi); WmipFree(WnodeAD); Status = ERROR_SUCCESS; } WmipFree(ImagePathStatic); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } return(Status); } void WmipProcessMofAddRemoveEvent( IN PWNODE_SINGLE_INSTANCE WnodeSI, IN NOTIFICATIONCALLBACK Callback, IN ULONG_PTR DeliveryContext, IN BOOLEAN IsAnsi ) { PWCHAR RegPath, ResourceName; PWCHAR *LanguageList; ULONG LanguageCount; ULONG Status; PWMIMOFLIST MofList; ULONG i; PWMIMOFENTRY MofEntry; ULONG Offset; ULONG SizeNeeded; PWCHAR w; RegPath = (PWCHAR)OffsetToPtr(WnodeSI, WnodeSI->DataBlockOffset); WmipAssert(*RegPath != 0); ResourceName = (PWCHAR)OffsetToPtr(WnodeSI, WnodeSI->DataBlockOffset + sizeof(USHORT) + *RegPath++ + sizeof(USHORT)); SizeNeeded = sizeof(WMIMOFLIST) + ((wcslen(RegPath) + (wcslen(ResourceName) + 2)) * sizeof(WCHAR)); MofList = (PWMIMOFLIST)WmipAlloc(SizeNeeded); if (MofList != NULL) { Status = WmipGetLanguageList(&LanguageList, &LanguageCount); if (Status == ERROR_SUCCESS) { MofList->MofListCount = 1; MofEntry = &MofList->MofEntry[0]; Offset = sizeof(WMIMOFLIST); MofEntry->RegPathOffset = Offset; w = (PWCHAR)OffsetToPtr(MofList, Offset); wcscpy(w, RegPath); Offset += (wcslen(RegPath) + 1) * sizeof(WCHAR); MofEntry->ResourceOffset = Offset; w = (PWCHAR)OffsetToPtr(MofList, Offset); wcscpy(w, ResourceName); if (WnodeSI->WnodeHeader.ProviderId == MOFEVENT_ACTION_REGISTRY_PATH) { MofEntry->Flags = 0; } else { MofEntry->Flags = WMIMOFENTRY_FLAG_USERMODE; } Status = WmipBuildMofAddRemoveEvent(WnodeSI, MofList, LanguageList, LanguageCount, TRUE, Callback, DeliveryContext, IsAnsi); // // Free up memory used to hold the language list // for (i = 0; i < LanguageCount; i++) { WmipFree(LanguageList[i]); } WmipFree(LanguageList); } WmipFree(MofList); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } if (Status != ERROR_SUCCESS) { // // If the WNODE_ALL_DATA event wasn't fired then just fire the // WNDOE_SINGLE_INSTANCE event so at least we get the language // neutral mof // WnodeSI->WnodeHeader.Flags &= ~WNODE_FLAG_INTERNAL; WmipMakeEventCallbacks((PWNODE_HEADER)WnodeSI, Callback, DeliveryContext, IsAnsi); } } void WmipProcessLanguageAddRemoveEvent( IN PWNODE_SINGLE_INSTANCE WnodeSI, IN NOTIFICATIONCALLBACK Callback, IN ULONG_PTR DeliveryContext, IN BOOLEAN IsAnsi ) { ULONG Status; PWMIMOFLIST MofList; PWCHAR Language; // // Get list of mof resources and build an event with the list of // resources for the language that is coming or going // Status = WmipGetMofResourceList(&MofList); if (Status == ERROR_SUCCESS) { Language = (PWCHAR)OffsetToPtr(WnodeSI, WnodeSI->DataBlockOffset + sizeof(USHORT)); Status = WmipBuildMofAddRemoveEvent(WnodeSI, MofList, &Language, 1, FALSE, Callback, DeliveryContext, IsAnsi); } }