1 /*
2  * Provides default drive shell extension
3  *
4  * Copyright 2005 Johannes Anderwald
5  * Copyright 2012 Rafal Harabien
6  * Copyright 2020 Katayama Hirofumi MZ
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include "precomp.h"
24 
25 #define _USE_MATH_DEFINES
26 #include <math.h>
27 #include <devguid.h>
28 
29 #define NTOS_MODE_USER
30 #include <ndk/iofuncs.h>
31 #include <ndk/obfuncs.h>
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(shell);
34 
35 typedef enum
36 {
37     HWPD_STANDARDLIST = 0,
38     HWPD_LARGELIST,
39     HWPD_MAX = HWPD_LARGELIST
40 } HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
41 
42 EXTERN_C HWND WINAPI
43 DeviceCreateHardwarePageEx(HWND hWndParent,
44                            LPGUID lpGuids,
45                            UINT uNumberOfGuids,
46                            HWPAGE_DISPLAYMODE DisplayMode);
47 UINT SH_FormatByteSize(LONGLONG cbSize, LPWSTR pwszResult, UINT cchResultMax);
48 
49 static VOID
GetDriveNameWithLetter(LPWSTR pwszText,UINT cchTextMax,LPCWSTR pwszDrive)50 GetDriveNameWithLetter(LPWSTR pwszText, UINT cchTextMax, LPCWSTR pwszDrive)
51 {
52     DWORD dwMaxComp, dwFileSys;
53     SIZE_T cchText = 0;
54 
55     if (GetVolumeInformationW(pwszDrive, pwszText, cchTextMax, NULL, &dwMaxComp, &dwFileSys, NULL, 0))
56     {
57         cchText = wcslen(pwszText);
58         if (cchText == 0)
59         {
60             /* load default volume label */
61             cchText = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, pwszText, cchTextMax);
62         }
63     }
64 
65     StringCchPrintfW(pwszText + cchText, cchTextMax - cchText, L" (%c:)", pwszDrive[0]);
66 }
67 
68 static VOID
InitializeChkDskDialog(HWND hwndDlg,LPCWSTR pwszDrive)69 InitializeChkDskDialog(HWND hwndDlg, LPCWSTR pwszDrive)
70 {
71     WCHAR wszText[100];
72     UINT Length;
73     SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pwszDrive);
74 
75     Length = GetWindowTextW(hwndDlg, wszText, sizeof(wszText) / sizeof(WCHAR));
76     wszText[Length] = L' ';
77     GetDriveNameWithLetter(&wszText[Length + 1], (sizeof(wszText) / sizeof(WCHAR)) - Length - 1, pwszDrive);
78     SetWindowText(hwndDlg, wszText);
79 }
80 
81 static HWND hChkdskDrvDialog = NULL;
82 static BOOLEAN bChkdskSuccess = FALSE;
83 
84 static BOOLEAN NTAPI
ChkdskCallback(IN CALLBACKCOMMAND Command,IN ULONG SubAction,IN PVOID ActionInfo)85 ChkdskCallback(
86     IN CALLBACKCOMMAND Command,
87     IN ULONG SubAction,
88     IN PVOID ActionInfo)
89 {
90     PDWORD Progress;
91     PBOOLEAN pSuccess;
92     switch(Command)
93     {
94         case PROGRESS:
95             Progress = (PDWORD)ActionInfo;
96             SendDlgItemMessageW(hChkdskDrvDialog, 14002, PBM_SETPOS, (WPARAM)*Progress, 0);
97             break;
98         case DONE:
99             pSuccess = (PBOOLEAN)ActionInfo;
100             bChkdskSuccess = (*pSuccess);
101             break;
102 
103         case VOLUMEINUSE:
104         case INSUFFICIENTRIGHTS:
105         case FSNOTSUPPORTED:
106         case CLUSTERSIZETOOSMALL:
107             bChkdskSuccess = FALSE;
108             FIXME("\n");
109             break;
110 
111         default:
112             break;
113     }
114 
115     return TRUE;
116 }
117 
118 static VOID
ChkDskNow(HWND hwndDlg,LPCWSTR pwszDrive)119 ChkDskNow(HWND hwndDlg, LPCWSTR pwszDrive)
120 {
121     //DWORD ClusterSize = 0;
122     WCHAR wszFs[30];
123     ULARGE_INTEGER TotalNumberOfFreeBytes, FreeBytesAvailableUser;
124     BOOLEAN bCorrectErrors = FALSE, bScanDrive = FALSE;
125 
126     if(!GetVolumeInformationW(pwszDrive, NULL, 0, NULL, NULL, NULL, wszFs, _countof(wszFs)))
127     {
128         FIXME("failed to get drive fs type\n");
129         return;
130     }
131 
132     if (!GetDiskFreeSpaceExW(pwszDrive, &FreeBytesAvailableUser, &TotalNumberOfFreeBytes, NULL))
133     {
134         FIXME("failed to get drive space type\n");
135         return;
136     }
137 
138     /*if (!GetDefaultClusterSize(wszFs, &ClusterSize, &TotalNumberOfFreeBytes))
139     {
140         FIXME("invalid cluster size\n");
141         return;
142     }*/
143 
144     if (SendDlgItemMessageW(hwndDlg, 14000, BM_GETCHECK, 0, 0) == BST_CHECKED)
145         bCorrectErrors = TRUE;
146 
147     if (SendDlgItemMessageW(hwndDlg, 14001, BM_GETCHECK, 0, 0) == BST_CHECKED)
148         bScanDrive = TRUE;
149 
150     hChkdskDrvDialog = hwndDlg;
151     bChkdskSuccess = FALSE;
152     SendDlgItemMessageW(hwndDlg, 14002, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
153     Chkdsk((LPWSTR)pwszDrive, (LPWSTR)wszFs, bCorrectErrors, TRUE, FALSE, bScanDrive, NULL, NULL, ChkdskCallback); // FIXME: casts
154 
155     hChkdskDrvDialog = NULL;
156     bChkdskSuccess = FALSE;
157 }
158 
159 static INT_PTR CALLBACK
ChkDskDlg(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)160 ChkDskDlg(
161     HWND hwndDlg,
162     UINT uMsg,
163     WPARAM wParam,
164     LPARAM lParam)
165 {
166     switch(uMsg)
167     {
168         case WM_INITDIALOG:
169             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
170             InitializeChkDskDialog(hwndDlg, (LPCWSTR)lParam);
171             return TRUE;
172         case WM_COMMAND:
173             switch(LOWORD(wParam))
174             {
175                 case IDCANCEL:
176                     EndDialog(hwndDlg, 0);
177                     break;
178                 case IDOK:
179                 {
180                     LPCWSTR pwszDrive = (LPCWSTR)GetWindowLongPtr(hwndDlg, DWLP_USER);
181                     ChkDskNow(hwndDlg, pwszDrive);
182                     break;
183                 }
184             }
185             break;
186     }
187 
188     return FALSE;
189 }
190 
191 VOID
PaintStaticControls(HWND hwndDlg,LPDRAWITEMSTRUCT pDrawItem)192 CDrvDefExt::PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT pDrawItem)
193 {
194     HBRUSH hBrush;
195 
196     if (pDrawItem->CtlID == 14013)
197     {
198         hBrush = CreateSolidBrush(RGB(0, 0, 255));
199         if (hBrush)
200         {
201             FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush);
202             DeleteObject((HGDIOBJ)hBrush);
203         }
204     }
205     else if (pDrawItem->CtlID == 14014)
206     {
207         hBrush = CreateSolidBrush(RGB(255, 0, 255));
208         if (hBrush)
209         {
210             FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush);
211             DeleteObject((HGDIOBJ)hBrush);
212         }
213     }
214     else if (pDrawItem->CtlID == 14015)
215     {
216         HBRUSH hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
217         HBRUSH hMagBrush = CreateSolidBrush(RGB(255, 0, 255));
218         HBRUSH hbrOld;
219         HPEN hBlackPen = (HPEN)GetStockObject(BLACK_PEN);
220         HPEN hDarkBluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 128));
221         HPEN hDarkMagPen = CreatePen(PS_SOLID, 1, RGB(128, 0, 128));
222         HPEN hOldPen = (HPEN)SelectObject(pDrawItem->hDC, hDarkMagPen);
223         INT xCenter = (pDrawItem->rcItem.left + pDrawItem->rcItem.right) / 2;
224         INT yCenter = (pDrawItem->rcItem.top + pDrawItem->rcItem.bottom - 10) / 2;
225         INT cx = pDrawItem->rcItem.right - pDrawItem->rcItem.left;
226         INT cy = pDrawItem->rcItem.bottom - pDrawItem->rcItem.top - 10;
227         INT xRadial = xCenter + (INT)(cos(M_PI + m_FreeSpacePerc / 100.0f * M_PI * 2.0f) * cx / 2);
228         INT yRadial = yCenter - (INT)(sin(M_PI + m_FreeSpacePerc / 100.0f * M_PI * 2.0f) * cy / 2);
229 
230         TRACE("FreeSpace %u a %f cx %d\n", m_FreeSpacePerc, M_PI+m_FreeSpacePerc / 100.0f * M_PI * 2.0f, cx);
231 
232         for (INT x = pDrawItem->rcItem.left; x < pDrawItem->rcItem.right; ++x)
233         {
234             double cos_val = (x - xCenter) * 2.0f / cx;
235             INT y = yCenter + (INT)(sin(acos(cos_val)) * cy / 2) - 1;
236             HPEN hCenterPen;
237 
238             if (m_FreeSpacePerc < 50 && x == xRadial)
239                 SelectObject(pDrawItem->hDC, hDarkBluePen);
240 
241             /* Temporarily change pens to draw edges */
242             if (x == pDrawItem->rcItem.left)
243                 hCenterPen = (HPEN)SelectObject(pDrawItem->hDC, hBlackPen);
244             else if (x == pDrawItem->rcItem.right - 1)
245                 SelectObject(pDrawItem->hDC, hBlackPen);
246 
247             MoveToEx(pDrawItem->hDC, x, y, NULL);
248             LineTo(pDrawItem->hDC, x, y + 10);
249             SetPixel(pDrawItem->hDC, x, y + 10, RGB(0, 0, 0));
250 
251             /* Restore fill section pens */
252             if (x == pDrawItem->rcItem.left)
253                 SelectObject(pDrawItem->hDC, hCenterPen);
254         }
255 
256         SelectObject(pDrawItem->hDC, hBlackPen);
257 
258         if (m_FreeSpacePerc > 50)
259         {
260             hbrOld = (HBRUSH)SelectObject(pDrawItem->hDC, hMagBrush);
261 
262             Ellipse(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top,
263                     pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10);
264 
265             SelectObject(pDrawItem->hDC, hBlueBrush);
266 
267             if (m_FreeSpacePerc < 100)
268             {
269                 Pie(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, pDrawItem->rcItem.right,
270                     pDrawItem->rcItem.bottom - 10, xRadial, yRadial, pDrawItem->rcItem.left, yCenter);
271             }
272         }
273         else
274         {
275             hbrOld = (HBRUSH)SelectObject(pDrawItem->hDC, hBlueBrush);
276 
277             Ellipse(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top,
278                     pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10);
279 
280             SelectObject(pDrawItem->hDC, hMagBrush);
281 
282             if (m_FreeSpacePerc > 0)
283             {
284                 Pie(pDrawItem->hDC, pDrawItem->rcItem.left, pDrawItem->rcItem.top, pDrawItem->rcItem.right,
285                     pDrawItem->rcItem.bottom - 10, pDrawItem->rcItem.left, yCenter, xRadial, yRadial);
286             }
287         }
288 
289         SelectObject(pDrawItem->hDC, hbrOld);
290         SelectObject(pDrawItem->hDC, hOldPen);
291 
292         DeleteObject(hBlueBrush);
293         DeleteObject(hMagBrush);
294         DeleteObject(hDarkBluePen);
295         DeleteObject(hDarkMagPen);
296     }
297 }
298 
299 // https://stackoverflow.com/questions/3098696/get-information-about-disk-drives-result-on-windows7-32-bit-system/3100268#3100268
300 static BOOL
GetDriveTypeAndCharacteristics(HANDLE hDevice,DEVICE_TYPE * pDeviceType,ULONG * pCharacteristics)301 GetDriveTypeAndCharacteristics(HANDLE hDevice, DEVICE_TYPE *pDeviceType, ULONG *pCharacteristics)
302 {
303     NTSTATUS Status;
304     IO_STATUS_BLOCK IoStatusBlock;
305     FILE_FS_DEVICE_INFORMATION DeviceInfo;
306 
307     Status = NtQueryVolumeInformationFile(hDevice, &IoStatusBlock,
308                                           &DeviceInfo, sizeof(DeviceInfo),
309                                           FileFsDeviceInformation);
310     if (Status == NO_ERROR)
311     {
312         *pDeviceType = DeviceInfo.DeviceType;
313         *pCharacteristics = DeviceInfo.Characteristics;
314         return TRUE;
315     }
316 
317     return FALSE;
318 }
319 
IsDriveFloppyW(LPCWSTR pszDriveRoot)320 BOOL IsDriveFloppyW(LPCWSTR pszDriveRoot)
321 {
322     LPCWSTR RootPath = pszDriveRoot;
323     WCHAR szRoot[16], szDeviceName[16];
324     UINT uType;
325     HANDLE hDevice;
326     DEVICE_TYPE DeviceType;
327     ULONG ulCharacteristics;
328     BOOL ret;
329 
330     lstrcpynW(szRoot, RootPath, _countof(szRoot));
331 
332     if (L'a' <= szRoot[0] && szRoot[0] <= 'z')
333     {
334         szRoot[0] += ('A' - 'a');
335     }
336 
337     if ('A' <= szRoot[0] && szRoot[0] <= L'Z' &&
338         szRoot[1] == L':' && szRoot[2] == 0)
339     {
340         // 'C:' --> 'C:\'
341         szRoot[2] = L'\\';
342         szRoot[3] = 0;
343     }
344 
345     if (!PathIsRootW(szRoot))
346     {
347         return FALSE;
348     }
349 
350     uType = GetDriveTypeW(szRoot);
351     if (uType == DRIVE_REMOVABLE)
352     {
353         if (szRoot[0] == L'A' || szRoot[0] == L'B')
354             return TRUE;
355     }
356     else
357     {
358         return FALSE;
359     }
360 
361     lstrcpynW(szDeviceName, L"\\\\.\\", _countof(szDeviceName));
362     szDeviceName[4] = szRoot[0];
363     szDeviceName[5] = L':';
364     szDeviceName[6] = UNICODE_NULL;
365 
366     hDevice = CreateFileW(szDeviceName, FILE_READ_ATTRIBUTES,
367                           FILE_SHARE_READ | FILE_SHARE_WRITE,
368                           NULL, OPEN_EXISTING, 0, NULL);
369     if (hDevice == INVALID_HANDLE_VALUE)
370     {
371         return FALSE;
372     }
373 
374     ret = FALSE;
375     if (GetDriveTypeAndCharacteristics(hDevice, &DeviceType, &ulCharacteristics))
376     {
377         if ((ulCharacteristics & FILE_FLOPPY_DISKETTE) == FILE_FLOPPY_DISKETTE)
378             ret = TRUE;
379     }
380 
381     CloseHandle(hDevice);
382 
383     return ret;
384 }
385 
IsDriveFloppyA(LPCSTR pszDriveRoot)386 BOOL IsDriveFloppyA(LPCSTR pszDriveRoot)
387 {
388     WCHAR szRoot[8];
389     MultiByteToWideChar(CP_ACP, 0, pszDriveRoot, -1, szRoot, _countof(szRoot));
390     return IsDriveFloppyW(szRoot);
391 }
392 
393 VOID
InitGeneralPage(HWND hwndDlg)394 CDrvDefExt::InitGeneralPage(HWND hwndDlg)
395 {
396     WCHAR wszVolumeName[MAX_PATH+1] = {0};
397     WCHAR wszFileSystem[MAX_PATH+1] = {0};
398     WCHAR wszBuf[128];
399     BOOL bRet;
400 
401     bRet = GetVolumeInformationW(m_wszDrive, wszVolumeName, _countof(wszVolumeName), NULL, NULL, NULL, wszFileSystem, _countof(wszFileSystem));
402     if (bRet)
403     {
404         /* Set volume label and filesystem */
405         SetDlgItemTextW(hwndDlg, 14000, wszVolumeName);
406         SetDlgItemTextW(hwndDlg, 14002, wszFileSystem);
407     }
408     else
409     {
410         LoadStringW(shell32_hInstance, IDS_FS_UNKNOWN, wszFileSystem, _countof(wszFileSystem));
411         SetDlgItemTextW(hwndDlg, 14002, wszFileSystem);
412     }
413 
414     /* Set drive type and icon */
415     UINT DriveType = GetDriveTypeW(m_wszDrive);
416     UINT IconId, TypeStrId = 0;
417     switch (DriveType)
418     {
419         case DRIVE_REMOVABLE:
420             if (IsDriveFloppyW(m_wszDrive))
421                 IconId = IDI_SHELL_3_14_FLOPPY;
422             else
423                 IconId = IDI_SHELL_REMOVEABLE;
424             break;
425         case DRIVE_CDROM: IconId = IDI_SHELL_CDROM; TypeStrId = IDS_DRIVE_CDROM; break;
426         case DRIVE_REMOTE: IconId = IDI_SHELL_NETDRIVE; TypeStrId = IDS_DRIVE_NETWORK; break;
427         case DRIVE_RAMDISK: IconId = IDI_SHELL_RAMDISK; break;
428         default: IconId = IDI_SHELL_DRIVE; TypeStrId = IDS_DRIVE_FIXED;
429     }
430 
431     if (DriveType == DRIVE_CDROM || DriveType == DRIVE_REMOTE)
432     {
433         /* volume label textbox */
434         SendMessage(GetDlgItem(hwndDlg, 14000), EM_SETREADONLY, TRUE, 0);
435 
436         /* disk compression */
437         ShowWindow(GetDlgItem(hwndDlg, 14011), FALSE);
438 
439         /* index */
440         ShowWindow(GetDlgItem(hwndDlg, 14012), FALSE);
441     }
442 
443     HICON hIcon = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IconId), IMAGE_ICON, 32, 32, LR_SHARED);
444     if (hIcon)
445         SendDlgItemMessageW(hwndDlg, 14016, STM_SETICON, (WPARAM)hIcon, 0);
446     if (TypeStrId && LoadStringW(shell32_hInstance, TypeStrId, wszBuf, _countof(wszBuf)))
447         SetDlgItemTextW(hwndDlg, 14001, wszBuf);
448 
449     ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes;
450     if(GetDiskFreeSpaceExW(m_wszDrive, &FreeBytesAvailable, &TotalNumberOfBytes, NULL))
451     {
452         /* Init free space percentage used for drawing piechart */
453         m_FreeSpacePerc = (UINT)(FreeBytesAvailable.QuadPart * 100ull / TotalNumberOfBytes.QuadPart);
454 
455         /* Used space */
456         if (SH_FormatByteSize(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
457             SetDlgItemTextW(hwndDlg, 14003, wszBuf);
458 
459         if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
460             SetDlgItemTextW(hwndDlg, 14004, wszBuf);
461 
462         /* Free space */
463         if (SH_FormatByteSize(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
464             SetDlgItemTextW(hwndDlg, 14005, wszBuf);
465 
466         if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
467             SetDlgItemTextW(hwndDlg, 14006, wszBuf);
468 
469         /* Total space */
470         if (SH_FormatByteSize(TotalNumberOfBytes.QuadPart, wszBuf, _countof(wszBuf)))
471             SetDlgItemTextW(hwndDlg, 14007, wszBuf);
472 
473         if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, wszBuf, _countof(wszBuf)))
474             SetDlgItemTextW(hwndDlg, 14008, wszBuf);
475     }
476     else
477     {
478         m_FreeSpacePerc = 0;
479 
480         if (SH_FormatByteSize(0, wszBuf, _countof(wszBuf)))
481         {
482             SetDlgItemTextW(hwndDlg, 14003, wszBuf);
483             SetDlgItemTextW(hwndDlg, 14005, wszBuf);
484             SetDlgItemTextW(hwndDlg, 14007, wszBuf);
485         }
486         if (StrFormatByteSizeW(0, wszBuf, _countof(wszBuf)))
487         {
488             SetDlgItemTextW(hwndDlg, 14004, wszBuf);
489             SetDlgItemTextW(hwndDlg, 14006, wszBuf);
490             SetDlgItemTextW(hwndDlg, 14008, wszBuf);
491         }
492     }
493 
494     /* Set drive description */
495     WCHAR wszFormat[50];
496     GetDlgItemTextW(hwndDlg, 14009, wszFormat, _countof(wszFormat));
497     swprintf(wszBuf, wszFormat, m_wszDrive[0]);
498     SetDlgItemTextW(hwndDlg, 14009, wszBuf);
499 
500     /* show disk cleanup button only for fixed drives */
501     ShowWindow(GetDlgItem(hwndDlg, 14010), DriveType == DRIVE_FIXED);
502 }
503 
504 INT_PTR CALLBACK
GeneralPageProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)505 CDrvDefExt::GeneralPageProc(
506     HWND hwndDlg,
507     UINT uMsg,
508     WPARAM wParam,
509     LPARAM lParam)
510 {
511     switch(uMsg)
512     {
513         case WM_INITDIALOG:
514         {
515             LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
516             if (ppsp == NULL)
517                 break;
518 
519             CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(ppsp->lParam);
520             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDrvDefExt);
521             pDrvDefExt->InitGeneralPage(hwndDlg);
522             return TRUE;
523         }
524         case WM_DRAWITEM:
525         {
526             LPDRAWITEMSTRUCT pDrawItem = (LPDRAWITEMSTRUCT)lParam;
527 
528             if (pDrawItem->CtlID >= 14013 && pDrawItem->CtlID <= 14015)
529             {
530                 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
531                 pDrvDefExt->PaintStaticControls(hwndDlg, pDrawItem);
532                 return TRUE;
533             }
534             break;
535         }
536         case WM_PAINT:
537             break;
538         case WM_COMMAND:
539             if (LOWORD(wParam) == 14010) /* Disk Cleanup */
540             {
541                 CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
542                 WCHAR wszBuf[256];
543                 DWORD cbBuf = sizeof(wszBuf);
544 
545                 if (RegGetValueW(HKEY_LOCAL_MACHINE,
546                                  L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\CleanupPath",
547                                  NULL,
548                                  RRF_RT_REG_SZ,
549                                  NULL,
550                                  (PVOID)wszBuf,
551                                  &cbBuf) == ERROR_SUCCESS)
552                 {
553                     WCHAR wszCmd[MAX_PATH];
554 
555                     StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]);
556 
557                     if (ShellExecuteW(hwndDlg, NULL, wszCmd, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
558                         ERR("Failed to create cleanup process %ls\n", wszCmd);
559                 }
560             }
561             else if (LOWORD(wParam) == 14000) /* Label */
562             {
563                 if (HIWORD(wParam) == EN_CHANGE)
564                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
565             }
566             break;
567         case WM_NOTIFY:
568             if (((LPNMHDR)lParam)->hwndFrom == GetParent(hwndDlg))
569             {
570                 /* Property Sheet */
571                 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
572 
573                 if (lppsn->hdr.code == PSN_APPLY)
574                 {
575                     CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
576                     WCHAR wszBuf[256];
577 
578                     if (GetDlgItemTextW(hwndDlg, 14000, wszBuf, _countof(wszBuf)))
579                         SetVolumeLabelW(pDrvDefExt->m_wszDrive, wszBuf);
580                     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
581                     return TRUE;
582                 }
583             }
584             break;
585 
586         default:
587             break;
588     }
589 
590     return FALSE;
591 }
592 
593 INT_PTR CALLBACK
ExtraPageProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)594 CDrvDefExt::ExtraPageProc(
595     HWND hwndDlg,
596     UINT uMsg,
597     WPARAM wParam,
598     LPARAM lParam)
599 {
600     switch (uMsg)
601     {
602         case WM_INITDIALOG:
603         {
604             LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
605             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam);
606             return TRUE;
607         }
608         case WM_COMMAND:
609         {
610             WCHAR wszBuf[MAX_PATH];
611             DWORD cbBuf = sizeof(wszBuf);
612             CDrvDefExt *pDrvDefExt = reinterpret_cast<CDrvDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
613 
614             switch(LOWORD(wParam))
615             {
616                 case 14000:
617                     DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_CHECK_DISK), hwndDlg, ChkDskDlg, (LPARAM)pDrvDefExt->m_wszDrive);
618                     break;
619                 case 14001:
620                     if (RegGetValueW(HKEY_LOCAL_MACHINE,
621                                      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath",
622                                      NULL,
623                                      RRF_RT_REG_SZ,
624                                      NULL,
625                                      (PVOID)wszBuf,
626                                      &cbBuf) == ERROR_SUCCESS)
627                     {
628                         WCHAR wszCmd[MAX_PATH];
629 
630                         StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]);
631 
632                         if (ShellExecuteW(hwndDlg, NULL, wszCmd, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
633                             ERR("Failed to create defrag process %ls\n", wszCmd);
634                     }
635                     break;
636                 case 14002:
637                     if (RegGetValueW(HKEY_LOCAL_MACHINE,
638                                      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath",
639                                      NULL,
640                                      RRF_RT_REG_SZ,
641                                      NULL,
642                                      (PVOID)wszBuf,
643                                      &cbBuf) == ERROR_SUCCESS)
644                     {
645                         if (ShellExecuteW(hwndDlg, NULL, wszBuf, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
646                             ERR("Failed to create backup process %ls\n", wszBuf);
647                     }
648             }
649             break;
650         }
651     }
652     return FALSE;
653 }
654 
655 INT_PTR CALLBACK
HardwarePageProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)656 CDrvDefExt::HardwarePageProc(
657     HWND hwndDlg,
658     UINT uMsg,
659     WPARAM wParam,
660     LPARAM lParam)
661 {
662     UNREFERENCED_PARAMETER(lParam);
663     UNREFERENCED_PARAMETER(wParam);
664 
665     switch(uMsg)
666     {
667         case WM_INITDIALOG:
668         {
669             GUID Guids[2];
670             Guids[0] = GUID_DEVCLASS_DISKDRIVE;
671             Guids[1] = GUID_DEVCLASS_CDROM;
672 
673             /* create the hardware page */
674             DeviceCreateHardwarePageEx(hwndDlg, Guids, _countof(Guids), HWPD_STANDARDLIST);
675             break;
676         }
677     }
678 
679     return FALSE;
680 }
681 
CDrvDefExt()682 CDrvDefExt::CDrvDefExt()
683 {
684     m_wszDrive[0] = L'\0';
685 }
686 
~CDrvDefExt()687 CDrvDefExt::~CDrvDefExt()
688 {
689 
690 }
691 
692 HRESULT WINAPI
Initialize(PCIDLIST_ABSOLUTE pidlFolder,IDataObject * pDataObj,HKEY hkeyProgID)693 CDrvDefExt::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDataObj, HKEY hkeyProgID)
694 {
695     FORMATETC format;
696     STGMEDIUM stgm;
697     HRESULT hr;
698 
699     TRACE("%p %p %p %p\n", this, pidlFolder, pDataObj, hkeyProgID);
700 
701     if (!pDataObj)
702         return E_FAIL;
703 
704     format.cfFormat = CF_HDROP;
705     format.ptd = NULL;
706     format.dwAspect = DVASPECT_CONTENT;
707     format.lindex = -1;
708     format.tymed = TYMED_HGLOBAL;
709 
710     hr = pDataObj->GetData(&format, &stgm);
711     if (FAILED(hr))
712         return hr;
713 
714     if (!DragQueryFileW((HDROP)stgm.hGlobal, 0, m_wszDrive, _countof(m_wszDrive)))
715     {
716         ERR("DragQueryFileW failed\n");
717         ReleaseStgMedium(&stgm);
718         return E_FAIL;
719     }
720 
721     ReleaseStgMedium(&stgm);
722     TRACE("Drive properties %ls\n", m_wszDrive);
723 
724     return S_OK;
725 }
726 
727 HRESULT WINAPI
QueryContextMenu(HMENU hmenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags)728 CDrvDefExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
729 {
730     UNIMPLEMENTED;
731     return E_NOTIMPL;
732 }
733 
734 HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpici)735 CDrvDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
736 {
737     UNIMPLEMENTED;
738     return E_NOTIMPL;
739 }
740 
741 HRESULT WINAPI
GetCommandString(UINT_PTR idCmd,UINT uType,UINT * pwReserved,LPSTR pszName,UINT cchMax)742 CDrvDefExt::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax)
743 {
744     UNIMPLEMENTED;
745     return E_NOTIMPL;
746 }
747 
748 HRESULT WINAPI
AddPages(LPFNADDPROPSHEETPAGE pfnAddPage,LPARAM lParam)749 CDrvDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
750 {
751     HPROPSHEETPAGE hPage;
752 
753     hPage = SH_CreatePropertySheetPage(IDD_DRIVE_PROPERTIES,
754                                        GeneralPageProc,
755                                        (LPARAM)this,
756                                        NULL);
757     if (hPage)
758         pfnAddPage(hPage, lParam);
759 
760     if (GetDriveTypeW(m_wszDrive) == DRIVE_FIXED)
761     {
762         hPage = SH_CreatePropertySheetPage(IDD_DRIVE_TOOLS,
763                                            ExtraPageProc,
764                                            (LPARAM)this,
765                                            NULL);
766         if (hPage)
767             pfnAddPage(hPage, lParam);
768     }
769 
770     if (GetDriveTypeW(m_wszDrive) != DRIVE_REMOTE)
771     {
772         hPage = SH_CreatePropertySheetPage(IDD_DRIVE_HARDWARE,
773                                            HardwarePageProc,
774                                            (LPARAM)this,
775                                            NULL);
776         if (hPage)
777             pfnAddPage(hPage, lParam);
778     }
779 
780     return S_OK;
781 }
782 
783 HRESULT WINAPI
ReplacePage(UINT uPageID,LPFNADDPROPSHEETPAGE pfnReplacePage,LPARAM lParam)784 CDrvDefExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam)
785 {
786     UNIMPLEMENTED;
787     return E_NOTIMPL;
788 }
789 
790 HRESULT WINAPI
SetSite(IUnknown * punk)791 CDrvDefExt::SetSite(IUnknown *punk)
792 {
793     UNIMPLEMENTED;
794     return E_NOTIMPL;
795 }
796 
797 HRESULT WINAPI
GetSite(REFIID iid,void ** ppvSite)798 CDrvDefExt::GetSite(REFIID iid, void **ppvSite)
799 {
800     UNIMPLEMENTED;
801     return E_NOTIMPL;
802 }
803