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/devprblm.c
22  * PURPOSE:         ReactOS Device Manager
23  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
24  * UPDATE HISTORY:
25  *      04-04-2004  Created
26  */
27 
28 #include "precomp.h"
29 #include "properties.h"
30 #include "resource.h"
31 
32 
33 BOOL
34 ShowDeviceProblemWizard(IN HWND hWndParent  OPTIONAL,
35                         IN HDEVINFO hDevInfo,
36                         IN PSP_DEVINFO_DATA DevInfoData,
37                         IN HMACHINE hMachine  OPTIONAL)
38 {
39     WCHAR szDeviceInstanceId[256];
40     CONFIGRET cr;
41     ULONG Status, ProblemNumber;
42     DWORD dwReboot;
43     BOOL Ret = FALSE;
44 
45     /* Get the device instance id */
46     if (!SetupDiGetDeviceInstanceId(hDevInfo,
47                                     DevInfoData,
48                                     szDeviceInstanceId,
49                                     256,
50                                     NULL))
51         return FALSE;
52 
53     cr = CM_Get_DevNode_Status_Ex(&Status,
54                                   &ProblemNumber,
55                                   DevInfoData->DevInst,
56                                   0,
57                                   hMachine);
58     if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
59     {
60         switch (ProblemNumber)
61         {
62             case CM_PROB_DEVLOADER_FAILED:
63             {
64                 /* FIXME - only if it's not a root bus devloader */
65                 /* FIXME - display the update driver wizard */
66                 break;
67             }
68 
69             case CM_PROB_OUT_OF_MEMORY:
70             case CM_PROB_ENTRY_IS_WRONG_TYPE:
71             case CM_PROB_LACKED_ARBITRATOR:
72             case CM_PROB_FAILED_START:
73             case CM_PROB_LIAR:
74             case CM_PROB_UNKNOWN_RESOURCE:
75             {
76                 /* FIXME - display the update driver wizard */
77                 InstallDevInst(hWndParent, szDeviceInstanceId, TRUE, &dwReboot);
78                 break;
79             }
80 
81             case CM_PROB_BOOT_CONFIG_CONFLICT:
82             case CM_PROB_NORMAL_CONFLICT:
83             case CM_PROB_REENUMERATION:
84             {
85                 /* FIXME - display the conflict wizard */
86                 break;
87             }
88 
89             case CM_PROB_FAILED_FILTER:
90             case CM_PROB_REINSTALL:
91             case CM_PROB_FAILED_INSTALL:
92             {
93                 /* FIXME - display the driver (re)installation wizard */
94                 InstallDevInst(hWndParent, szDeviceInstanceId, TRUE, &dwReboot);
95                 break;
96             }
97 
98             case CM_PROB_DEVLOADER_NOT_FOUND:
99             {
100                 /* FIXME - 4 cases:
101                    1) if it's a missing system devloader:
102                       - fail
103                    2) if it's not a system devloader but still missing:
104                       - display the driver reinstallation wizard
105                    3) if it's not a system devloader but the file can be found:
106                       - display the update driver wizard
107                    4) if it's a missing or empty software key
108                       - display the update driver wizard
109                  */
110                 break;
111             }
112 
113             case CM_PROB_INVALID_DATA:
114             case CM_PROB_PARTIAL_LOG_CONF:
115             case CM_PROB_NO_VALID_LOG_CONF:
116             case CM_PROB_HARDWARE_DISABLED:
117             case CM_PROB_CANT_SHARE_IRQ:
118             case CM_PROB_TRANSLATION_FAILED:
119             case CM_PROB_SYSTEM_SHUTDOWN:
120             case CM_PROB_PHANTOM:
121                 /* FIXME - do nothing */
122                 break;
123 
124             case CM_PROB_NOT_VERIFIED:
125             case CM_PROB_DEVICE_NOT_THERE:
126                 /* FIXME - display search hardware wizard */
127                 break;
128 
129             case CM_PROB_NEED_RESTART:
130             case CM_PROB_WILL_BE_REMOVED:
131             case CM_PROB_MOVED:
132             case CM_PROB_TOO_EARLY:
133             case CM_PROB_DISABLED_SERVICE:
134                 /* FIXME - reboot computer */
135                 break;
136 
137             case CM_PROB_REGISTRY:
138                 /* FIXME - check registry */
139                 break;
140 
141             case CM_PROB_DISABLED:
142             {
143                 /* FIXME - if device was disabled by user display the "Enable Device" wizard,
144                            otherwise Troubleshoot because the device was disabled by the system */
145                 break;
146             }
147 
148             case CM_PROB_DEVLOADER_NOT_READY:
149             {
150                 /* FIXME - if it's a graphics adapter:
151                            - if it's a a secondary adapter and the main adapter
152                              couldn't be found
153                              - do nothing or default action
154                            - else
155                              - display the Properties
156                          - else
157                            - Update driver
158                  */
159                 break;
160             }
161 
162             case CM_PROB_FAILED_ADD:
163             {
164                 /* FIXME - display the properties of the sub-device */
165                 break;
166             }
167 
168             case CM_PROB_NO_SOFTCONFIG:
169             case CM_PROB_IRQ_TRANSLATION_FAILED:
170             case CM_PROB_FAILED_DRIVER_ENTRY:
171             case CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD:
172             case CM_PROB_DRIVER_FAILED_LOAD:
173             case CM_PROB_DRIVER_SERVICE_KEY_INVALID:
174             case CM_PROB_LEGACY_SERVICE_NO_DEVICES:
175             case CM_PROB_DUPLICATE_DEVICE:
176             case CM_PROB_FAILED_POST_START:
177             case CM_PROB_HALTED:
178             case CM_PROB_HELD_FOR_EJECT:
179             case CM_PROB_DRIVER_BLOCKED:
180             case CM_PROB_REGISTRY_TOO_LARGE:
181             default:
182             {
183                 /* FIXME - troubleshoot the device */
184                 break;
185             }
186         }
187     }
188 
189     return Ret;
190 }
191 
192 
193 /***************************************************************************
194  * NAME                                                         EXPORTED
195  *      DeviceProblemWizardA
196  *
197  * DESCRIPTION
198  *   Calls the device problem wizard
199  *
200  * ARGUMENTS
201  *   hWndParent:    Handle to the parent window
202  *   lpMachineName: Machine Name, NULL is the local machine
203  *   lpDeviceID:    Specifies the device, also see NOTEs
204  *
205  * RETURN VALUE
206  *   TRUE:  if no errors occured
207  *   FALSE: if errors occured
208  *
209  * @implemented
210  */
211 BOOL
212 WINAPI
213 DeviceProblemWizardA(IN HWND hWndParent  OPTIONAL,
214                      IN LPCSTR lpMachineName  OPTIONAL,
215                      IN LPCSTR lpDeviceID)
216 {
217     LPWSTR lpMachineNameW = NULL;
218     LPWSTR lpDeviceIDW = NULL;
219     BOOL Ret = FALSE;
220 
221     if (lpMachineName != NULL)
222     {
223         if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
224                                                          CP_ACP)))
225         {
226             goto Cleanup;
227         }
228     }
229     if (lpDeviceID != NULL)
230     {
231         if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
232                                                       CP_ACP)))
233         {
234             goto Cleanup;
235         }
236     }
237 
238     Ret = DeviceProblemWizardW(hWndParent,
239                                lpMachineNameW,
240                                lpDeviceIDW);
241 
242 Cleanup:
243     if (lpMachineNameW != NULL)
244     {
245         HeapFree(GetProcessHeap(),
246                  0,
247                  lpMachineNameW);
248     }
249     if (lpDeviceIDW != NULL)
250     {
251         HeapFree(GetProcessHeap(),
252                  0,
253                  lpDeviceIDW);
254     }
255 
256     return Ret;
257 }
258 
259 
260 /***************************************************************************
261  * NAME                                                         EXPORTED
262  *      DeviceProblemWizardW
263  *
264  * DESCRIPTION
265  *   Calls the device problem wizard
266  *
267  * ARGUMENTS
268  *   hWndParent:    Handle to the parent window
269  *   lpMachineName: Machine Name, NULL is the local machine
270  *   lpDeviceID:    Specifies the device, also see NOTEs
271  *
272  * RETURN VALUE
273  *   TRUE:  if no errors occured
274  *   FALSE: if errors occured
275  *
276  * @unimplemented
277  */
278 BOOL
279 WINAPI
280 DeviceProblemWizardW(IN HWND hWndParent  OPTIONAL,
281                      IN LPCWSTR lpMachineName  OPTIONAL,
282                      IN LPCWSTR lpDeviceID)
283 {
284     HDEVINFO hDevInfo;
285     SP_DEVINFO_DATA DevInfoData;
286     HINSTANCE hComCtl32;
287     CONFIGRET cr;
288     HMACHINE hMachine;
289     BOOL Ret = FALSE;
290 
291     if (lpDeviceID == NULL)
292     {
293         SetLastError(ERROR_INVALID_PARAMETER);
294         return FALSE;
295     }
296 
297     /* dynamically load comctl32 */
298     hComCtl32 = LoadAndInitComctl32();
299     if (hComCtl32 != NULL)
300     {
301         hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
302                                                  hWndParent,
303                                                  lpMachineName,
304                                                  NULL);
305         if (hDevInfo != INVALID_HANDLE_VALUE)
306         {
307             cr = CM_Connect_Machine(lpMachineName,
308                                     &hMachine);
309             if (cr == CR_SUCCESS)
310             {
311                 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
312                 if (SetupDiOpenDeviceInfo(hDevInfo,
313                                           lpDeviceID,
314                                           hWndParent,
315                                           0,
316                                           &DevInfoData))
317                 {
318                     Ret = ShowDeviceProblemWizard(hWndParent,
319                                                   hDevInfo,
320                                                   &DevInfoData,
321                                                   hMachine);
322                 }
323 
324                 CM_Disconnect_Machine(hMachine);
325             }
326 
327             SetupDiDestroyDeviceInfoList(hDevInfo);
328         }
329 
330         FreeLibrary(hComCtl32);
331     }
332 
333     return Ret;
334 }
335 
336 
337 static const UINT ProblemStringId[NUM_CM_PROB] =
338 {
339     IDS_DEV_NO_PROBLEM,
340     IDS_DEV_DEVLOADER_FAILED,
341     IDS_DEV_NOT_CONFIGURED,
342     IDS_DEV_OUT_OF_MEMORY,
343     IDS_DEV_ENTRY_IS_WRONG_TYPE,
344     IDS_DEV_LACKED_ARBITRATOR,
345     IDS_DEV_BOOT_CONFIG_CONFLICT,
346     IDS_DEV_FAILED_FILTER,
347     IDS_DEV_DEVLOADER_NOT_FOUND,
348     IDS_DEV_INVALID_DATA,
349     IDS_DEV_FAILED_START,
350     IDS_DEV_LIAR,
351     IDS_DEV_NORMAL_CONFLICT,
352     IDS_DEV_NOT_VERIFIED,
353     IDS_DEV_NEED_RESTART,
354     IDS_DEV_REENUMERATION,
355     IDS_DEV_PARTIAL_LOG_CONF,
356     IDS_DEV_UNKNOWN_RESOURCE,
357     IDS_DEV_REINSTALL,
358     IDS_DEV_REGISTRY,
359     IDS_UNKNOWN, /* CM_PROB_VXDLDR, not used on NT */
360     IDS_DEV_WILL_BE_REMOVED,
361     IDS_DEV_DISABLED,
362     IDS_DEV_DEVLOADER_NOT_READY,
363     IDS_DEV_DEVICE_NOT_THERE,
364     IDS_DEV_MOVED,
365     IDS_DEV_TOO_EARLY,
366     IDS_DEV_NO_VALID_LOG_CONF,
367     IDS_DEV_FAILED_INSTALL,
368     IDS_DEV_HARDWARE_DISABLED,
369     IDS_DEV_CANT_SHARE_IRQ,
370     IDS_DEV_FAILED_ADD,
371     IDS_DEV_DISABLED_SERVICE,
372     IDS_DEV_TRANSLATION_FAILED,
373     IDS_DEV_NO_SOFTCONFIG,
374     IDS_DEV_BIOS_TABLE,
375     IDS_DEV_IRQ_TRANSLATION_FAILED,
376     IDS_DEV_FAILED_DRIVER_ENTRY,
377     IDS_DEV_DRIVER_FAILED_PRIOR_UNLOAD,
378     IDS_DEV_DRIVER_FAILED_LOAD,
379     IDS_DEV_DRIVER_SERVICE_KEY_INVALID,
380     IDS_DEV_LEGACY_SERVICE_NO_DEVICES,
381     IDS_DEV_DUPLICATE_DEVICE,
382     IDS_DEV_FAILED_POST_START,
383     IDS_DEV_HALTED,
384     IDS_DEV_PHANTOM,
385     IDS_DEV_SYSTEM_SHUTDOWN,
386     IDS_DEV_HELD_FOR_EJECT,
387     IDS_DEV_DRIVER_BLOCKED,
388     IDS_DEV_REGISTRY_TOO_LARGE,
389     IDS_DEV_SETPROPERTIES_FAILED
390 };
391 
392 
393 /***************************************************************************
394  * NAME                                                         EXPORTED
395  *      DeviceProblemTextA
396  *
397  * DESCRIPTION
398  *   Gets the problem text from a problem number displayed in the properties dialog
399  *
400  * ARGUMENTS
401  *   hMachine:   Machine handle or NULL for the local machine
402  *   DevInst:    Device instance handle
403  *   uProblemId: Specifies the problem ID
404  *   lpString:   Pointer to a buffer where the string is to be copied to. If the buffer
405  *               is too small, the return value is the required string length in characters,
406  *               excluding the NULL-termination.
407  *   uMaxString: Size of the buffer in characters
408  *
409  * RETURN VALUE
410  *   The return value is the length of the string in characters.
411  *   It returns 0 if an error occured.
412  *
413  * @implemented
414  */
415 UINT
416 WINAPI
417 DeviceProblemTextA(IN HMACHINE hMachine  OPTIONAL,
418                    IN DEVINST dnDevInst,
419                    IN ULONG uProblemId,
420                    OUT LPSTR lpString,
421                    IN UINT uMaxString)
422 {
423     LPWSTR lpBuffer = NULL;
424     UINT Ret = 0;
425 
426     if (uMaxString != 0)
427     {
428         lpBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(),
429                                      0,
430                                      (uMaxString + 1) * sizeof(WCHAR));
431         if (lpBuffer == NULL)
432         {
433             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
434             return 0;
435         }
436     }
437 
438     Ret = DeviceProblemTextW(hMachine,
439                              dnDevInst,
440                              uProblemId,
441                              lpBuffer,
442                              uMaxString);
443 
444     if (lpBuffer != NULL)
445     {
446         if (Ret)
447         {
448             WideCharToMultiByte(CP_ACP,
449                                 0,
450                                 lpBuffer,
451                                 (int)Ret,
452                                 lpString,
453                                 (int)uMaxString,
454                                 NULL,
455                                 NULL);
456         }
457 
458         HeapFree(GetProcessHeap(),
459                  0,
460                  lpBuffer);
461     }
462 
463     return Ret;
464 }
465 
466 
467 /***************************************************************************
468  * NAME                                                         EXPORTED
469  *      DeviceProblemTextW
470  *
471  * DESCRIPTION
472  *   Gets the problem text from a problem number displayed in the properties dialog
473  *
474  * ARGUMENTS
475  *   hMachine:   Machine handle or NULL for the local machine
476  *   DevInst:    Device instance handle
477  *   uProblemId: Specifies the problem ID
478  *   lpString:   Pointer to a buffer where the string is to be copied to. If the buffer
479  *               is too small, the return value is the required string length in characters,
480  *               excluding the NULL-termination.
481  *   uMaxString: Size of the buffer in characters
482  *
483  * RETURN VALUE
484  *   The return value is the length of the string in characters.
485  *   It returns 0 if an error occured.
486  *
487  * @implemented
488  */
489 UINT
490 WINAPI
491 DeviceProblemTextW(IN HMACHINE hMachine  OPTIONAL,
492                    IN DEVINST dnDevInst,
493                    IN ULONG uProblemId,
494                    OUT LPWSTR lpString,
495                    IN UINT uMaxString)
496 {
497     UINT MessageId = IDS_UNKNOWN;
498     UINT Ret = 0;
499 
500     if (uProblemId < sizeof(ProblemStringId) / sizeof(ProblemStringId[0]))
501         MessageId = ProblemStringId[uProblemId];
502 
503     if (uProblemId == 0)
504     {
505         if (uMaxString != 0)
506         {
507             Ret = LoadString(hDllInstance,
508                              MessageId,
509                              lpString,
510                              (int)uMaxString);
511         }
512         else
513         {
514             Ret = (UINT)LengthOfStrResource(hDllInstance,
515                                             MessageId);
516         }
517     }
518     else
519     {
520         LPWSTR szProblem;
521         WCHAR szInfo[] = L"FIXME";
522         DWORD dwRet;
523         BOOL AdvFormat = FALSE;
524         UINT StringIDs[] =
525         {
526             MessageId,
527             IDS_DEVCODE,
528         };
529 
530         switch (uProblemId)
531         {
532             case CM_PROB_DEVLOADER_FAILED:
533             {
534                 /* FIXME - if not a root bus devloader then use IDS_DEV_DEVLOADER_FAILED2 */
535                 /* FIXME - get the type string (ie. ISAPNP, PCI or BIOS for root bus devloaders,
536                            or FLOP, ESDI, SCSI, etc for others */
537                 AdvFormat = TRUE;
538                 break;
539             }
540 
541             case CM_PROB_DEVLOADER_NOT_FOUND:
542             {
543                 /* FIXME - 4 cases:
544                    1) if it's a missing system devloader:
545                       - get the system devloader name
546                    2) if it's not a system devloader but still missing:
547                       - get the devloader name (file name?)
548                    3) if it's not a system devloader but the file can be found:
549                       - use IDS_DEV_DEVLOADER_NOT_FOUND2
550                    4) if it's a missing or empty software key
551                       - use IDS_DEV_DEVLOADER_NOT_FOUND3
552                       - AdvFormat = FALSE!
553                  */
554                 AdvFormat = TRUE;
555                 break;
556             }
557 
558             case CM_PROB_INVALID_DATA:
559                 /* FIXME - if the device isn't enumerated by the BIOS/ACPI use IDS_DEV_INVALID_DATA2 */
560                 AdvFormat = FALSE;
561                 break;
562 
563             case CM_PROB_NORMAL_CONFLICT:
564                 /* FIXME - get resource type (IRQ, DMA, Memory or I/O) */
565                 AdvFormat = TRUE;
566                 break;
567 
568             case CM_PROB_UNKNOWN_RESOURCE:
569                 /* FIXME - get the .inf file name */
570                 AdvFormat = TRUE;
571                 break;
572 
573             case CM_PROB_DISABLED:
574                 /* FIXME - if the device was disabled by the system use IDS_DEV_DISABLED2 */
575                 break;
576 
577             case CM_PROB_FAILED_ADD:
578                 /* FIXME - get the name of the sub-device with the error */
579                 AdvFormat = TRUE;
580                 break;
581         }
582 
583         if (AdvFormat)
584         {
585             StringIDs[1] = IDS_DEVCODE2;
586             dwRet = LoadAndFormatStringsCat(hDllInstance,
587                                             StringIDs,
588                                             sizeof(StringIDs) / sizeof(StringIDs[0]),
589                                             &szProblem,
590                                             szInfo,
591                                             uProblemId);
592         }
593         else
594         {
595             dwRet = LoadAndFormatStringsCat(hDllInstance,
596                                             StringIDs,
597                                             sizeof(StringIDs) / sizeof(StringIDs[0]),
598                                             &szProblem,
599                                             uProblemId);
600         }
601 
602         if (dwRet != 0)
603         {
604             if (uMaxString != 0 && uMaxString >= dwRet)
605             {
606                 wcscpy(lpString,
607                        szProblem);
608             }
609 
610             LocalFree((HLOCAL)szProblem);
611 
612             Ret = dwRet;
613         }
614     }
615 
616     return Ret;
617 }
618