xref: /reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp (revision cdf90707)
1 /*
2 * PROJECT:     ReactOS Device Manager
3 * LICENSE:     GPL - See COPYING in the top level directory
4 * FILE:        dll/win32/devmgr/devmgmt/ClassNode.cpp
5 * PURPOSE:     Class object for
6 * COPYRIGHT:   Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9 
10 #include "precomp.h"
11 #include "devmgmt.h"
12 #include "ClassNode.h"
13 
14 
15 CClassNode::CClassNode(
16     _In_ LPGUID ClassGuid,
17     _In_ PSP_CLASSIMAGELIST_DATA ImageListData
18     ) :
19     CNode(ClassNode, ImageListData)
20 {
21     CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID));
22 }
23 
24 
25 CClassNode::~CClassNode()
26 {
27 }
28 
29 
30 bool
31 CClassNode::SetupNode()
32 {
33     DWORD RequiredSize, Type, Size;
34     DWORD Success;
35     HKEY hKey;
36 
37     // Open the registry key for this class
38     hKey = SetupDiOpenClassRegKeyExW(&m_ClassGuid,
39                                      MAXIMUM_ALLOWED,
40                                      DIOCR_INSTALLER,
41                                      NULL,
42                                      0);
43     if (hKey != INVALID_HANDLE_VALUE)
44     {
45         // Lookup the class description (win7+)
46         Size = sizeof(m_DisplayName);
47         Success = RegQueryValueExW(hKey,
48                                    L"ClassDesc",
49                                    NULL,
50                                    &Type,
51                                    (LPBYTE)m_DisplayName,
52                                    &Size);
53         if (Success == ERROR_SUCCESS)
54         {
55             if (Type != REG_SZ)
56             {
57                 Success = ERROR_INVALID_DATA;
58             }
59             // Check if the string starts with an @
60             else if (m_DisplayName[0] == L'@')
61             {
62                 // The description is located in a module resource
63                 Success = ConvertResourceDescriptorToString(m_DisplayName, sizeof(m_DisplayName));
64             }
65         }
66         else if (Success == ERROR_FILE_NOT_FOUND)
67         {
68             // WinXP stores the description in the default value
69             Size = sizeof(m_DisplayName);
70             Success = RegQueryValueExW(hKey,
71                                        NULL,
72                                        NULL,
73                                        &Type,
74                                        (LPBYTE)m_DisplayName,
75                                        &Size);
76             if (Success == ERROR_SUCCESS && Type != REG_SZ)
77             {
78                 Success = ERROR_INVALID_DATA;
79             }
80         }
81 
82         // Close the registry key
83         RegCloseKey(hKey);
84     }
85     else
86     {
87         Success = GetLastError();
88     }
89 
90     // Check if we failed to get the class description
91     if (Success != ERROR_SUCCESS)
92     {
93         // Use the class name as the description
94         RequiredSize = _countof(m_DisplayName);
95         (VOID)SetupDiClassNameFromGuidW(&m_ClassGuid,
96                                         m_DisplayName,
97                                         RequiredSize,
98                                         &RequiredSize);
99     }
100 
101     // Get the image index for this class
102     (VOID)SetupDiGetClassImageIndex(m_ImageListData,
103                                     &m_ClassGuid,
104                                     &m_ClassImage);
105 
106     return true;
107 }
108 
109 
110 DWORD
111 CClassNode::ConvertResourceDescriptorToString(
112     _Inout_z_ LPWSTR ResourceDescriptor,
113     _In_ DWORD ResourceDescriptorSize
114     )
115 {
116     WCHAR ModulePath[MAX_PATH];
117     WCHAR ResString[256];
118     INT ResourceId;
119     HMODULE hModule;
120     LPWSTR ptr;
121     DWORD Size;
122     DWORD dwError;
123 
124     // First check for a semi colon */
125     ptr = wcschr(ResourceDescriptor, L';');
126     if (ptr)
127     {
128         // This must be an inf based descriptor, the desc is after the semi colon
129         StringCbCopyW(ResourceDescriptor, ResourceDescriptorSize, ++ptr);
130         dwError = ERROR_SUCCESS;
131     }
132     else
133     {
134         // This must be a dll resource based descriptor. Find the comma
135         ptr = wcschr(ResourceDescriptor, L',');
136         if (ptr == NULL)
137             return ERROR_INVALID_DATA;
138 
139         // Terminate the string where the comma was
140         *ptr = UNICODE_NULL;
141 
142         // Expand any environment strings
143         Size = ExpandEnvironmentStringsW(&ResourceDescriptor[1], ModulePath, MAX_PATH);
144         if (Size > MAX_PATH)
145             return ERROR_BUFFER_OVERFLOW;
146         if (Size == 0)
147             return GetLastError();
148 
149         // Put the comma back and move past it
150         *ptr = L',';
151         ptr++;
152 
153         // Load the dll
154         hModule = LoadLibraryExW(ModulePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
155         if (hModule == NULL)
156             return GetLastError();
157 
158         // Convert the resource id to a number
159         ResourceId = _wtoi(ptr);
160 
161         // If the number is negative, make it positive
162         if (ResourceId < 0)
163             ResourceId = -ResourceId;
164 
165         // Load the string from the dll
166         if (LoadStringW(hModule, ResourceId, ResString, 256))
167         {
168             StringCbCopyW(ResourceDescriptor, ResourceDescriptorSize, ResString);
169             dwError = ERROR_SUCCESS;
170         }
171         else
172         {
173             dwError = GetLastError();
174         }
175 
176         // Free the library
177         FreeLibrary(hModule);
178     }
179 
180     return dwError;
181 }
182