xref: /reactos/dll/win32/devmgr/properties/misc.cpp (revision 627f3dc7)
1 /*
2  * ReactOS Device Manager Applet
3  * Copyright (C) 2004 - 2005 ReactOS Team
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 /*
20  * PROJECT:         ReactOS devmgr.dll
21  * FILE:            lib/devmgr/misc.c
22  * PURPOSE:         ReactOS Device Manager
23  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
24  * UPDATE HISTORY:
25  *      2005/11/24  Created
26  */
27 
28 #include "precomp.h"
29 #include "properties.h"
30 #include "resource.h"
31 
32 
33 INT
LengthOfStrResource(IN HINSTANCE hInst,IN UINT uID)34 LengthOfStrResource(IN HINSTANCE hInst,
35                     IN UINT uID)
36 {
37     HRSRC hrSrc;
38     HGLOBAL hRes;
39     LPWSTR lpName, lpStr;
40 
41     if (hInst == NULL)
42     {
43         return -1;
44     }
45 
46     /* There are always blocks of 16 strings */
47     lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
48 
49     /* Find the string table block */
50     if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
51         (hRes = LoadResource(hInst, hrSrc)) &&
52         (lpStr = (LPWSTR)LockResource(hRes)))
53     {
54         UINT x;
55 
56         /* Find the string we're looking for */
57         uID &= 0xF; /* position in the block, same as % 16 */
58         for (x = 0; x < uID; x++)
59         {
60             lpStr += (*lpStr) + 1;
61         }
62 
63         /* Found the string */
64         return (int)(*lpStr);
65     }
66     return -1;
67 }
68 
69 
70 static INT
AllocAndLoadString(OUT LPWSTR * lpTarget,IN HINSTANCE hInst,IN UINT uID)71 AllocAndLoadString(OUT LPWSTR *lpTarget,
72                    IN HINSTANCE hInst,
73                    IN UINT uID)
74 {
75     INT ln;
76 
77     ln = LengthOfStrResource(hInst,
78                              uID);
79     if (ln++ > 0)
80     {
81         (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
82                                          ln * sizeof(WCHAR));
83         if ((*lpTarget) != NULL)
84         {
85             INT Ret;
86             if (!(Ret = LoadStringW(hInst, uID, *lpTarget, ln)))
87             {
88                 LocalFree((HLOCAL)(*lpTarget));
89             }
90             return Ret;
91         }
92     }
93     return 0;
94 }
95 
96 
97 static INT
AllocAndLoadStringsCat(OUT LPWSTR * lpTarget,IN HINSTANCE hInst,IN UINT * uID,IN UINT nIDs)98 AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
99                        IN HINSTANCE hInst,
100                        IN UINT *uID,
101                        IN UINT nIDs)
102 {
103     INT ln = 0;
104     UINT i;
105 
106     for (i = 0;
107          i != nIDs;
108          i++)
109     {
110         ln += LengthOfStrResource(hInst,
111                                   uID[i]);
112     }
113 
114     if (ln != 0)
115     {
116         (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
117                                          (ln + 1) * sizeof(WCHAR));
118         if ((*lpTarget) != NULL)
119         {
120             LPWSTR s = *lpTarget;
121             INT Ret = 0;
122 
123             for (i = 0;
124                  i != nIDs;
125                  i++)
126             {
127                 if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
128                 {
129                     LocalFree((HLOCAL)(*lpTarget));
130                     return 0;
131                 }
132 
133                 s += Ret;
134             }
135 
136             return s - *lpTarget;
137         }
138     }
139     return 0;
140 }
141 
142 
143 DWORD
LoadAndFormatString(IN HINSTANCE hInstance,IN UINT uID,OUT LPWSTR * lpTarget,...)144 LoadAndFormatString(IN HINSTANCE hInstance,
145                     IN UINT uID,
146                     OUT LPWSTR *lpTarget,
147                     ...)
148 {
149     DWORD Ret = 0;
150     LPWSTR lpFormat;
151     va_list lArgs;
152 
153     if (AllocAndLoadString(&lpFormat,
154                            hInstance,
155                            uID) != 0)
156     {
157         va_start(lArgs, lpTarget);
158         /* let's use FormatMessage to format it because it has the ability to allocate
159            memory automatically */
160         Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
161                              lpFormat,
162                              0,
163                              0,
164                              (LPWSTR)lpTarget,
165                              0,
166                              &lArgs);
167         va_end(lArgs);
168 
169         LocalFree((HLOCAL)lpFormat);
170     }
171 
172     return Ret;
173 }
174 
175 
176 DWORD
LoadAndFormatStringsCat(IN HINSTANCE hInstance,IN UINT * uID,IN UINT nIDs,OUT LPWSTR * lpTarget,...)177 LoadAndFormatStringsCat(IN HINSTANCE hInstance,
178                         IN UINT *uID,
179                         IN UINT nIDs,
180                         OUT LPWSTR *lpTarget,
181                         ...)
182 {
183     DWORD Ret = 0;
184     LPWSTR lpFormat;
185     va_list lArgs;
186 
187     if (AllocAndLoadStringsCat(&lpFormat,
188                                hInstance,
189                                uID,
190                                nIDs) != 0)
191     {
192         va_start(lArgs, lpTarget);
193         /* let's use FormatMessage to format it because it has the ability to allocate
194            memory automatically */
195         Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
196                              lpFormat,
197                              0,
198                              0,
199                              (LPWSTR)lpTarget,
200                              0,
201                              &lArgs);
202         va_end(lArgs);
203 
204         LocalFree((HLOCAL)lpFormat);
205     }
206 
207     return Ret;
208 }
209 
210 
211 LPARAM
ListViewGetSelectedItemData(IN HWND hwnd)212 ListViewGetSelectedItemData(IN HWND hwnd)
213 {
214     int Index;
215 
216     Index = ListView_GetNextItem(hwnd,
217                                  -1,
218                                  LVNI_SELECTED);
219     if (Index != -1)
220     {
221         LVITEM li;
222 
223         li.mask = LVIF_PARAM;
224         li.iItem = Index;
225         li.iSubItem = 0;
226 
227         if (ListView_GetItem(hwnd,
228                              &li))
229         {
230             return li.lParam;
231         }
232     }
233 
234     return 0;
235 }
236 
237 
238 LPWSTR
ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,IN UINT uCodePage)239 ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
240                           IN UINT uCodePage)
241 {
242     LPWSTR lpUnicodeStr;
243     INT nLength;
244 
245     nLength = MultiByteToWideChar(uCodePage,
246                                   0,
247                                   lpMultiByteStr,
248                                   -1,
249                                   NULL,
250                                   0);
251     if (nLength == 0)
252         return NULL;
253 
254     lpUnicodeStr = (LPWSTR)HeapAlloc(GetProcessHeap(),
255                                      0,
256                                      nLength * sizeof(WCHAR));
257     if (lpUnicodeStr == NULL)
258     {
259         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
260         return NULL;
261     }
262 
263     if (!MultiByteToWideChar(uCodePage,
264                              0,
265                              lpMultiByteStr,
266                              nLength,
267                              lpUnicodeStr,
268                              nLength))
269     {
270         HeapFree(GetProcessHeap(),
271                  0,
272                  lpUnicodeStr);
273         return NULL;
274     }
275 
276     return lpUnicodeStr;
277 }
278 
279 
280 BOOL
GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,OUT LPWSTR szBuffer,IN DWORD BufferSize)281 GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
282                             IN PSP_DEVINFO_DATA DeviceInfoData,
283                             OUT LPWSTR szBuffer,
284                             IN DWORD BufferSize)
285 {
286     DWORD RegDataType;
287     BOOL Ret = FALSE;
288 
289     if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
290                                           DeviceInfoData,
291                                           SPDRP_MFG,
292                                           &RegDataType,
293                                           (PBYTE)szBuffer,
294                                           BufferSize * sizeof(WCHAR),
295                                           NULL) ||
296         RegDataType != REG_SZ)
297     {
298         szBuffer[0] = L'\0';
299         if (LoadString(hDllInstance,
300                        IDS_UNKNOWN,
301                        szBuffer,
302                        BufferSize))
303         {
304             Ret = TRUE;
305         }
306     }
307     else
308     {
309         /* FIXME - check string for NULL termination! */
310         Ret = TRUE;
311     }
312 
313     return Ret;
314 }
315 
316 
317 BOOL
GetDeviceLocationString(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,IN DEVINST dnParentDevInst OPTIONAL,OUT LPWSTR szBuffer,IN DWORD BufferSize)318 GetDeviceLocationString(IN HDEVINFO DeviceInfoSet,
319                         IN PSP_DEVINFO_DATA DeviceInfoData,
320                         IN DEVINST dnParentDevInst  OPTIONAL,
321                         OUT LPWSTR szBuffer,
322                         IN DWORD BufferSize)
323 {
324     DWORD RegDataType;
325     ULONG DataSize;
326     CONFIGRET cRet;
327     LPWSTR szFormatted;
328     HKEY hKey;
329     DWORD dwSize, dwType;
330     BOOL Ret = FALSE;
331 
332     DataSize = BufferSize * sizeof(WCHAR);
333     szBuffer[0] = L'\0';
334 
335     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
336                                 DeviceInfoData,
337                                 DICS_FLAG_GLOBAL,
338                                 0,
339                                 DIREG_DRV,
340                                 KEY_QUERY_VALUE);
341     if (hKey != INVALID_HANDLE_VALUE)
342     {
343         /* query the LocationInformationOverride value */
344         dwSize = BufferSize;
345         if (RegQueryValueEx(hKey,
346                             L"LocationInformationOverride",
347                             NULL,
348                             &dwType,
349                             (LPBYTE)szBuffer,
350                             &dwSize) == ERROR_SUCCESS &&
351             dwType == REG_SZ &&
352             szBuffer[0] != L'\0')
353         {
354             Ret = TRUE;
355         }
356         else
357         {
358             szBuffer[0] = L'\0';
359         }
360 
361         RegCloseKey(hKey);
362     }
363 
364 
365     if (!Ret)
366     {
367         if (dnParentDevInst != 0)
368         {
369             /* query the parent node name */
370             if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
371                                                  CM_DRP_DEVICEDESC,
372                                                  &RegDataType,
373                                                  szBuffer,
374                                                  &DataSize,
375                                                  0) == CR_SUCCESS &&
376                  RegDataType == REG_SZ &&
377                  LoadAndFormatString(hDllInstance,
378                                      IDS_DEVONPARENT,
379                                      &szFormatted,
380                                      szBuffer) != 0)
381             {
382                 wcsncpy(szBuffer,
383                         szFormatted,
384                         BufferSize - 1);
385                 szBuffer[BufferSize - 1] = L'\0';
386                 LocalFree((HLOCAL)szFormatted);
387                 Ret = TRUE;
388             }
389         }
390         else if (DeviceInfoData->DevInst != 0)
391         {
392             cRet = CM_Get_DevNode_Registry_Property(DeviceInfoData->DevInst,
393                                                     CM_DRP_LOCATION_INFORMATION,
394                                                     &RegDataType,
395                                                     szBuffer,
396                                                     &DataSize,
397                                                     0);
398             if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
399             {
400                 /* FIXME - check string for NULL termination! */
401                 Ret = TRUE;
402             }
403 
404             if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
405             {
406                 /* convert the string to an integer value and create a
407                    formatted string */
408                 ULONG ulLocation = (ULONG)wcstoul(szBuffer,
409                                                   NULL,
410                                                   10);
411                 if (LoadAndFormatString(hDllInstance,
412                                         IDS_LOCATIONSTR,
413                                         &szFormatted,
414                                         ulLocation,
415                                         szBuffer) != 0)
416                 {
417                     wcsncpy(szBuffer,
418                             szFormatted,
419                             BufferSize - 1);
420                     szBuffer[BufferSize - 1] = L'\0';
421                     LocalFree((HLOCAL)szFormatted);
422                 }
423                 else
424                     Ret = FALSE;
425             }
426         }
427     }
428 
429     if (!Ret &&
430         LoadString(hDllInstance,
431                    IDS_UNKNOWN,
432                    szBuffer,
433                    BufferSize))
434     {
435         Ret = TRUE;
436     }
437 
438     return Ret;
439 }
440 
441 
442 BOOL
GetDeviceStatusString(IN DEVINST DevInst,IN HMACHINE hMachine,OUT LPWSTR szBuffer,IN DWORD BufferSize)443 GetDeviceStatusString(IN DEVINST DevInst,
444                       IN HMACHINE hMachine,
445                       OUT LPWSTR szBuffer,
446                       IN DWORD BufferSize)
447 {
448     CONFIGRET cr;
449     ULONG Status, ProblemNumber;
450     UINT MessageId = IDS_UNKNOWN;
451     BOOL Ret = FALSE;
452 
453     szBuffer[0] = L'\0';
454     cr = CM_Get_DevNode_Status_Ex(&Status,
455                                   &ProblemNumber,
456                                   DevInst,
457                                   0,
458                                   hMachine);
459     if (cr == CR_SUCCESS)
460     {
461         if (Status & DN_HAS_PROBLEM)
462         {
463             UINT uRet;
464 
465             uRet = DeviceProblemTextW(hMachine,
466                                      DevInst,
467                                      ProblemNumber,
468                                      szBuffer,
469                                      (BufferSize != 0 ? BufferSize : BufferSize - 1));
470 
471             Ret = (uRet != 0 && uRet < BufferSize);
472         }
473         else
474         {
475             if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
476             {
477                 MessageId = IDS_NODRIVERLOADED;
478             }
479             else
480             {
481                 MessageId = IDS_DEV_NO_PROBLEM;
482             }
483 
484             goto GeneralMessage;
485         }
486     }
487     else
488     {
489 GeneralMessage:
490         if (LoadString(hDllInstance,
491                         MessageId,
492                         szBuffer,
493                         (int)BufferSize))
494         {
495             Ret = TRUE;
496         }
497     }
498 
499     return Ret;
500 }
501 
502 
503 BOOL
GetDriverProviderString(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,OUT LPWSTR szBuffer,IN DWORD BufferSize)504 GetDriverProviderString(IN HDEVINFO DeviceInfoSet,
505                         IN PSP_DEVINFO_DATA DeviceInfoData,
506                         OUT LPWSTR szBuffer,
507                         IN DWORD BufferSize)
508 {
509     HKEY hKey;
510     DWORD dwSize, dwType;
511     BOOL Ret = FALSE;
512 
513     szBuffer[0] = L'\0';
514 
515     /* get driver provider, date and version */
516     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
517                                 DeviceInfoData,
518                                 DICS_FLAG_GLOBAL,
519                                 0,
520                                 DIREG_DRV,
521                                 KEY_QUERY_VALUE);
522     if (hKey != INVALID_HANDLE_VALUE)
523     {
524         /* query the driver provider */
525         dwSize = BufferSize;
526         if (RegQueryValueEx(hKey,
527                             REGSTR_VAL_PROVIDER_NAME,
528                             NULL,
529                             &dwType,
530                             (LPBYTE)szBuffer,
531                             &dwSize) == ERROR_SUCCESS &&
532             dwType == REG_SZ &&
533             szBuffer[0] != L'\0')
534         {
535             Ret = TRUE;
536         }
537         else
538         {
539             szBuffer[0] = L'\0';
540         }
541 
542         RegCloseKey(hKey);
543     }
544 
545     if (szBuffer[0] == L'\0')
546     {
547         /* unable to query the information */
548         if (LoadString(hDllInstance,
549                        IDS_UNKNOWN,
550                        szBuffer,
551                        BufferSize))
552         {
553             Ret = TRUE;
554         }
555     }
556 
557     return Ret;
558 }
559 
560 
561 BOOL
GetDriverVersionString(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,OUT LPWSTR szBuffer,IN DWORD BufferSize)562 GetDriverVersionString(IN HDEVINFO DeviceInfoSet,
563                        IN PSP_DEVINFO_DATA DeviceInfoData,
564                        OUT LPWSTR szBuffer,
565                        IN DWORD BufferSize)
566 {
567     HKEY hKey;
568     DWORD dwSize, dwType;
569     BOOL Ret = FALSE;
570 
571     szBuffer[0] = L'\0';
572 
573     /* get driver provider, date and version */
574     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
575                                 DeviceInfoData,
576                                 DICS_FLAG_GLOBAL,
577                                 0,
578                                 DIREG_DRV,
579                                 KEY_QUERY_VALUE);
580     if (hKey != INVALID_HANDLE_VALUE)
581     {
582         /* query the driver provider */
583         dwSize = BufferSize;
584         if (RegQueryValueEx(hKey,
585                             L"DriverVersion",
586                             NULL,
587                             &dwType,
588                             (LPBYTE)szBuffer,
589                             &dwSize) == ERROR_SUCCESS &&
590             dwType == REG_SZ &&
591             szBuffer[0] != L'\0')
592         {
593             Ret = TRUE;
594         }
595         else
596         {
597             szBuffer[0] = L'\0';
598         }
599 
600         RegCloseKey(hKey);
601     }
602 
603     if (szBuffer[0] == L'\0')
604     {
605         /* unable to query the information */
606         if (LoadString(hDllInstance,
607                        IDS_NOTAVAILABLE,
608                        szBuffer,
609                        BufferSize))
610         {
611             Ret = TRUE;
612         }
613     }
614 
615     return Ret;
616 }
617 
618 BOOL
GetDriverDateString(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,OUT LPWSTR szBuffer,IN DWORD BufferSize)619 GetDriverDateString(IN HDEVINFO DeviceInfoSet,
620                     IN PSP_DEVINFO_DATA DeviceInfoData,
621                     OUT LPWSTR szBuffer,
622                     IN DWORD BufferSize)
623 {
624     HKEY hKey;
625     FILETIME DriverDate;
626     SYSTEMTIME SystemTime, LocalTime;
627     DWORD dwSize, dwType;
628     BOOL Ret = FALSE;
629 
630     szBuffer[0] = L'\0';
631 
632     /* get driver provider, date and version */
633     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
634                                 DeviceInfoData,
635                                 DICS_FLAG_GLOBAL,
636                                 0,
637                                 DIREG_DRV,
638                                 KEY_QUERY_VALUE);
639     if (hKey != INVALID_HANDLE_VALUE)
640     {
641         /* query the driver provider */
642         dwSize = sizeof(FILETIME);
643         if (RegQueryValueEx(hKey,
644                             L"DriverDateData",
645                             NULL,
646                             &dwType,
647                             (LPBYTE)&DriverDate,
648                             &dwSize) == ERROR_SUCCESS &&
649             dwType == REG_BINARY &&
650             dwSize == sizeof(FILETIME) &&
651             FileTimeToSystemTime(&DriverDate,
652                                  &SystemTime) &&
653             SystemTimeToTzSpecificLocalTime(NULL,
654                                             &SystemTime,
655                                             &LocalTime) &&
656             GetDateFormat(LOCALE_USER_DEFAULT,
657                           DATE_SHORTDATE,
658                           &LocalTime,
659                           NULL,
660                           szBuffer,
661                           BufferSize) != 0)
662         {
663             Ret = TRUE;
664         }
665 
666         RegCloseKey(hKey);
667     }
668 
669     if (!Ret)
670     {
671         /* unable to query the information */
672         if (LoadString(hDllInstance,
673                        IDS_NOTAVAILABLE,
674                        szBuffer,
675                        BufferSize))
676         {
677             Ret = TRUE;
678         }
679     }
680 
681     return Ret;
682 }
683 
684 
685 
686 BOOL
IsDeviceHidden(IN DEVINST DevInst,IN HMACHINE hMachine,OUT BOOL * IsHidden)687 IsDeviceHidden(IN DEVINST DevInst,
688                IN HMACHINE hMachine,
689                OUT BOOL *IsHidden)
690 {
691     CONFIGRET cr;
692     ULONG Status, ProblemNumber;
693     BOOL Ret = FALSE;
694 
695     cr = CM_Get_DevNode_Status_Ex(&Status,
696                                   &ProblemNumber,
697                                   DevInst,
698                                   0,
699                                   hMachine);
700     if (cr == CR_SUCCESS)
701     {
702         *IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
703         Ret = TRUE;
704     }
705 
706     return Ret;
707 }
708 
709 
710 BOOL
CanDisableDevice(IN DEVINST DevInst,IN HMACHINE hMachine,OUT BOOL * CanDisable)711 CanDisableDevice(IN DEVINST DevInst,
712                  IN HMACHINE hMachine,
713                  OUT BOOL *CanDisable)
714 {
715     CONFIGRET cr;
716     ULONG Status, ProblemNumber;
717     BOOL Ret = FALSE;
718 
719     cr = CM_Get_DevNode_Status_Ex(&Status,
720                                   &ProblemNumber,
721                                   DevInst,
722                                   0,
723                                   hMachine);
724     if (cr == CR_SUCCESS)
725     {
726         *CanDisable = ((Status & DN_DISABLEABLE) != 0);
727         Ret = TRUE;
728     }
729 
730     return Ret;
731 }
732 
733 
734 BOOL
IsDeviceStarted(IN DEVINST DevInst,IN HMACHINE hMachine,OUT BOOL * IsStarted)735 IsDeviceStarted(IN DEVINST DevInst,
736                 IN HMACHINE hMachine,
737                 OUT BOOL *IsStarted)
738 {
739     CONFIGRET cr;
740     ULONG Status, ProblemNumber;
741     BOOL Ret = FALSE;
742 
743     cr = CM_Get_DevNode_Status_Ex(&Status,
744                                   &ProblemNumber,
745                                   DevInst,
746                                   0,
747                                   hMachine);
748     if (cr == CR_SUCCESS)
749     {
750         *IsStarted = ((Status & DN_STARTED) != 0);
751         Ret = TRUE;
752     }
753 
754     return Ret;
755 }
756 
757 
758 BOOL
IsDriverInstalled(IN DEVINST DevInst,IN HMACHINE hMachine,OUT BOOL * Installed)759 IsDriverInstalled(IN DEVINST DevInst,
760                   IN HMACHINE hMachine,
761                   OUT BOOL *Installed)
762 {
763     CONFIGRET cr;
764     ULONG Status, ProblemNumber;
765     BOOL Ret = FALSE;
766 
767     cr = CM_Get_DevNode_Status_Ex(&Status,
768                                   &ProblemNumber,
769                                   DevInst,
770                                   0,
771                                   hMachine);
772     if (cr == CR_SUCCESS)
773     {
774         *Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
775                       (Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
776         Ret = TRUE;
777     }
778 
779     return Ret;
780 }
781 
782 
783 BOOL
EnableDevice(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,IN BOOL bEnable,IN DWORD HardwareProfile OPTIONAL,OUT BOOL * bNeedReboot OPTIONAL)784 EnableDevice(IN HDEVINFO DeviceInfoSet,
785              IN PSP_DEVINFO_DATA DevInfoData  OPTIONAL,
786              IN BOOL bEnable,
787              IN DWORD HardwareProfile  OPTIONAL,
788              OUT BOOL *bNeedReboot  OPTIONAL)
789 {
790     SP_PROPCHANGE_PARAMS pcp;
791     SP_DEVINSTALL_PARAMS dp;
792     DWORD LastErr;
793     BOOL Ret = FALSE;
794 
795     pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
796     pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
797     pcp.HwProfile = HardwareProfile;
798 
799     if (bEnable)
800     {
801         /* try to enable the device on the global profile */
802         pcp.StateChange = DICS_ENABLE;
803         pcp.Scope = DICS_FLAG_GLOBAL;
804 
805         /* ignore errors */
806         LastErr = GetLastError();
807         if (SetupDiSetClassInstallParams(DeviceInfoSet,
808                                          DevInfoData,
809                                          &pcp.ClassInstallHeader,
810                                          sizeof(SP_PROPCHANGE_PARAMS)))
811         {
812             SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
813                                       DeviceInfoSet,
814                                       DevInfoData);
815         }
816         SetLastError(LastErr);
817     }
818 
819     /* try config-specific */
820     pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
821     pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
822 
823     if (SetupDiSetClassInstallParams(DeviceInfoSet,
824                                      DevInfoData,
825                                      &pcp.ClassInstallHeader,
826                                      sizeof(SP_PROPCHANGE_PARAMS)) &&
827         SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
828                                   DeviceInfoSet,
829                                   DevInfoData))
830     {
831         dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
832         if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
833                                           DevInfoData,
834                                           &dp))
835         {
836             if (bNeedReboot != NULL)
837             {
838                 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
839             }
840 
841             Ret = TRUE;
842         }
843     }
844     return Ret;
845 }
846 
847 
848 BOOL
GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,OUT LPWSTR szBuffer,IN DWORD BufferSize)849 GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
850                     OUT LPWSTR szBuffer,
851                     IN DWORD BufferSize)
852 {
853     BOOL Ret = FALSE;
854 
855     if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
856                                     szBuffer,
857                                     BufferSize,
858                                     NULL))
859     {
860         szBuffer[0] = L'\0';
861         if (LoadString(hDllInstance,
862                        IDS_UNKNOWN,
863                        szBuffer,
864                        BufferSize))
865         {
866             Ret = TRUE;
867         }
868     }
869     else
870     {
871         /* FIXME - check string for NULL termination! */
872         Ret = TRUE;
873     }
874 
875     return Ret;
876 }
877 
878 
879 BOOL
GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,OUT LPWSTR szBuffer,IN DWORD BufferSize)880 GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
881                            IN PSP_DEVINFO_DATA DeviceInfoData,
882                            OUT LPWSTR szBuffer,
883                            IN DWORD BufferSize)
884 {
885     DWORD RegDataType;
886     BOOL Ret = FALSE;
887 
888     if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
889                                           DeviceInfoData,
890                                           SPDRP_FRIENDLYNAME,
891                                           &RegDataType,
892                                           (PBYTE)szBuffer,
893                                           BufferSize * sizeof(WCHAR),
894                                           NULL) ||
895          SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
896                                           DeviceInfoData,
897                                           SPDRP_DEVICEDESC,
898                                           &RegDataType,
899                                           (PBYTE)szBuffer,
900                                           BufferSize * sizeof(WCHAR),
901                                           NULL)) &&
902         RegDataType == REG_SZ)
903     {
904         /* FIXME - check string for NULL termination! */
905         Ret = TRUE;
906     }
907     else
908     {
909         szBuffer[0] = L'\0';
910         if (LoadString(hDllInstance,
911                        IDS_UNKNOWNDEVICE,
912                        szBuffer,
913                        BufferSize))
914         {
915             Ret = TRUE;
916         }
917     }
918 
919     return Ret;
920 }
921 
922 
923 BOOL
FindCurrentDriver(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,OUT PSP_DRVINFO_DATA DriverInfoData)924 FindCurrentDriver(IN HDEVINFO DeviceInfoSet,
925                   IN PSP_DEVINFO_DATA DeviceInfoData,
926                   OUT PSP_DRVINFO_DATA DriverInfoData)
927 {
928     HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
929     SP_DEVINSTALL_PARAMS InstallParams = {0};
930     SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = {0};
931     WCHAR InfPath[MAX_PATH];
932     WCHAR InfSection[LINE_LEN];
933     DWORD dwType, dwLength;
934     DWORD i = 0;
935     LONG rc;
936     BOOL Ret = FALSE;
937 
938     /* Steps to find the right driver:
939      * 1) Get the device install parameters
940      * 2) Open the driver registry key
941      * 3) Read the .inf file name
942      * 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name
943      * 5) Build class driver list
944      * 6) Read inf section and inf section extension from registry
945      * 7) Enumerate drivers
946      * 8) Find the one who is in the same section as current driver?
947      */
948 
949     /* 1) Get the install params */
950     InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
951     if (!SetupDiGetDeviceInstallParams(DeviceInfoSet,
952                                        DeviceInfoData,
953                                        &InstallParams))
954     {
955         ERR("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
956         goto Cleanup;
957     }
958 
959 #ifdef DI_FLAGSEX_INSTALLEDDRIVER
960     InstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
961     if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
962                                       DeviceInfoData,
963                                       &InstallParams))
964     {
965         if (SetupDiBuildDriverInfoList(DeviceInfoSet,
966                                        DeviceInfoData,
967                                        SPDIT_CLASSDRIVER) &&
968             SetupDiEnumDriverInfo(DeviceInfoSet,
969                                   DeviceInfoData,
970                                   SPDIT_CLASSDRIVER,
971                                   0,
972                                   DriverInfoData))
973         {
974             Ret = TRUE;
975         }
976 
977         goto Cleanup;
978     }
979     InstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
980 #endif
981 
982     /* 2) Open the driver registry key */
983     hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
984                                 DeviceInfoData,
985                                 DICS_FLAG_GLOBAL,
986                                 0,
987                                 DIREG_DRV,
988                                 KEY_QUERY_VALUE);
989     if (hKey == INVALID_HANDLE_VALUE)
990     {
991         ERR("SetupDiOpenDevRegKey() failed with error 0x%lx\n", GetLastError());
992         goto Cleanup;
993     }
994 
995     /* 3) Read the .inf file name */
996     dwLength = (sizeof(InfPath) / sizeof(InfPath[0])) - 1;
997     rc = RegQueryValueEx(hKey,
998                          REGSTR_VAL_INFPATH,
999                          0,
1000                          &dwType,
1001                          (LPBYTE)InfPath,
1002                          &dwLength);
1003     if (rc != ERROR_SUCCESS)
1004     {
1005         ERR("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
1006         SetLastError(rc);
1007         goto Cleanup;
1008     }
1009     else if (dwType != REG_SZ)
1010     {
1011         ERR("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
1012         SetLastError(ERROR_GEN_FAILURE);
1013         goto Cleanup;
1014     }
1015     InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
1016 
1017     /* 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name */
1018     InstallParams.Flags |= DI_ENUMSINGLEINF;
1019     InstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
1020     wcscpy(InstallParams.DriverPath, InfPath);
1021     if (!SetupDiSetDeviceInstallParams(DeviceInfoSet,
1022                                        DeviceInfoData,
1023                                        &InstallParams))
1024     {
1025         ERR("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
1026         goto Cleanup;
1027     }
1028 
1029     /* 5) Build class driver list */
1030     if (!SetupDiBuildDriverInfoList(DeviceInfoSet,
1031                                     DeviceInfoData,
1032                                     SPDIT_CLASSDRIVER))
1033     {
1034         ERR("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
1035         goto Cleanup;
1036     }
1037 
1038     /* 6) Read inf section and from registry */
1039     dwLength = (sizeof(InfSection) / sizeof(InfSection[0])) - 1;
1040     rc = RegQueryValueEx(hKey,
1041                          REGSTR_VAL_INFSECTION,
1042                          0,
1043                          &dwType,
1044                          (LPBYTE)InfSection,
1045                          &dwLength);
1046     if (rc != ERROR_SUCCESS)
1047     {
1048         ERR("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
1049         SetLastError(rc);
1050         goto Cleanup;
1051     }
1052     else if (dwType != REG_SZ)
1053     {
1054         ERR("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
1055         SetLastError(ERROR_GEN_FAILURE);
1056         goto Cleanup;
1057     }
1058     InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
1059 
1060     /* 7) Enumerate drivers */
1061     DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
1062     DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1063     while (SetupDiEnumDriverInfo(DeviceInfoSet,
1064                                  DeviceInfoData,
1065                                  SPDIT_CLASSDRIVER,
1066                                  i,
1067                                  DriverInfoData))
1068     {
1069         /* 8) Find the one who is in the same section as current driver */
1070         if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
1071                                         DeviceInfoData,
1072                                         DriverInfoData,
1073                                         &DriverInfoDetailData,
1074                                         DriverInfoDetailData.cbSize,
1075                                         NULL) &&
1076             GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1077         {
1078             ERR("SetupDiGetDriverInfoDetail() failed with error 0x%lx\n", GetLastError());
1079             goto Cleanup;
1080         }
1081         if (_wcsicmp(DriverInfoDetailData.SectionName, InfSection) == 0)
1082         {
1083             /* We have found the right driver */
1084             Ret = TRUE;
1085             goto Cleanup;
1086         }
1087 
1088         i++;
1089     }
1090     if (GetLastError() != ERROR_NO_MORE_ITEMS)
1091     {
1092         ERR("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
1093         goto Cleanup;
1094     }
1095 
1096     SetLastError(ERROR_NO_DRIVER_SELECTED);
1097 
1098 Cleanup:
1099     if (hKey != INVALID_HANDLE_VALUE)
1100         RegCloseKey(hKey);
1101     return Ret;
1102 }
1103 
1104 
1105 HINSTANCE
LoadAndInitComctl32(VOID)1106 LoadAndInitComctl32(VOID)
1107 {
1108     typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
1109     PINITCOMMONCONTROLS pInitCommonControls;
1110     HINSTANCE hComCtl32;
1111 
1112     hComCtl32 = LoadLibrary(L"comctl32.dll");
1113     if (hComCtl32 != NULL)
1114     {
1115         /* initialize the common controls */
1116         pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
1117                                                                   "InitCommonControls");
1118         if (pInitCommonControls == NULL)
1119         {
1120             FreeLibrary(hComCtl32);
1121             return NULL;
1122         }
1123 
1124         pInitCommonControls();
1125     }
1126 
1127     return hComCtl32;
1128 }
1129 
1130 
1131 BOOL
GetDeviceAndComputerName(LPWSTR lpString,WCHAR szDeviceID[],WCHAR szMachineName[])1132 GetDeviceAndComputerName(LPWSTR lpString,
1133                          WCHAR szDeviceID[],
1134                          WCHAR szMachineName[])
1135 {
1136     BOOL ret = FALSE;
1137 
1138     szDeviceID[0] = L'\0';
1139     szMachineName[0] = L'\0';
1140 
1141     while (*lpString != L'\0')
1142     {
1143         if (*lpString == L'/')
1144         {
1145             lpString++;
1146             if (!_wcsnicmp(lpString, L"DeviceID", 8))
1147             {
1148                 lpString += 9;
1149                 if (*lpString != L'\0')
1150                 {
1151                     int i = 0;
1152                     while ((*lpString != L' ') &&
1153                            (*lpString != L'\0') &&
1154                            (i <= MAX_DEVICE_ID_LEN))
1155                     {
1156                         szDeviceID[i++] = *lpString++;
1157                     }
1158                     szDeviceID[i] = L'\0';
1159                     ret = TRUE;
1160                 }
1161             }
1162             else if (!_wcsnicmp(lpString, L"MachineName", 11))
1163             {
1164                 lpString += 12;
1165                 if (*lpString != L'\0')
1166                 {
1167                     int i = 0;
1168                     while ((*lpString != L' ') &&
1169                            (*lpString != L'\0') &&
1170                            (i <= MAX_COMPUTERNAME_LENGTH))
1171                     {
1172                         szMachineName[i++] = *lpString++;
1173                     }
1174                     szMachineName[i] = L'\0';
1175                 }
1176             }
1177             /* knock the pointer back one and let the next
1178             * pointer deal with incrementing, otherwise we
1179             * go past the end of the string */
1180             lpString--;
1181         }
1182         lpString++;
1183     }
1184 
1185     return ret;
1186 }
1187