Add the driver page if necessary, based on a patch by Herve
[reactos.git] / reactos / lib / devmgr / misc.c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /* $Id: devmgr.c 12852 2005-01-06 13:58:04Z mf $
20 *
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/misc.c
23 * PURPOSE: ReactOS Device Manager
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
25 * UPDATE HISTORY:
26 * 2005/11/24 Created
27 */
28 #include <precomp.h>
29
30 HINSTANCE hDllInstance = NULL;
31
32
33 INT
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 = 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
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
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 }
131
132 s += Ret;
133 }
134
135 return s - *lpTarget;
136 }
137 }
138 return 0;
139 }
140
141
142 DWORD
143 LoadAndFormatString(IN HINSTANCE hInstance,
144 IN UINT uID,
145 OUT LPWSTR *lpTarget,
146 ...)
147 {
148 DWORD Ret = 0;
149 LPWSTR lpFormat;
150 va_list lArgs;
151
152 if (AllocAndLoadString(&lpFormat,
153 hInstance,
154 uID) != 0)
155 {
156 va_start(lArgs, lpTarget);
157 /* let's use FormatMessage to format it because it has the ability to allocate
158 memory automatically */
159 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
160 lpFormat,
161 0,
162 0,
163 (LPWSTR)lpTarget,
164 0,
165 &lArgs);
166 va_end(lArgs);
167
168 LocalFree((HLOCAL)lpFormat);
169 }
170
171 return Ret;
172 }
173
174
175 DWORD
176 LoadAndFormatStringsCat(IN HINSTANCE hInstance,
177 IN UINT *uID,
178 IN UINT nIDs,
179 OUT LPWSTR *lpTarget,
180 ...)
181 {
182 DWORD Ret = 0;
183 LPWSTR lpFormat;
184 va_list lArgs;
185
186 if (AllocAndLoadStringsCat(&lpFormat,
187 hInstance,
188 uID,
189 nIDs) != 0)
190 {
191 va_start(lArgs, lpTarget);
192 /* let's use FormatMessage to format it because it has the ability to allocate
193 memory automatically */
194 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
195 lpFormat,
196 0,
197 0,
198 (LPWSTR)lpTarget,
199 0,
200 &lArgs);
201 va_end(lArgs);
202
203 LocalFree((HLOCAL)lpFormat);
204 }
205
206 return Ret;
207 }
208
209
210 LPARAM
211 ListViewGetSelectedItemData(IN HWND hwnd)
212 {
213 int Index;
214
215 Index = ListView_GetNextItem(hwnd,
216 -1,
217 LVNI_SELECTED);
218 if (Index != -1)
219 {
220 LVITEM li;
221
222 li.mask = LVIF_PARAM;
223 li.iItem = Index;
224 li.iSubItem = 0;
225
226 if (ListView_GetItem(hwnd,
227 &li))
228 {
229 return li.lParam;
230 }
231 }
232
233 return 0;
234 }
235
236
237 LPWSTR
238 ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
239 IN UINT uCodePage)
240 {
241 LPWSTR lpUnicodeStr;
242 INT nLength;
243
244 nLength = MultiByteToWideChar(uCodePage,
245 0,
246 lpMultiByteStr,
247 -1,
248 NULL,
249 0);
250 if (nLength == 0)
251 return NULL;
252
253 lpUnicodeStr = HeapAlloc(GetProcessHeap(),
254 0,
255 nLength * sizeof(WCHAR));
256 if (lpUnicodeStr == NULL)
257 {
258 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
259 return NULL;
260 }
261
262 if (!MultiByteToWideChar(uCodePage,
263 0,
264 lpMultiByteStr,
265 nLength,
266 lpUnicodeStr,
267 nLength))
268 {
269 HeapFree(GetProcessHeap(),
270 0,
271 lpUnicodeStr);
272 return NULL;
273 }
274
275 return lpUnicodeStr;
276 }
277
278
279 BOOL
280 GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
281 IN PSP_DEVINFO_DATA DeviceInfoData,
282 OUT LPWSTR szBuffer,
283 IN DWORD BufferSize)
284 {
285 DWORD RegDataType;
286 BOOL Ret = FALSE;
287
288 if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
289 DeviceInfoData,
290 SPDRP_MFG,
291 &RegDataType,
292 (PBYTE)szBuffer,
293 BufferSize * sizeof(WCHAR),
294 NULL) ||
295 RegDataType != REG_SZ)
296 {
297 szBuffer[0] = L'\0';
298 if (LoadString(hDllInstance,
299 IDS_UNKNOWN,
300 szBuffer,
301 BufferSize))
302 {
303 Ret = TRUE;
304 }
305 }
306 else
307 {
308 /* FIXME - check string for NULL termination! */
309 Ret = TRUE;
310 }
311
312 return Ret;
313 }
314
315
316 BOOL
317 GetDeviceLocationString(IN DEVINST dnDevInst OPTIONAL,
318 IN DEVINST dnParentDevInst OPTIONAL,
319 OUT LPWSTR szBuffer,
320 IN DWORD BufferSize)
321 {
322 DWORD RegDataType;
323 ULONG DataSize;
324 CONFIGRET cRet;
325 LPWSTR szFormatted;
326 BOOL Ret = FALSE;
327
328 DataSize = BufferSize * sizeof(WCHAR);
329 szBuffer[0] = L'\0';
330 if (dnParentDevInst != 0)
331 {
332 /* query the parent node name */
333 if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
334 CM_DRP_DEVICEDESC,
335 &RegDataType,
336 szBuffer,
337 &DataSize,
338 0) == CR_SUCCESS &&
339 RegDataType == REG_SZ &&
340 LoadAndFormatString(hDllInstance,
341 IDS_DEVONPARENT,
342 &szFormatted,
343 szBuffer) != 0)
344 {
345 wcsncpy(szBuffer,
346 szFormatted,
347 BufferSize - 1);
348 szBuffer[BufferSize - 1] = L'\0';
349 LocalFree((HLOCAL)szFormatted);
350 Ret = TRUE;
351 }
352 }
353 else if (dnDevInst != 0)
354 {
355 cRet = CM_Get_DevNode_Registry_Property(dnDevInst,
356 CM_DRP_LOCATION_INFORMATION,
357 &RegDataType,
358 szBuffer,
359 &DataSize,
360 0);
361 if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
362 {
363 /* FIXME - check string for NULL termination! */
364 Ret = TRUE;
365 }
366
367 if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
368 {
369 /* convert the string to an integer value and create a
370 formatted string */
371 ULONG ulLocation = (ULONG)wcstoul(szBuffer,
372 NULL,
373 10);
374 if (LoadAndFormatString(hDllInstance,
375 IDS_LOCATIONSTR,
376 &szFormatted,
377 ulLocation,
378 szBuffer) != 0)
379 {
380 wcsncpy(szBuffer,
381 szFormatted,
382 BufferSize - 1);
383 szBuffer[BufferSize - 1] = L'\0';
384 LocalFree((HLOCAL)szFormatted);
385 }
386 else
387 Ret = FALSE;
388 }
389 }
390
391 if (!Ret &&
392 LoadString(hDllInstance,
393 IDS_UNKNOWN,
394 szBuffer,
395 BufferSize))
396 {
397 Ret = TRUE;
398 }
399
400 return Ret;
401 }
402
403
404 BOOL
405 GetDeviceStatusString(IN DEVINST DevInst,
406 IN HMACHINE hMachine,
407 OUT LPWSTR szBuffer,
408 IN DWORD BufferSize)
409 {
410 CONFIGRET cr;
411 ULONG Status, ProblemNumber;
412 UINT MessageId = IDS_UNKNOWN;
413 BOOL Ret = FALSE;
414
415 szBuffer[0] = L'\0';
416 cr = CM_Get_DevNode_Status_Ex(&Status,
417 &ProblemNumber,
418 DevInst,
419 0,
420 hMachine);
421 if (cr == CR_SUCCESS)
422 {
423 if (Status & DN_HAS_PROBLEM)
424 {
425 UINT uRet;
426
427 uRet = DeviceProblemText(hMachine,
428 DevInst,
429 ProblemNumber,
430 szBuffer,
431 (BufferSize != 0 ? BufferSize : BufferSize - 1));
432
433 Ret = (uRet != 0 && uRet < BufferSize);
434 }
435 else
436 {
437 if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
438 {
439 MessageId = IDS_NODRIVERLOADED;
440 }
441 else
442 {
443 MessageId = IDS_DEV_NO_PROBLEM;
444 }
445
446 goto GeneralMessage;
447 }
448 }
449 else
450 {
451 GeneralMessage:
452 Ret = LoadString(hDllInstance,
453 MessageId,
454 szBuffer,
455 (int)BufferSize);
456 }
457
458 return Ret;
459 }
460
461
462 BOOL
463 IsDeviceHidden(IN DEVINST DevInst,
464 IN HMACHINE hMachine,
465 OUT BOOL *IsHidden)
466 {
467 CONFIGRET cr;
468 ULONG Status, ProblemNumber;
469 BOOL Ret = FALSE;
470
471 cr = CM_Get_DevNode_Status_Ex(&Status,
472 &ProblemNumber,
473 DevInst,
474 0,
475 hMachine);
476 if (cr == CR_SUCCESS)
477 {
478 *IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
479 Ret = TRUE;
480 }
481
482 return Ret;
483 }
484
485
486 BOOL
487 CanDisableDevice(IN DEVINST DevInst,
488 IN HMACHINE hMachine,
489 OUT BOOL *CanDisable)
490 {
491 CONFIGRET cr;
492 ULONG Status, ProblemNumber;
493 BOOL Ret = FALSE;
494
495 cr = CM_Get_DevNode_Status_Ex(&Status,
496 &ProblemNumber,
497 DevInst,
498 0,
499 hMachine);
500 if (cr == CR_SUCCESS)
501 {
502 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
503 Ret = TRUE;
504 }
505
506 return Ret;
507 }
508
509
510 BOOL
511 IsDeviceStarted(IN DEVINST DevInst,
512 IN HMACHINE hMachine,
513 OUT BOOL *IsStarted)
514 {
515 CONFIGRET cr;
516 ULONG Status, ProblemNumber;
517 BOOL Ret = FALSE;
518
519 cr = CM_Get_DevNode_Status_Ex(&Status,
520 &ProblemNumber,
521 DevInst,
522 0,
523 hMachine);
524 if (cr == CR_SUCCESS)
525 {
526 *IsStarted = ((Status & DN_STARTED) != 0);
527 Ret = TRUE;
528 }
529
530 return Ret;
531 }
532
533
534 BOOL
535 IsDriverInstalled(IN DEVINST DevInst,
536 IN HMACHINE hMachine,
537 OUT BOOL *Installed)
538 {
539 CONFIGRET cr;
540 ULONG Status, ProblemNumber;
541 BOOL Ret = FALSE;
542
543 cr = CM_Get_DevNode_Status_Ex(&Status,
544 &ProblemNumber,
545 DevInst,
546 0,
547 hMachine);
548 if (cr == CR_SUCCESS)
549 {
550 *Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
551 (Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
552 Ret = TRUE;
553 }
554
555 return Ret;
556 }
557
558
559 BOOL
560 EnableDevice(IN HDEVINFO DeviceInfoSet,
561 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
562 IN BOOL bEnable,
563 IN DWORD HardwareProfile OPTIONAL,
564 OUT BOOL *bNeedReboot OPTIONAL)
565 {
566 SP_PROPCHANGE_PARAMS pcp;
567 SP_DEVINSTALL_PARAMS dp;
568 DWORD LastErr;
569 BOOL Ret = FALSE;
570
571 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
572 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
573 pcp.HwProfile = HardwareProfile;
574
575 if (bEnable)
576 {
577 /* try to enable the device on the global profile */
578 pcp.StateChange = DICS_ENABLE;
579 pcp.Scope = DICS_FLAG_GLOBAL;
580
581 /* ignore errors */
582 LastErr = GetLastError();
583 if (SetupDiSetClassInstallParams(DeviceInfoSet,
584 DevInfoData,
585 &pcp.ClassInstallHeader,
586 sizeof(SP_PROPCHANGE_PARAMS)))
587 {
588 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
589 DeviceInfoSet,
590 DevInfoData);
591 }
592 SetLastError(LastErr);
593 }
594
595 /* try config-specific */
596 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
597 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
598
599 if (SetupDiSetClassInstallParams(DeviceInfoSet,
600 DevInfoData,
601 &pcp.ClassInstallHeader,
602 sizeof(SP_PROPCHANGE_PARAMS)) &&
603 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
604 DeviceInfoSet,
605 DevInfoData))
606 {
607 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
608 if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
609 DevInfoData,
610 &dp))
611 {
612 if (bNeedReboot != NULL)
613 {
614 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
615 }
616
617 Ret = TRUE;
618 }
619 }
620 return Ret;
621 }
622
623
624 BOOL
625 GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
626 OUT LPWSTR szBuffer,
627 IN DWORD BufferSize)
628 {
629 BOOL Ret = FALSE;
630
631 if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
632 szBuffer,
633 BufferSize,
634 NULL))
635 {
636 szBuffer[0] = L'\0';
637 if (LoadString(hDllInstance,
638 IDS_UNKNOWN,
639 szBuffer,
640 BufferSize))
641 {
642 Ret = TRUE;
643 }
644 }
645 else
646 {
647 /* FIXME - check string for NULL termination! */
648 Ret = TRUE;
649 }
650
651 return Ret;
652 }
653
654
655 BOOL
656 GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
657 IN PSP_DEVINFO_DATA DeviceInfoData,
658 OUT LPWSTR szBuffer,
659 IN DWORD BufferSize)
660 {
661 DWORD RegDataType;
662 BOOL Ret = FALSE;
663
664 if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
665 DeviceInfoData,
666 SPDRP_FRIENDLYNAME,
667 &RegDataType,
668 (PBYTE)szBuffer,
669 BufferSize * sizeof(WCHAR),
670 NULL) ||
671 SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
672 DeviceInfoData,
673 SPDRP_DEVICEDESC,
674 &RegDataType,
675 (PBYTE)szBuffer,
676 BufferSize * sizeof(WCHAR),
677 NULL)) &&
678 RegDataType == REG_SZ)
679 {
680 /* FIXME - check string for NULL termination! */
681 Ret = TRUE;
682 }
683 else
684 {
685 szBuffer[0] = L'\0';
686 if (LoadString(hDllInstance,
687 IDS_UNKNOWNDEVICE,
688 szBuffer,
689 BufferSize))
690 {
691 Ret = TRUE;
692 }
693 }
694
695 return Ret;
696 }
697
698
699 HINSTANCE
700 LoadAndInitComctl32(VOID)
701 {
702 typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
703 PINITCOMMONCONTROLS pInitCommonControls;
704 HINSTANCE hComCtl32;
705
706 hComCtl32 = LoadLibrary(L"comctl32.dll");
707 if (hComCtl32 != NULL)
708 {
709 /* initialize the common controls */
710 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
711 "InitCommonControls");
712 if (pInitCommonControls == NULL)
713 {
714 FreeLibrary(hComCtl32);
715 return NULL;
716 }
717
718 pInitCommonControls();
719 }
720
721 return hComCtl32;
722 }
723
724
725 BOOL
726 STDCALL
727 DllMain(IN HINSTANCE hinstDLL,
728 IN DWORD dwReason,
729 IN LPVOID lpvReserved)
730 {
731 switch (dwReason)
732 {
733 case DLL_PROCESS_ATTACH:
734 DisableThreadLibraryCalls(hinstDLL);
735 hDllInstance = hinstDLL;
736 break;
737 }
738
739 return TRUE;
740 }