fixed bug 1407
[reactos.git] / reactos / dll / win32 / newdev / newdev.c
1 /*
2 * New device installer (newdev.dll)
3 *
4 * Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
5 * 2005 Christoph von Wittich (Christoph@ActiveVB.de)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #define YDEBUG
23 #include "newdev.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(newdev);
26
27 static BOOL SearchDriver ( PDEVINSTDATA DevInstData, LPCTSTR Path );
28 static BOOL InstallDriver ( PDEVINSTDATA DevInstData );
29 static DWORD WINAPI FindDriverProc( LPVOID lpParam );
30 static BOOL FindDriver ( PDEVINSTDATA DevInstData, LPCWSTR InfFile );
31
32 static DEVINSTDATA DevInstData;
33 HINSTANCE hDllInstance;
34 HANDLE hThread;
35
36 static BOOL
37 CanDisableDevice(
38 IN DEVINST DevInst,
39 IN HMACHINE hMachine,
40 OUT BOOL *CanDisable)
41 {
42 #if 0
43 /* hpoussin, Dec 2005. I've disabled this code because
44 * ntoskrnl never sets the DN_DISABLEABLE flag.
45 */
46 CONFIGRET cr;
47 ULONG Status, ProblemNumber;
48 BOOL Ret = FALSE;
49
50 cr = CM_Get_DevNode_Status_Ex(
51 &Status,
52 &ProblemNumber,
53 DevInst,
54 0,
55 hMachine);
56 if (cr == CR_SUCCESS)
57 {
58 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
59 Ret = TRUE;
60 }
61
62 return Ret;
63 #else
64 *CanDisable = TRUE;
65 return TRUE;
66 #endif
67 }
68
69
70 static BOOL
71 IsDeviceStarted(
72 IN DEVINST DevInst,
73 IN HMACHINE hMachine,
74 OUT BOOL *IsEnabled)
75 {
76 CONFIGRET cr;
77 ULONG Status, ProblemNumber;
78 BOOL Ret = FALSE;
79
80 cr = CM_Get_DevNode_Status_Ex(
81 &Status,
82 &ProblemNumber,
83 DevInst,
84 0,
85 hMachine);
86 if (cr == CR_SUCCESS)
87 {
88 *IsEnabled = ((Status & DN_STARTED) != 0);
89 Ret = TRUE;
90 }
91
92 return Ret;
93 }
94
95
96 static BOOL
97 StartDevice(
98 IN HDEVINFO DeviceInfoSet,
99 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
100 IN BOOL bEnable,
101 IN DWORD HardwareProfile OPTIONAL,
102 OUT BOOL *bNeedReboot OPTIONAL)
103 {
104 SP_PROPCHANGE_PARAMS pcp;
105 SP_DEVINSTALL_PARAMS dp;
106 DWORD LastErr;
107 BOOL Ret = FALSE;
108
109 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
110 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
111 pcp.HwProfile = HardwareProfile;
112
113 if (bEnable)
114 {
115 /* try to enable the device on the global profile */
116 pcp.StateChange = DICS_ENABLE;
117 pcp.Scope = DICS_FLAG_GLOBAL;
118
119 /* ignore errors */
120 LastErr = GetLastError();
121 if (SetupDiSetClassInstallParams(
122 DeviceInfoSet,
123 DevInfoData,
124 &pcp.ClassInstallHeader,
125 sizeof(SP_PROPCHANGE_PARAMS)))
126 {
127 SetupDiCallClassInstaller(
128 DIF_PROPERTYCHANGE,
129 DeviceInfoSet,
130 DevInfoData);
131 }
132 SetLastError(LastErr);
133 }
134
135 /* try config-specific */
136 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
137 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
138
139 if (SetupDiSetClassInstallParams(
140 DeviceInfoSet,
141 DevInfoData,
142 &pcp.ClassInstallHeader,
143 sizeof(SP_PROPCHANGE_PARAMS)) &&
144 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
145 DeviceInfoSet,
146 DevInfoData))
147 {
148 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
149 if (SetupDiGetDeviceInstallParams(
150 DeviceInfoSet,
151 DevInfoData,
152 &dp))
153 {
154 if (bNeedReboot != NULL)
155 {
156 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
157 }
158
159 Ret = TRUE;
160 }
161 }
162 return Ret;
163 }
164
165 /*
166 * @implemented
167 */
168 BOOL WINAPI
169 UpdateDriverForPlugAndPlayDevicesW(
170 IN HWND hwndParent,
171 IN LPCWSTR HardwareId,
172 IN LPCWSTR FullInfPath,
173 IN DWORD InstallFlags,
174 OUT PBOOL bRebootRequired OPTIONAL)
175 {
176 DEVINSTDATA DevInstData;
177 DWORD i;
178 LPWSTR Buffer = NULL;
179 DWORD BufferSize;
180 LPCWSTR CurrentHardwareId; /* Pointer into Buffer */
181 BOOL FoundHardwareId, FoundAtLeastOneDevice = FALSE;
182 BOOL ret = FALSE;
183
184 DevInstData.hDevInfo = INVALID_HANDLE_VALUE;
185
186 TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %S %S 0x%lx %p)\n",
187 hwndParent, HardwareId, FullInfPath, InstallFlags, bRebootRequired);
188
189 /* FIXME: InstallFlags bRebootRequired ignored! */
190
191 /* Check flags */
192 /* FIXME: if (InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE))
193 {
194 DPRINT("Unknown flags: 0x%08lx\n", InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE));
195 SetLastError(ERROR_INVALID_FLAGS);
196 goto cleanup;
197 }*/
198
199 /* Enumerate all devices of the system */
200 DevInstData.hDevInfo = SetupDiGetClassDevsW(NULL, NULL, hwndParent, DIGCF_ALLCLASSES | DIGCF_PRESENT);
201 if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE)
202 goto cleanup;
203 DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
204 for (i = 0; ; i++)
205 {
206 if (!SetupDiEnumDeviceInfo(DevInstData.hDevInfo, i, &DevInstData.devInfoData))
207 {
208 if (GetLastError() != ERROR_NO_MORE_ITEMS)
209 {
210 TRACE("SetupDiEnumDeviceInfo() failed with error 0x%lx\n", GetLastError());
211 goto cleanup;
212 }
213 /* This error was expected */
214 break;
215 }
216
217 /* Get Hardware ID */
218 HeapFree(GetProcessHeap(), 0, Buffer);
219 Buffer = NULL;
220 BufferSize = 0;
221 while (!SetupDiGetDeviceRegistryPropertyW(
222 DevInstData.hDevInfo,
223 &DevInstData.devInfoData,
224 SPDRP_HARDWAREID,
225 NULL,
226 (PBYTE)Buffer,
227 BufferSize,
228 &BufferSize))
229 {
230 if (GetLastError() == ERROR_FILE_NOT_FOUND)
231 {
232 Buffer = NULL;
233 break;
234 }
235 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
236 {
237 TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%lx\n", GetLastError());
238 goto cleanup;
239 }
240 /* This error was expected */
241 HeapFree(GetProcessHeap(), 0, Buffer);
242 Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
243 if (!Buffer)
244 {
245 TRACE("HeapAlloc() failed\n", GetLastError());
246 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
247 goto cleanup;
248 }
249 }
250 if (Buffer == NULL)
251 continue;
252
253 /* Check if we match the given hardware ID */
254 FoundHardwareId = FALSE;
255 for (CurrentHardwareId = Buffer; *CurrentHardwareId != UNICODE_NULL; CurrentHardwareId += wcslen(CurrentHardwareId) + 1)
256 {
257 if (wcscmp(CurrentHardwareId, HardwareId) == 0)
258 {
259 FoundHardwareId = TRUE;
260 break;
261 }
262 }
263 if (!FoundHardwareId)
264 continue;
265
266 /* We need to try to update the driver of this device */
267
268 /* Get Instance ID */
269 HeapFree(GetProcessHeap(), 0, Buffer);
270 Buffer = NULL;
271 if (SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, NULL, 0, &BufferSize))
272 {
273 /* Error, as the output buffer should be too small */
274 SetLastError(ERROR_GEN_FAILURE);
275 goto cleanup;
276 }
277 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
278 {
279 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
280 goto cleanup;
281 }
282 else if ((Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize)) == NULL)
283 {
284 TRACE("HeapAlloc() failed\n", GetLastError());
285 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
286 goto cleanup;
287 }
288 else if (!SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, Buffer, BufferSize, NULL))
289 {
290 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
291 goto cleanup;
292 }
293 TRACE("Trying to update the driver of %S\n", Buffer);
294
295 /* Search driver in the specified .inf file */
296 if (!FindDriver(&DevInstData, FullInfPath))
297 {
298 TRACE("FindDriver() failed with error 0x%lx\n", GetLastError());
299 continue;
300 }
301
302 /* FIXME: HACK! We shouldn't check of ERROR_PRIVILEGE_NOT_HELD */
303 //if (!InstallDriver(&DevInstData))
304 if (!InstallDriver(&DevInstData) && GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
305 {
306 TRACE("InstallDriver() failed with error 0x%lx\n", GetLastError());
307 continue;
308 }
309
310 FoundAtLeastOneDevice = TRUE;
311 }
312
313 if (FoundAtLeastOneDevice)
314 {
315 SetLastError(NO_ERROR);
316 ret = TRUE;
317 }
318 else
319 {
320 TRACE("No device found with HardwareID %S\n", HardwareId);
321 SetLastError(ERROR_NO_SUCH_DEVINST);
322 }
323
324 cleanup:
325 if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE)
326 SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo);
327 HeapFree(GetProcessHeap(), 0, Buffer);
328 return ret;
329 }
330
331 /*
332 * @implemented
333 */
334 BOOL WINAPI
335 UpdateDriverForPlugAndPlayDevicesA(
336 IN HWND hwndParent,
337 IN LPCSTR HardwareId,
338 IN LPCSTR FullInfPath,
339 IN DWORD InstallFlags,
340 OUT PBOOL bRebootRequired OPTIONAL)
341 {
342 BOOL Result;
343 LPWSTR HardwareIdW = NULL;
344 LPWSTR FullInfPathW = NULL;
345
346 int len = MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, NULL, 0);
347 HardwareIdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
348 if (!HardwareIdW)
349 {
350 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
351 return FALSE;
352 }
353 MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, HardwareIdW, len);
354
355 len = MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, NULL, 0);
356 FullInfPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
357 if (!FullInfPathW)
358 {
359 HeapFree(GetProcessHeap(), 0, HardwareIdW);
360 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
361 return FALSE;
362 }
363 MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, FullInfPathW, len);
364
365 Result = UpdateDriverForPlugAndPlayDevicesW(
366 hwndParent,
367 HardwareIdW,
368 FullInfPathW,
369 InstallFlags,
370 bRebootRequired);
371
372 HeapFree(GetProcessHeap(), 0, HardwareIdW);
373 HeapFree(GetProcessHeap(), 0, FullInfPathW);
374
375 return Result;
376 }
377
378
379 static HFONT
380 CreateTitleFont(VOID)
381 {
382 NONCLIENTMETRICS ncm;
383 LOGFONT LogFont;
384 HDC hdc;
385 INT FontSize;
386 HFONT hFont;
387
388 ncm.cbSize = sizeof(NONCLIENTMETRICS);
389 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
390
391 LogFont = ncm.lfMessageFont;
392 LogFont.lfWeight = FW_BOLD;
393 _tcscpy(LogFont.lfFaceName, _T("MS Shell Dlg"));
394
395 hdc = GetDC(NULL);
396 FontSize = 12;
397 LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72;
398 hFont = CreateFontIndirect(&LogFont);
399 ReleaseDC(NULL, hdc);
400
401 return hFont;
402 }
403
404 static VOID
405 CenterWindow(
406 IN HWND hWnd)
407 {
408 HWND hWndParent;
409 RECT rcParent;
410 RECT rcWindow;
411
412 hWndParent = GetParent(hWnd);
413 if (hWndParent == NULL)
414 hWndParent = GetDesktopWindow();
415
416 GetWindowRect(hWndParent, &rcParent);
417 GetWindowRect(hWnd, &rcWindow);
418
419 SetWindowPos(
420 hWnd,
421 HWND_TOP,
422 ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2,
423 ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2,
424 0,
425 0,
426 SWP_NOSIZE);
427 }
428
429 static INT_PTR CALLBACK
430 WelcomeDlgProc(
431 IN HWND hwndDlg,
432 IN UINT uMsg,
433 IN WPARAM wParam,
434 IN LPARAM lParam)
435 {
436
437 PDEVINSTDATA DevInstData;
438
439 /* Retrieve pointer to the global setup data */
440 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
441
442 switch (uMsg)
443 {
444 case WM_INITDIALOG:
445 {
446 HWND hwndControl;
447 DWORD dwStyle;
448
449 /* Get pointer to the global setup data */
450 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
451 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
452
453 hwndControl = GetParent(hwndDlg);
454
455 /* Center the wizard window */
456 CenterWindow (hwndControl);
457
458 /* Hide the system menu */
459 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
460 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
461
462 /* Set title font */
463 SendDlgItemMessage(
464 hwndDlg,
465 IDC_WELCOMETITLE,
466 WM_SETFONT,
467 (WPARAM)DevInstData->hTitleFont,
468 (LPARAM)TRUE);
469
470 SendDlgItemMessage(
471 hwndDlg,
472 IDC_DEVICE,
473 WM_SETTEXT,
474 0,
475 (LPARAM) DevInstData->buffer);
476
477 SendDlgItemMessage(
478 hwndDlg,
479 IDC_RADIO_AUTO,
480 BM_SETCHECK,
481 (WPARAM) TRUE,
482 (LPARAM) 0);
483 break;
484 }
485
486 case WM_NOTIFY:
487 {
488 LPNMHDR lpnm = (LPNMHDR)lParam;
489
490 switch (lpnm->code)
491 {
492 case PSN_SETACTIVE:
493 /* Enable the Next button */
494 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
495 break;
496
497 case PSN_WIZNEXT:
498 /* Handle a Next button click, if necessary */
499 if (SendDlgItemMessage(hwndDlg, IDC_RADIO_AUTO, BM_GETCHECK, (WPARAM) 0, (LPARAM) 0) == BST_CHECKED)
500 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_SEARCHDRV);
501 break;
502
503 default:
504 break;
505 }
506 break;
507 }
508
509 default:
510 break;
511 }
512
513 return FALSE;
514 }
515
516 static INT_PTR CALLBACK
517 CHSourceDlgProc(
518 IN HWND hwndDlg,
519 IN UINT uMsg,
520 IN WPARAM wParam,
521 IN LPARAM lParam)
522 {
523 PDEVINSTDATA DevInstData;
524
525 /* Retrieve pointer to the global setup data */
526 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
527
528 switch (uMsg)
529 {
530 case WM_INITDIALOG:
531 {
532 HWND hwndControl;
533 DWORD dwStyle;
534
535 /* Get pointer to the global setup data */
536 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
537 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
538
539 hwndControl = GetParent(hwndDlg);
540
541 /* Center the wizard window */
542 CenterWindow (hwndControl);
543
544 /* Hide the system menu */
545 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
546 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
547
548 SendDlgItemMessage(
549 hwndDlg,
550 IDC_RADIO_SEARCHHERE,
551 BM_SETCHECK,
552 (WPARAM) TRUE,
553 (LPARAM) 0);
554
555 break;
556 }
557
558 case WM_NOTIFY:
559 {
560 LPNMHDR lpnm = (LPNMHDR)lParam;
561
562 switch (lpnm->code)
563 {
564 case PSN_SETACTIVE:
565 /* Enable the Next and Back buttons */
566 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
567 break;
568
569 case PSN_WIZNEXT:
570 /* Handle a Next button click, if necessary */
571 PropSheet_SetCurSel(GetParent(hwndDlg), 0, 4);
572 break;
573
574 default:
575 break;
576 }
577 break;
578 }
579
580 default:
581 break;
582 }
583
584 return FALSE;
585 }
586
587 static INT_PTR CALLBACK
588 SearchDrvDlgProc(
589 IN HWND hwndDlg,
590 IN UINT uMsg,
591 IN WPARAM wParam,
592 IN LPARAM lParam)
593 {
594 PDEVINSTDATA DevInstData;
595 DWORD dwThreadId;
596
597 /* Retrieve pointer to the global setup data */
598 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
599
600 switch (uMsg)
601 {
602 case WM_INITDIALOG:
603 {
604 HWND hwndControl;
605 DWORD dwStyle;
606
607 /* Get pointer to the global setup data */
608 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
609 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
610
611 DevInstData->hDialog = hwndDlg;
612 hwndControl = GetParent(hwndDlg);
613
614 /* Center the wizard window */
615 CenterWindow (hwndControl);
616
617 SendDlgItemMessage(
618 hwndDlg,
619 IDC_DEVICE,
620 WM_SETTEXT,
621 0,
622 (LPARAM) DevInstData->buffer);
623
624 /* Hide the system menu */
625 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
626 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
627 break;
628 }
629
630 case WM_SEARCH_FINISHED:
631 {
632 CloseHandle(hThread);
633 hThread = 0;
634 if (wParam == 0)
635 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_NODRIVER);
636 else
637 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_FINISHPAGE);
638 break;
639 }
640
641 case WM_NOTIFY:
642 {
643 LPNMHDR lpnm = (LPNMHDR)lParam;
644
645 switch (lpnm->code)
646 {
647 case PSN_SETACTIVE:
648 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK);
649 hThread = CreateThread( NULL, 0, FindDriverProc, DevInstData, 0, &dwThreadId);
650 break;
651
652 case PSN_KILLACTIVE:
653 if (hThread != 0)
654 {
655 SetWindowLong ( hwndDlg, DWL_MSGRESULT, TRUE);
656 return TRUE;
657 }
658 break;
659
660 case PSN_WIZNEXT:
661 /* Handle a Next button click, if necessary */
662 break;
663
664 default:
665 break;
666 }
667 break;
668 }
669
670 default:
671 break;
672 }
673
674 return FALSE;
675 }
676
677 static DWORD WINAPI
678 FindDriverProc(
679 IN LPVOID lpParam)
680 {
681 TCHAR drive[] = {'?',':',0};
682 size_t nType;
683 DWORD dwDrives;
684 PDEVINSTDATA DevInstData;
685 DWORD config_flags;
686 UINT i = 1;
687
688 DevInstData = (PDEVINSTDATA)lpParam;
689
690 dwDrives = GetLogicalDrives();
691 for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
692 {
693 if (dwDrives & i)
694 {
695 nType = GetDriveType( drive );
696 if (nType == DRIVE_CDROM)
697 {
698 /* search for inf file */
699 if (SearchDriver ( DevInstData, drive ))
700 {
701 /* if we found a valid driver inf... */
702 if (FindDriver ( DevInstData, NULL ))
703 {
704 InstallDriver ( DevInstData );
705 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 1, 0);
706 return 0;
707 }
708 }
709 }
710 }
711 i <<= 1;
712 }
713
714 /* update device configuration */
715 if (SetupDiGetDeviceRegistryProperty(
716 DevInstData->hDevInfo,
717 &DevInstData->devInfoData,
718 SPDRP_CONFIGFLAGS,
719 NULL,
720 (BYTE *)&config_flags,
721 sizeof(config_flags),
722 NULL))
723 {
724 config_flags |= CONFIGFLAG_FAILEDINSTALL;
725 SetupDiSetDeviceRegistryProperty(
726 DevInstData->hDevInfo,
727 &DevInstData->devInfoData,
728 SPDRP_CONFIGFLAGS,
729 (BYTE *)&config_flags, sizeof(config_flags) );
730 }
731
732 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 0, 0);
733 return 0;
734 }
735
736 static INT_PTR CALLBACK
737 FinishDlgProc(
738 IN HWND hwndDlg,
739 IN UINT uMsg,
740 IN WPARAM wParam,
741 IN LPARAM lParam)
742 {
743
744 PDEVINSTDATA DevInstData;
745
746 /* Retrieve pointer to the global setup data */
747 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
748
749 switch (uMsg)
750 {
751 case WM_INITDIALOG:
752 {
753 HWND hwndControl;
754
755 /* Get pointer to the global setup data */
756 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
757 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
758
759 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
760 ShowWindow (hwndControl, SW_HIDE);
761 EnableWindow (hwndControl, FALSE);
762
763 SendDlgItemMessage(
764 hwndDlg,
765 IDC_DEVICE,
766 WM_SETTEXT,
767 0,
768 (LPARAM) DevInstData->drvInfoData.Description);
769
770 /* Set title font */
771 SendDlgItemMessage(
772 hwndDlg,
773 IDC_FINISHTITLE,
774 WM_SETFONT,
775 (WPARAM)DevInstData->hTitleFont,
776 (LPARAM)TRUE);
777 break;
778 }
779
780 case WM_NOTIFY:
781 {
782 LPNMHDR lpnm = (LPNMHDR)lParam;
783
784 switch (lpnm->code)
785 {
786 case PSN_SETACTIVE:
787 /* Enable the correct buttons on for the active page */
788 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
789 break;
790
791 case PSN_WIZBACK:
792 /* Handle a Back button click, if necessary */
793 break;
794
795 case PSN_WIZFINISH:
796 /* Handle a Finish button click, if necessary */
797 break;
798
799 default:
800 break;
801 }
802 break;
803 }
804
805 default:
806 break;
807 }
808
809 return FALSE;
810 }
811
812 static INT_PTR CALLBACK
813 InstFailDlgProc(
814 IN HWND hwndDlg,
815 IN UINT uMsg,
816 IN WPARAM wParam,
817 IN LPARAM lParam)
818 {
819
820 PDEVINSTDATA DevInstData;
821
822 /* Get pointer to the global setup data */
823 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
824
825 switch (uMsg)
826 {
827 case WM_INITDIALOG:
828 {
829 HWND hwndControl;
830 BOOL DisableableDevice = FALSE;
831
832 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
833 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
834
835 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
836 ShowWindow (hwndControl, SW_HIDE);
837 EnableWindow (hwndControl, FALSE);
838
839 /* Set title font */
840 SendDlgItemMessage(
841 hwndDlg,
842 IDC_FINISHTITLE,
843 WM_SETFONT,
844 (WPARAM)DevInstData->hTitleFont,
845 (LPARAM)TRUE);
846
847 /* disable the "do not show this dialog anymore" checkbox
848 if the device cannot be disabled */
849 CanDisableDevice(
850 DevInstData->devInfoData.DevInst,
851 NULL,
852 &DisableableDevice);
853 EnableWindow(
854 GetDlgItem(hwndDlg, IDC_DONOTSHOWDLG),
855 DisableableDevice);
856 break;
857 }
858
859 case WM_NOTIFY:
860 {
861 LPNMHDR lpnm = (LPNMHDR)lParam;
862
863 switch (lpnm->code)
864 {
865 case PSN_SETACTIVE:
866 /* Enable the correct buttons on for the active page */
867 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
868 break;
869
870 case PSN_WIZBACK:
871 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_WELCOMEPAGE);
872 /* Handle a Back button click, if necessary */
873 break;
874
875 case PSN_WIZFINISH:
876 {
877 BOOL DisableableDevice = FALSE;
878 BOOL IsStarted = FALSE;
879
880 if (CanDisableDevice(DevInstData->devInfoData.DevInst,
881 NULL,
882 &DisableableDevice) &&
883 DisableableDevice &&
884 IsDeviceStarted(
885 DevInstData->devInfoData.DevInst,
886 NULL,
887 &IsStarted) &&
888 !IsStarted &&
889 SendDlgItemMessage(
890 hwndDlg,
891 IDC_DONOTSHOWDLG,
892 BM_GETCHECK,
893 (WPARAM) 0, (LPARAM) 0) == BST_CHECKED)
894 {
895 /* disable the device */
896 StartDevice(
897 DevInstData->hDevInfo,
898 &DevInstData->devInfoData,
899 FALSE,
900 0,
901 NULL);
902 }
903 break;
904 }
905
906 default:
907 break;
908 }
909 break;
910 }
911
912 default:
913 break;
914 }
915
916 return FALSE;
917 }
918
919
920 static BOOL
921 FindDriver(
922 IN PDEVINSTDATA DevInstData,
923 IN LPCWSTR InfFile OPTIONAL)
924 {
925 SP_DEVINSTALL_PARAMS DevInstallParams = {0,};
926 BOOL ret;
927
928 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
929 if (!SetupDiGetDeviceInstallParams(DevInstData->hDevInfo, &DevInstData->devInfoData, &DevInstallParams))
930 {
931 TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
932 return FALSE;
933 }
934 DevInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
935
936 if (InfFile)
937 {
938 DevInstallParams.Flags |= DI_ENUMSINGLEINF;
939 wcscpy(DevInstallParams.DriverPath, InfFile);
940 }
941
942 if (!SetupDiSetDeviceInstallParams(DevInstData->hDevInfo, &DevInstData->devInfoData, &DevInstallParams))
943 {
944 TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
945 return FALSE;
946 }
947
948 ret = SetupDiBuildDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER);
949 if (!ret)
950 {
951 TRACE("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
952 return FALSE;
953 }
954
955 DevInstData->drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
956 ret = SetupDiEnumDriverInfo(
957 DevInstData->hDevInfo,
958 &DevInstData->devInfoData,
959 SPDIT_COMPATDRIVER,
960 0,
961 &DevInstData->drvInfoData);
962 if (!ret)
963 {
964 if (GetLastError() == ERROR_NO_MORE_ITEMS)
965 return FALSE;
966 TRACE("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
967 return FALSE;
968 }
969 TRACE("Installing driver %S: %S\n", DevInstData->drvInfoData.MfgName, DevInstData->drvInfoData.Description);
970
971 return TRUE;
972 }
973
974
975 static BOOL
976 IsDots(IN LPCTSTR str)
977 {
978 if(_tcscmp(str, _T(".")) && _tcscmp(str, _T(".."))) return FALSE;
979 return TRUE;
980 }
981
982 static LPTSTR
983 GetFileExt(IN LPTSTR FileName)
984 {
985 if (FileName == 0)
986 return _T("");
987
988 int i = _tcsclen(FileName);
989 while ((i >= 0) && (FileName[i] != _T('.')))
990 i--;
991
992 FileName = _tcslwr(FileName);
993
994 if (i >= 0)
995 return &FileName[i];
996 else
997 return _T("");
998 }
999
1000 static BOOL
1001 SearchDriver(
1002 IN PDEVINSTDATA DevInstData,
1003 IN LPCTSTR Path)
1004 {
1005 WIN32_FIND_DATA wfd;
1006 SP_DEVINSTALL_PARAMS DevInstallParams;
1007 TCHAR DirPath[MAX_PATH];
1008 TCHAR FileName[MAX_PATH];
1009 TCHAR FullPath[MAX_PATH];
1010 TCHAR LastDirPath[MAX_PATH] = _T("");
1011 TCHAR PathWithPattern[MAX_PATH];
1012 BOOL ok = TRUE;
1013 BOOL ret;
1014 HANDLE hFindFile;
1015
1016 _tcscpy(DirPath, Path);
1017
1018 if (DirPath[_tcsclen(DirPath) - 1] != '\\')
1019 _tcscat(DirPath, _T("\\"));
1020
1021 _tcscpy(PathWithPattern, DirPath);
1022 _tcscat(PathWithPattern, _T("\\*"));
1023
1024 for (hFindFile = FindFirstFile(PathWithPattern, &wfd); ((hFindFile != INVALID_HANDLE_VALUE) && ok); ok = FindNextFile(hFindFile, &wfd))
1025 {
1026
1027 _tcscpy(FileName, wfd.cFileName);
1028 if (IsDots(FileName))
1029 continue;
1030
1031 if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1032 {
1033 _tcscpy(FullPath, DirPath);
1034 _tcscat(FullPath, FileName);
1035 if(SearchDriver(DevInstData, FullPath))
1036 break;
1037 }
1038 else
1039 {
1040 LPCTSTR pszExtension = GetFileExt(FileName);
1041
1042 if ((_tcscmp(pszExtension, _T(".inf")) == 0) && (_tcscmp(LastDirPath, DirPath) != 0))
1043 {
1044 _tcscpy(LastDirPath, DirPath);
1045 ZeroMemory (&DevInstallParams, sizeof(SP_DEVINSTALL_PARAMS));
1046 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1047
1048 ret = SetupDiGetDeviceInstallParams(
1049 DevInstData->hDevInfo,
1050 &DevInstData->devInfoData,
1051 &DevInstallParams);
1052
1053 if (_tcsclen(DirPath) <= MAX_PATH)
1054 {
1055 memcpy(DevInstallParams.DriverPath, DirPath, (_tcsclen(DirPath) + 1) * sizeof(TCHAR));
1056 }
1057
1058 ret = SetupDiSetDeviceInstallParams(
1059 DevInstData->hDevInfo,
1060 &DevInstData->devInfoData,
1061 &DevInstallParams);
1062
1063 if ( FindDriver ( DevInstData, NULL ) )
1064 {
1065 if (hFindFile != INVALID_HANDLE_VALUE)
1066 FindClose(hFindFile);
1067 return TRUE;
1068 }
1069
1070 }
1071 }
1072 }
1073
1074 if (hFindFile != INVALID_HANDLE_VALUE)
1075 FindClose(hFindFile);
1076
1077 return FALSE;
1078 }
1079
1080 static BOOL
1081 InstallDriver(
1082 IN PDEVINSTDATA DevInstData)
1083 {
1084
1085 BOOL ret;
1086
1087 ret = SetupDiCallClassInstaller(
1088 DIF_SELECTBESTCOMPATDRV,
1089 DevInstData->hDevInfo,
1090 &DevInstData->devInfoData);
1091 if (!ret)
1092 {
1093 TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%lx\n", GetLastError());
1094 return FALSE;
1095 }
1096
1097 ret = SetupDiCallClassInstaller(
1098 DIF_ALLOW_INSTALL,
1099 DevInstData->hDevInfo,
1100 &DevInstData->devInfoData);
1101 if (!ret)
1102 {
1103 TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%lx\n", GetLastError());
1104 return FALSE;
1105 }
1106
1107 ret = SetupDiCallClassInstaller(
1108 DIF_NEWDEVICEWIZARD_PREANALYZE,
1109 DevInstData->hDevInfo,
1110 &DevInstData->devInfoData);
1111 if (!ret)
1112 {
1113 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%lx\n", GetLastError());
1114 return FALSE;
1115 }
1116
1117 ret = SetupDiCallClassInstaller(
1118 DIF_NEWDEVICEWIZARD_POSTANALYZE,
1119 DevInstData->hDevInfo,
1120 &DevInstData->devInfoData);
1121 if (!ret)
1122 {
1123 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%lx\n", GetLastError());
1124 return FALSE;
1125 }
1126
1127 ret = SetupDiCallClassInstaller(
1128 DIF_INSTALLDEVICEFILES,
1129 DevInstData->hDevInfo,
1130 &DevInstData->devInfoData);
1131 if (!ret)
1132 {
1133 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%lx\n", GetLastError());
1134 return FALSE;
1135 }
1136
1137 ret = SetupDiCallClassInstaller(
1138 DIF_REGISTER_COINSTALLERS,
1139 DevInstData->hDevInfo,
1140 &DevInstData->devInfoData);
1141 if (!ret)
1142 {
1143 TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%lx\n", GetLastError());
1144 return FALSE;
1145 }
1146
1147 ret = SetupDiCallClassInstaller(
1148 DIF_INSTALLINTERFACES,
1149 DevInstData->hDevInfo,
1150 &DevInstData->devInfoData);
1151 if (!ret)
1152 {
1153 TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%lx\n", GetLastError());
1154 return FALSE;
1155 }
1156
1157 ret = SetupDiCallClassInstaller(
1158 DIF_INSTALLDEVICE,
1159 DevInstData->hDevInfo,
1160 &DevInstData->devInfoData);
1161 if (!ret)
1162 {
1163 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%lx\n", GetLastError());
1164 return FALSE;
1165 }
1166
1167 ret = SetupDiCallClassInstaller(
1168 DIF_NEWDEVICEWIZARD_FINISHINSTALL,
1169 DevInstData->hDevInfo,
1170 &DevInstData->devInfoData);
1171 if (!ret)
1172 {
1173 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%lx\n", GetLastError());
1174 return FALSE;
1175 }
1176
1177 ret = SetupDiCallClassInstaller(
1178 DIF_DESTROYPRIVATEDATA,
1179 DevInstData->hDevInfo,
1180 &DevInstData->devInfoData);
1181 if (!ret)
1182 {
1183 TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%lx\n", GetLastError());
1184 return FALSE;
1185 }
1186
1187 return TRUE;
1188 }
1189
1190 static VOID
1191 CleanUp(VOID)
1192 {
1193
1194 if (DevInstData.devInfoData.cbSize != 0)
1195 {
1196 if (!SetupDiDestroyDriverInfoList(DevInstData.hDevInfo, &DevInstData.devInfoData, SPDIT_COMPATDRIVER))
1197 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
1198 }
1199
1200 if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE)
1201 {
1202 if (!SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo))
1203 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
1204 }
1205
1206 if (DevInstData.buffer)
1207 HeapFree(GetProcessHeap(), 0, DevInstData.buffer);
1208
1209 }
1210
1211 /*
1212 * @implemented
1213 */
1214 BOOL WINAPI
1215 DevInstallW(
1216 IN HWND hWndParent,
1217 IN HINSTANCE hInstance,
1218 IN LPCWSTR InstanceId,
1219 IN INT Show)
1220 {
1221
1222 PROPSHEETHEADER psh;
1223 HPROPSHEETPAGE ahpsp[5];
1224 PROPSHEETPAGE psp;
1225 BOOL ret;
1226 DWORD config_flags;
1227
1228 if (!IsUserAdmin())
1229 {
1230 /* XP kills the process... */
1231 ExitProcess(ERROR_ACCESS_DENIED);
1232 }
1233
1234 /* Clear devinst data */
1235 ZeroMemory(&DevInstData, sizeof(DEVINSTDATA));
1236 DevInstData.devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
1237
1238 DevInstData.hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
1239 if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE)
1240 {
1241 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%lx\n", GetLastError());
1242 CleanUp();
1243 return FALSE;
1244 }
1245
1246 DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1247 ret = SetupDiOpenDeviceInfoW(
1248 DevInstData.hDevInfo,
1249 InstanceId,
1250 NULL,
1251 0, /* Open flags */
1252 &DevInstData.devInfoData);
1253 if (!ret)
1254 {
1255 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId);
1256 DevInstData.devInfoData.cbSize = 0;
1257 CleanUp();
1258 return FALSE;
1259 }
1260
1261 SetLastError(ERROR_GEN_FAILURE);
1262 ret = SetupDiGetDeviceRegistryProperty(
1263 DevInstData.hDevInfo,
1264 &DevInstData.devInfoData,
1265 SPDRP_DEVICEDESC,
1266 &DevInstData.regDataType,
1267 NULL, 0,
1268 &DevInstData.requiredSize);
1269
1270 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData.regDataType == REG_SZ)
1271 {
1272 DevInstData.buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData.requiredSize);
1273 if (!DevInstData.buffer)
1274 {
1275 TRACE("HeapAlloc() failed\n");
1276 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1277 }
1278 else
1279 {
1280 ret = SetupDiGetDeviceRegistryProperty(
1281 DevInstData.hDevInfo,
1282 &DevInstData.devInfoData,
1283 SPDRP_DEVICEDESC,
1284 &DevInstData.regDataType,
1285 DevInstData.buffer, DevInstData.requiredSize,
1286 &DevInstData.requiredSize);
1287 }
1288 }
1289 if (!ret)
1290 {
1291 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId);
1292 CleanUp();
1293 return FALSE;
1294 }
1295
1296 if (SetupDiGetDeviceRegistryProperty(
1297 DevInstData.hDevInfo,
1298 &DevInstData.devInfoData,
1299 SPDRP_CONFIGFLAGS,
1300 NULL,
1301 (BYTE *)&config_flags,
1302 sizeof(config_flags),
1303 NULL))
1304 {
1305 if (config_flags & CONFIGFLAG_FAILEDINSTALL)
1306 {
1307 CleanUp();
1308 return TRUE;
1309 }
1310 }
1311
1312 TRACE("Installing %S (%S)\n", DevInstData.buffer, InstanceId);
1313
1314 if ((!FindDriver(&DevInstData, NULL)) && (Show != SW_HIDE))
1315 {
1316
1317 /* Create the Welcome page */
1318 ZeroMemory (&psp, sizeof(PROPSHEETPAGE));
1319 psp.dwSize = sizeof(PROPSHEETPAGE);
1320 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1321 psp.hInstance = hDllInstance;
1322 psp.lParam = (LPARAM)&DevInstData;
1323 psp.pfnDlgProc = WelcomeDlgProc;
1324 psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
1325 ahpsp[IDD_WELCOMEPAGE] = CreatePropertySheetPage(&psp);
1326
1327 /* Create the Select Source page */
1328 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
1329 psp.pfnDlgProc = CHSourceDlgProc;
1330 psp.pszTemplate = MAKEINTRESOURCE(IDD_CHSOURCE);
1331 ahpsp[IDD_CHSOURCE] = CreatePropertySheetPage(&psp);
1332
1333 /* Create the Search driver page */
1334 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
1335 psp.pfnDlgProc = SearchDrvDlgProc;
1336 psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHDRV);
1337 ahpsp[IDD_SEARCHDRV] = CreatePropertySheetPage(&psp);
1338
1339 /* Create the Finish page */
1340 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1341 psp.pfnDlgProc = FinishDlgProc;
1342 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
1343 ahpsp[IDD_FINISHPAGE] = CreatePropertySheetPage(&psp);
1344
1345 /* Create the Install failed page */
1346 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1347 psp.pfnDlgProc = InstFailDlgProc;
1348 psp.pszTemplate = MAKEINTRESOURCE(IDD_NODRIVER);
1349 ahpsp[IDD_NODRIVER] = CreatePropertySheetPage(&psp);
1350
1351 /* Create the property sheet */
1352 psh.dwSize = sizeof(PROPSHEETHEADER);
1353 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
1354 psh.hInstance = hDllInstance;
1355 psh.hwndParent = NULL;
1356 psh.nPages = 5;
1357 psh.nStartPage = 0;
1358 psh.phpage = ahpsp;
1359 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
1360 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
1361
1362 /* Create title font */
1363 DevInstData.hTitleFont = CreateTitleFont();
1364
1365 /* Display the wizard */
1366 PropertySheet(&psh);
1367
1368 DeleteObject(DevInstData.hTitleFont);
1369
1370 }
1371 else
1372 {
1373 InstallDriver ( &DevInstData );
1374 }
1375
1376 CleanUp();
1377 return TRUE;
1378 }
1379
1380 /*
1381 * @unimplemented
1382 */
1383 BOOL WINAPI
1384 ClientSideInstallW(
1385 IN HWND hWndOwner,
1386 IN DWORD dwUnknownFlags,
1387 IN LPWSTR lpNamedPipeName)
1388 {
1389 /* NOTE: pNamedPipeName is in the format:
1390 * "\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
1391 */
1392 FIXME("Stub\n");
1393 return FALSE;
1394 }
1395
1396 BOOL WINAPI
1397 DllMain(
1398 IN HINSTANCE hInstance,
1399 IN DWORD dwReason,
1400 IN LPVOID lpReserved)
1401 {
1402 if (dwReason == DLL_PROCESS_ATTACH)
1403 {
1404 INITCOMMONCONTROLSEX InitControls;
1405
1406 DisableThreadLibraryCalls(hInstance);
1407
1408 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
1409 InitControls.dwICC = ICC_PROGRESS_CLASS;
1410 InitCommonControlsEx(&InitControls);
1411 hDllInstance = hInstance;
1412 }
1413
1414 return TRUE;
1415 }