1 /*
2  * Provides default drive shell extension
3  *
4  * Copyright 2005 Johannes Anderwald
5  * Copyright 2012 Rafal Harabien
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "precomp.h"
23 
24 #define _USE_MATH_DEFINES
25 #include <math.h>
26 
27 WINE_DEFAULT_DEBUG_CHANNEL(shell);
28 
29 static const GUID GUID_DEVCLASS_DISKDRIVE = {0x4d36e967L, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
30 
31 typedef enum
32 {
33     HWPD_STANDARDLIST = 0,
34     HWPD_LARGELIST,
35     HWPD_MAX = HWPD_LARGELIST
36 } HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
37 
38 EXTERN_C HWND WINAPI
39 DeviceCreateHardwarePageEx(HWND hWndParent,
40                            LPGUID lpGuids,
41                            UINT uNumberOfGuids,
42                            HWPAGE_DISPLAYMODE DisplayMode);
43 UINT SH_FormatByteSize(LONGLONG cbSize, LPWSTR pwszResult, UINT cchResultMax);
44 
45 static VOID
46 GetDriveNameWithLetter(LPWSTR pwszText, UINT cchTextMax, LPCWSTR pwszDrive)
47 {
48     DWORD dwMaxComp, dwFileSys;
49     SIZE_T cchText = 0;
50 
51     if (GetVolumeInformationW(pwszDrive, pwszText, cchTextMax, NULL, &dwMaxComp, &dwFileSys, NULL, 0))
52     {
53         cchText = wcslen(pwszText);
54         if (cchText == 0)
55         {
56             /* load default volume label */
57             cchText = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, pwszText, cchTextMax);
58         }
59     }
60 
61     StringCchPrintfW(pwszText + cchText, cchTextMax - cchText, L" (%c:)", pwszDrive[0]);
62 }
63 
64 static VOID
65 InitializeChkDskDialog(HWND hwndDlg, LPCWSTR pwszDrive)
66 {
67     WCHAR wszText[100];
68     UINT Length;
69     SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pwszDrive);
70 
71     Length = GetWindowTextW(hwndDlg, wszText, sizeof(wszText) / sizeof(WCHAR));
72     wszText[Length] = L' ';
73     GetDriveNameWithLetter(&wszText[Length + 1], (sizeof(wszText) / sizeof(WCHAR)) - Length - 1, pwszDrive);
74     SetWindowText(hwndDlg, wszText);
75 }
76 
77 static HWND hChkdskDrvDialog = NULL;
78 static BOOLEAN bChkdskSuccess = FALSE;
79 
80 static BOOLEAN NTAPI
81 ChkdskCallback(
82     IN CALLBACKCOMMAND Command,
83     IN ULONG SubAction,
84     IN PVOID ActionInfo)
85 {
86     PDWORD Progress;
87     PBOOLEAN pSuccess;
88     switch(Command)
89     {
90         case PROGRESS:
91             Progress = (PDWORD)ActionInfo;
92             SendDlgItemMessageW(hChkdskDrvDialog, 14002, PBM_SETPOS, (WPARAM)*Progress, 0);
93             break;
94         case DONE:
95             pSuccess = (PBOOLEAN)ActionInfo;
96             bChkdskSuccess = (*pSuccess);
97             break;
98 
99         case VOLUMEINUSE:
100         case INSUFFICIENTRIGHTS:
101         case FSNOTSUPPORTED:
102         case CLUSTERSIZETOOSMALL:
103             bChkdskSuccess = FALSE;
104             FIXME("\n");
105             break;
106 
107         default:
108             break;
109     }
110 
111     return TRUE;
112 }
113 
114 static VOID
115 ChkDskNow(HWND hwndDlg, LPCWSTR pwszDrive)
116 {
117     //DWORD ClusterSize = 0;
118     WCHAR wszFs[30];
119     ULARGE_INTEGER TotalNumberOfFreeBytes, FreeBytesAvailableUser;
120     BOOLEAN bCorrectErrors = FALSE, bScanDrive = FALSE;
121 
122     if(!GetVolumeInformationW(pwszDrive, NULL, 0, NULL, NULL, NULL, wszFs, _countof(wszFs)))
123     {
124         FIXME("failed to get drive fs type\n");
125         return;
126     }
127 
128     if (!GetDiskFreeSpaceExW(pwszDrive, &FreeBytesAvailableUser, &TotalNumberOfFreeBytes, NULL))
129     {
130         FIXME("failed to get drive space type\n");
131         return;
132     }
133 
134     /*if (!GetDefaultClusterSize(wszFs, &ClusterSize, &TotalNumberOfFreeBytes))
135     {
136         FIXME("invalid cluster size\n");
137         return;
138     }*/
139 
140     if (SendDlgItemMessageW(hwndDlg, 14000, BM_GETCHECK, 0, 0) == BST_CHECKED)
141         bCorrectErrors = TRUE;
142 
143     if (SendDlgItemMessageW(hwndDlg, 14001, BM_GETCHECK, 0, 0) == BST_CHECKED)
144         bScanDrive = TRUE;
145 
146     hChkdskDrvDialog = hwndDlg;
147     bChkdskSuccess = FALSE;
148     SendDlgItemMessageW(hwndDlg, 14002, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
149     Chkdsk((LPWSTR)pwszDrive, (LPWSTR)wszFs, bCorrectErrors, TRUE, FALSE, bScanDrive, NULL, NULL, ChkdskCallback); // FIXME: casts
150 
151     hChkdskDrvDialog = NULL;
152     bChkdskSuccess = FALSE;
153 }
154 
155 static INT_PTR CALLBACK
156 ChkDskDlg(
157     HWND hwndDlg,
158     UINT uMsg,
159     WPARAM wParam,
160     LPARAM lParam)
161 {
162     switch(uMsg)
163     {
164         case WM_INITDIALOG:
165             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
166             InitializeChkDskDialog(hwndDlg, (LPCWSTR)lParam);
167             return TRUE;
168         case WM_COMMAND:
169             switch(LOWORD(wParam))
170             {
171                 case IDCANCEL:
172                     EndDialog(hwndDlg, 0);
173                     break;
174                 case IDOK:
175                 {
176                     LPCWSTR pwszDrive = (LPCWSTR)GetWindowLongPtr(hwndDlg, DWLP_USER);
177                     ChkDskNow(hwndDlg, pwszDrive);
178                     break;
179                 }
180             }
181             break;
182     }
183 
184     return FALSE;
185 }
186 
187 VOID
188 CDrvDefExt::PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT pDrawItem)
189 {
190     HBRUSH hBrush;
191 
192     if (pDrawItem->CtlID == 14013)
193     {
194         hBrush = CreateSolidBrush(RGB(0, 0, 255));
195         if (hBrush)
196         {
197             FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush);
198             DeleteObject((HGDIOBJ)hBrush);
199         }
200     }
201     else if (pDrawItem->CtlID == 14014)
202     {
203         hBrush = CreateSolidBrush(RGB(255, 0, 255));
204         if (hBrush)
205         {
206             FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush);
207             DeleteObject((HGDIOBJ)hBrush);
208         }
209     }
210     else if (pDrawItem->CtlID == 14015)
211     {
212         HBRUSH hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
213         HBRUSH hMagBrush = CreateSolidBrush(RGB(255, 0, 255));
214         HBRUSH hbrOld;
215         HPEN hDarkBluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 128));
216         HPEN hDarkMagPen = CreatePen(PS_SOLID, 1, RGB(128, 0, 128));
217         HPEN hOldPen = (HPEN)SelectObject(pDrawItem->hDC, hDarkMagPen);
218         INT xCenter = (pDrawItem->rcItem.left + pDrawItem->rcItem.right) / 2;
219         INT yCenter = (pDrawItem->rcItem.top + pDrawItem->rcItem.bottom - 10) / 2;
220         INT cx = pDrawItem->rcItem.right - pDrawItem->rcItem.left;
221         INT cy = pDrawItem->rcItem.bottom - pDrawItem->rcItem.top - 10;
222         INT xRadial = xCenter + (INT)(cos(M_PI + m_FreeSpacePerc / 100.0f * M_PI * 2.0f) * cx / 2);
223         INT yRadial = yCenter - (INT)(sin(M_PI + m_FreeSpacePerc / 100.0f * M_PI * 2.0f) * cy / 2);
224 
225         TRACE("FreeSpace %u a %f cx %d\n", m_FreeSpacePerc, M_PI+m_FreeSpacePerc / 100.0f * M_PI * 2.0f, cx);
226 
227         for (INT x = pDrawItem->rcItem.left; x < pDrawItem->rcItem.right; ++x)
228         {
229             double cos_val = (x - xCenter) * 2.0f / cx;
230             INT y = yCenter + (INT)(sin(acos(cos_val)) * cy / 2) - 1;
231 
232             if (m_FreeSpacePerc < 50 && x == xRadial)
233                 SelectObject(pDrawItem->hDC, hDarkBluePen);
234 
235             MoveToEx(pDrawItem->hDC, x, y, NULL);
236             LineTo(pDrawItem->hDC, x, y + 10);
237         }
238 
239         SelectObject(pDrawItem->hDC, hOldPen);
240 
241         if (m_FreeSpacePerc > 50)
242         {
243             hbrOld = (HBRUSH)SelectObject(pDrawItem->hDC, hMagBrush);
244 
245             Ellipse(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top,
246                     pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10);
247 
248             SelectObject(pDrawItem->hDC, hBlueBrush);
249 
250             if (m_FreeSpacePerc < 100)
251             {
252                 Pie(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, pDrawItem->rcItem.right,
253                     pDrawItem->rcItem.bottom - 10, xRadial, yRadial, pDrawItem->rcItem.left, yCenter);
254             }
255         }
256         else
257         {
258             hbrOld = (HBRUSH)SelectObject(pDrawItem->hDC, hBlueBrush);
259 
260             Ellipse(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top,
261                     pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10);
262 
263             SelectObject(pDrawItem->hDC, hMagBrush);
264 
265             if (m_FreeSpacePerc > 0)
266             {
267                 Pie(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, pDrawItem->rcItem.right,
268                     pDrawItem->rcItem.bottom - 10, pDrawItem->rcItem.left, yCenter, xRadial, yRadial);
269             }
270         }
271 
272         SelectObject(pDrawItem->hDC, hbrOld);
273 
274         DeleteObject(hBlueBrush);
275         DeleteObject(hMagBrush);
276         DeleteObject(hDarkBluePen);
277         DeleteObject(hDarkMagPen);
278     }
279 }
280 
281 VOID
282 CDrvDefExt::InitGeneralPage(HWND hwndDlg)
283 {
284     WCHAR wszVolumeName[MAX_PATH+1] = {0};
285     WCHAR wszFileSystem[MAX_PATH+1] = {0};
286     WCHAR wszBuf[128];
287     BOOL bRet;
288 
289     bRet = GetVolumeInformationW(m_wszDrive, wszVolumeName, _countof(wszVolumeName), NULL, NULL, NULL, wszFileSystem, _countof(wszFileSystem));
290     if (bRet)
291     {
292         /* Set volume label and filesystem */
293         SetDlgItemTextW(hwndDlg, 14000, wszVolumeName);
294         SetDlgItemTextW(hwndDlg, 14002, wszFileSystem);
295     }
296     else
297     {
298         LoadStringW(shell32_hInstance, IDS_FS_UNKNOWN, wszFileSystem, _countof(wszFileSystem));
299         SetDlgItemTextW(hwndDlg, 14002, wszFileSystem);
300     }
301 
302     /* Set drive type and icon */
303     UINT DriveType = GetDriveTypeW(m_wszDrive);
304     UINT IconId, TypeStrId = 0;
305     switch (DriveType)
306     {
307         case DRIVE_REMOVABLE: IconId = IDI_SHELL_3_14_FLOPPY; break;
308         case DRIVE_CDROM: IconId = IDI_SHELL_CDROM; TypeStrId = IDS_DRIVE_CDROM; break;
309         case DRIVE_REMOTE: IconId = IDI_SHELL_NETDRIVE; TypeStrId = IDS_DRIVE_NETWORK; break;
310         case DRIVE_RAMDISK: IconId = IDI_SHELL_RAMDISK; break;
311         default: IconId = IDI_SHELL_DRIVE; TypeStrId = IDS_DRIVE_FIXED;
312     }
313 
314     if (DriveType == DRIVE_CDROM || DriveType == DRIVE_REMOTE)
315     {
316         /* volume label textbox */
317         SendMessage(GetDlgItem(hwndDlg, 14000), EM_SETREADONLY, TRUE, 0);
318 
319         /* disk compression */
320         ShowWindow(GetDlgItem(hwndDlg, 14011), FALSE);
321 
322         /* index */
323         ShowWindow(GetDlgItem(hwndDlg, 14012), FALSE);
324     }
325 
326     HICON hIcon = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IconId), IMAGE_ICON, 32, 32, LR_SHARED);
327     if (hIcon)
328         SendDlgItemMessageW(hwndDlg, 14016, STM_SETICON, (WPARAM)hIcon, 0);
329     if (TypeStrId && LoadStringW(shell32_hInstance, TypeStrId, wszBuf, _countof(wszBuf)))
330         SetDlgItemTextW(hwndDlg, 14001, wszBuf);
331 
332     ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes;
333     if(GetDiskFreeSpaceExW(m_wszDrive, &FreeBytesAvailable, &TotalNumberOfBytes, NULL))
334     {
335         /* Init free space percentage used for drawing piechart */
336         m_FreeSpacePerc = (UINT)(FreeBytesAvailable.QuadPart * 100ull / TotalNumberOfBytes.QuadPart);
337 
338         /* Used space */
339         if (SH_FormatByteSize(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
340             SetDlgItemTextW(hwndDlg, 14003, wszBuf);
341 
342         if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
343             SetDlgItemTextW(hwndDlg, 14004, wszBuf);
344 
345         /* Free space */
346         if (SH_FormatByteSize(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
347             SetDlgItemTextW(hwndDlg, 14005, wszBuf);
348 
349         if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
350             SetDlgItemTextW(hwndDlg, 14006, wszBuf);
351 
352         /* Total space */
353         if (SH_FormatByteSize(TotalNumberOfBytes.QuadPart, wszBuf, _countof(wszBuf)))
354             SetDlgItemTextW(hwndDlg, 14007, wszBuf);
355 
356         if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, wszBuf, _countof(wszBuf)))
357             SetDlgItemTextW(hwndDlg, 14008, wszBuf);
358     }
359     else
360     {
361         m_FreeSpacePerc = 0;
362 
363         if (SH_FormatByteSize(0, wszBuf, _countof(wszBuf)))
364         {
365             SetDlgItemTextW(hwndDlg, 14003, wszBuf);
366             SetDlgItemTextW(hwndDlg, 14005, wszBuf);
367             SetDlgItemTextW(hwndDlg, 14007, wszBuf);
368         }
369         if (StrFormatByteSizeW(0, wszBuf, _countof(wszBuf)))
370         {
371             SetDlgItemTextW(hwndDlg, 14004, wszBuf);
372             SetDlgItemTextW(hwndDlg, 14006, wszBuf);
373             SetDlgItemTextW(hwndDlg, 14008, wszBuf);
374         }
375     }
376 
377     /* Set drive description */
378     WCHAR wszFormat[50];
379     GetDlgItemTextW(hwndDlg, 14009, wszFormat, _countof(wszFormat));
380     swprintf(wszBuf, wszFormat, m_wszDrive[0]);
381     SetDlgItemTextW(hwndDlg, 14009, wszBuf);
382 
383     /* show disk cleanup button only for fixed drives */
384     ShowWindow(GetDlgItem(hwndDlg, 14010), DriveType == DRIVE_FIXED);
385 }
386 
387 INT_PTR CALLBACK
388 CDrvDefExt::GeneralPageProc(
389     HWND hwndDlg,
390     UINT uMsg,
391     WPARAM wParam,
392     LPARAM lParam)
393 {
394     switch(uMsg)
395     {
396         case WM_INITDIALOG:
397         {
398             LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
399             if (ppsp == NULL)
400                 break;
401 
402             CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(ppsp->lParam);
403             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDrvDefExt);
404             pDrvDefExt->InitGeneralPage(hwndDlg);
405             return TRUE;
406         }
407         case WM_DRAWITEM:
408         {
409             LPDRAWITEMSTRUCT pDrawItem = (LPDRAWITEMSTRUCT)lParam;
410 
411             if (pDrawItem->CtlID >= 14013 && pDrawItem->CtlID <= 14015)
412             {
413                 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
414                 pDrvDefExt->PaintStaticControls(hwndDlg, pDrawItem);
415                 return TRUE;
416             }
417             break;
418         }
419         case WM_PAINT:
420             break;
421         case WM_COMMAND:
422             if (LOWORD(wParam) == 14010) /* Disk Cleanup */
423             {
424                 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
425                 WCHAR wszBuf[256];
426                 DWORD cbBuf = sizeof(wszBuf);
427 
428                 if (RegGetValueW(HKEY_LOCAL_MACHINE,
429                                  L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\CleanupPath",
430                                  NULL,
431                                  RRF_RT_REG_SZ,
432                                  NULL,
433                                  (PVOID)wszBuf,
434                                  &cbBuf) == ERROR_SUCCESS)
435                 {
436                     WCHAR wszCmd[MAX_PATH];
437 
438                     StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]);
439 
440                     if (ShellExecuteW(hwndDlg, NULL, wszCmd, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
441                         ERR("Failed to create cleanup process %ls\n", wszCmd);
442                 }
443             }
444             else if (LOWORD(wParam) == 14000) /* Label */
445             {
446                 if (HIWORD(wParam) == EN_CHANGE)
447                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
448             }
449             break;
450         case WM_NOTIFY:
451             if (((LPNMHDR)lParam)->hwndFrom == GetParent(hwndDlg))
452             {
453                 /* Property Sheet */
454                 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
455 
456                 if (lppsn->hdr.code == PSN_APPLY)
457                 {
458                     CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
459                     WCHAR wszBuf[256];
460 
461                     if (GetDlgItemTextW(hwndDlg, 14000, wszBuf, _countof(wszBuf)))
462                         SetVolumeLabelW(pDrvDefExt->m_wszDrive, wszBuf);
463                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
464                     return TRUE;
465                 }
466             }
467             break;
468 
469         default:
470             break;
471     }
472 
473     return FALSE;
474 }
475 
476 INT_PTR CALLBACK
477 CDrvDefExt::ExtraPageProc(
478     HWND hwndDlg,
479     UINT uMsg,
480     WPARAM wParam,
481     LPARAM lParam)
482 {
483     switch (uMsg)
484     {
485         case WM_INITDIALOG:
486         {
487             LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
488             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam);
489             return TRUE;
490         }
491         case WM_COMMAND:
492         {
493             WCHAR wszBuf[MAX_PATH];
494             DWORD cbBuf = sizeof(wszBuf);
495             CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
496 
497             switch(LOWORD(wParam))
498             {
499                 case 14000:
500                     DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_CHECK_DISK), hwndDlg, ChkDskDlg, (LPARAM)pDrvDefExt->m_wszDrive);
501                     break;
502                 case 14001:
503                     if (RegGetValueW(HKEY_LOCAL_MACHINE,
504                                      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath",
505                                      NULL,
506                                      RRF_RT_REG_SZ,
507                                      NULL,
508                                      (PVOID)wszBuf,
509                                      &cbBuf) == ERROR_SUCCESS)
510                     {
511                         WCHAR wszCmd[MAX_PATH];
512 
513                         StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]);
514 
515                         if (ShellExecuteW(hwndDlg, NULL, wszCmd, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
516                             ERR("Failed to create defrag process %ls\n", wszCmd);
517                     }
518                     break;
519                 case 14002:
520                     if (RegGetValueW(HKEY_LOCAL_MACHINE,
521                                      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath",
522                                      NULL,
523                                      RRF_RT_REG_SZ,
524                                      NULL,
525                                      (PVOID)wszBuf,
526                                      &cbBuf) == ERROR_SUCCESS)
527                     {
528                         if (ShellExecuteW(hwndDlg, NULL, wszBuf, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
529                             ERR("Failed to create backup process %ls\n", wszBuf);
530                     }
531             }
532             break;
533         }
534     }
535     return FALSE;
536 }
537 
538 INT_PTR CALLBACK
539 CDrvDefExt::HardwarePageProc(
540     HWND hwndDlg,
541     UINT uMsg,
542     WPARAM wParam,
543     LPARAM lParam)
544 {
545     UNREFERENCED_PARAMETER(lParam);
546     UNREFERENCED_PARAMETER(wParam);
547 
548     switch(uMsg)
549     {
550         case WM_INITDIALOG:
551         {
552             GUID Guid = GUID_DEVCLASS_DISKDRIVE;
553 
554             /* create the hardware page */
555             DeviceCreateHardwarePageEx(hwndDlg, &Guid, 1, HWPD_STANDARDLIST);
556             break;
557         }
558     }
559 
560     return FALSE;
561 }
562 
563 CDrvDefExt::CDrvDefExt()
564 {
565     m_wszDrive[0] = L'\0';
566 }
567 
568 CDrvDefExt::~CDrvDefExt()
569 {
570 
571 }
572 
573 HRESULT WINAPI
574 CDrvDefExt::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDataObj, HKEY hkeyProgID)
575 {
576     FORMATETC format;
577     STGMEDIUM stgm;
578     HRESULT hr;
579 
580     TRACE("%p %p %p %p\n", this, pidlFolder, pDataObj, hkeyProgID);
581 
582     if (!pDataObj)
583         return E_FAIL;
584 
585     format.cfFormat = CF_HDROP;
586     format.ptd = NULL;
587     format.dwAspect = DVASPECT_CONTENT;
588     format.lindex = -1;
589     format.tymed = TYMED_HGLOBAL;
590 
591     hr = pDataObj->GetData(&format, &stgm);
592     if (FAILED(hr))
593         return hr;
594 
595     if (!DragQueryFileW((HDROP)stgm.hGlobal, 0, m_wszDrive, _countof(m_wszDrive)))
596     {
597         ERR("DragQueryFileW failed\n");
598         ReleaseStgMedium(&stgm);
599         return E_FAIL;
600     }
601 
602     ReleaseStgMedium(&stgm);
603     TRACE("Drive properties %ls\n", m_wszDrive);
604 
605     return S_OK;
606 }
607 
608 HRESULT WINAPI
609 CDrvDefExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
610 {
611     UNIMPLEMENTED;
612     return E_NOTIMPL;
613 }
614 
615 HRESULT WINAPI
616 CDrvDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
617 {
618     UNIMPLEMENTED;
619     return E_NOTIMPL;
620 }
621 
622 HRESULT WINAPI
623 CDrvDefExt::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax)
624 {
625     UNIMPLEMENTED;
626     return E_NOTIMPL;
627 }
628 
629 HRESULT WINAPI
630 CDrvDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
631 {
632     HPROPSHEETPAGE hPage;
633 
634     hPage = SH_CreatePropertySheetPage(IDD_DRIVE_PROPERTIES,
635                                        GeneralPageProc,
636                                        (LPARAM)this,
637                                        NULL);
638     if (hPage)
639         pfnAddPage(hPage, lParam);
640 
641     if (GetDriveTypeW(m_wszDrive) == DRIVE_FIXED)
642     {
643         hPage = SH_CreatePropertySheetPage(IDD_DRIVE_TOOLS,
644                                            ExtraPageProc,
645                                            (LPARAM)this,
646                                            NULL);
647         if (hPage)
648             pfnAddPage(hPage, lParam);
649     }
650 
651     if (GetDriveTypeW(m_wszDrive) != DRIVE_REMOTE)
652     {
653         hPage = SH_CreatePropertySheetPage(IDD_DRIVE_HARDWARE,
654                                            HardwarePageProc,
655                                            (LPARAM)this,
656                                            NULL);
657         if (hPage)
658             pfnAddPage(hPage, lParam);
659     }
660 
661     return S_OK;
662 }
663 
664 HRESULT WINAPI
665 CDrvDefExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam)
666 {
667     UNIMPLEMENTED;
668     return E_NOTIMPL;
669 }
670 
671 HRESULT WINAPI
672 CDrvDefExt::SetSite(IUnknown *punk)
673 {
674     UNIMPLEMENTED;
675     return E_NOTIMPL;
676 }
677 
678 HRESULT WINAPI
679 CDrvDefExt::GetSite(REFIID iid, void **ppvSite)
680 {
681     UNIMPLEMENTED;
682     return E_NOTIMPL;
683 }
684