- implement changing drive volume name
[reactos.git] / reactos / dll / win32 / shell32 / drive.c
1 /*
2 * Shell Library Functions
3 *
4 * Copyright 2005 Johannes Anderwald
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #define LARGEINT_PROTOS
24 #define LargeIntegerDivide RtlLargeIntegerDivide
25 #define ExtendedIntegerMultiply RtlExtendedIntegerMultiply
26 #define ConvertUlongToLargeInteger RtlConvertUlongToLargeInteger
27 #define LargeIntegerSubtract RtlLargeIntegerSubtract
28 #define MAX_PROPERTY_SHEET_PAGE 32
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include "winerror.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winreg.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38 #include "commdlg.h"
39 #include "wine/debug.h"
40
41 #include "shellapi.h"
42 #include <shlwapi.h>
43 #include "shlobj.h"
44 #include "shell32_main.h"
45 #include "shresdef.h"
46 #include "undocshell.h"
47 #include <prsht.h>
48 #include <initguid.h>
49 #include <devguid.h>
50 #include <winioctl.h>
51 #include <largeint.h>
52
53 WINE_DEFAULT_DEBUG_CHANNEL(shell);
54
55 typedef enum
56 {
57 HWPD_STANDARDLIST = 0,
58 HWPD_LARGELIST,
59 HWPD_MAX = HWPD_LARGELIST
60 } HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
61
62 HWND WINAPI
63 DeviceCreateHardwarePageEx(HWND hWndParent,
64 LPGUID lpGuids,
65 UINT uNumberOfGuids,
66 HWPAGE_DISPLAYMODE DisplayMode);
67
68 #define DRIVE_PROPERTY_PAGES (3)
69
70
71 static
72 LARGE_INTEGER
73 GetFreeBytesShare(LARGE_INTEGER TotalNumberOfFreeBytes, LARGE_INTEGER TotalNumberOfBytes)
74 {
75 LARGE_INTEGER Temp, Result, Remainder;
76
77 Temp = LargeIntegerDivide(TotalNumberOfBytes, ConvertUlongToLargeInteger(100), &Remainder);
78 if (Temp.QuadPart >= TotalNumberOfFreeBytes.QuadPart)
79 {
80 Result = ConvertUlongToLargeInteger(1);
81 }else
82 {
83 Result = LargeIntegerDivide(TotalNumberOfFreeBytes, Temp, &Remainder);
84 }
85
86 return Result;
87 }
88
89 static
90 void
91 PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT drawItem)
92 {
93 HBRUSH hBrush;
94
95 if (drawItem->CtlID == 14013)
96 {
97 hBrush = CreateSolidBrush(RGB(0, 0, 255));
98 if (hBrush)
99 {
100 FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
101 DeleteObject((HGDIOBJ)hBrush);
102 }
103 }else if (drawItem->CtlID == 14014)
104 {
105 hBrush = CreateSolidBrush(RGB(255, 0, 255));
106 if (hBrush)
107 {
108 FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
109 DeleteObject((HGDIOBJ)hBrush);
110 }
111 }
112 else if (drawItem->CtlID == 14015)
113 {
114 HBRUSH hBlueBrush;
115 HBRUSH hMagBrush;
116 RECT rect;
117 LONG horzsize;
118 LARGE_INTEGER Result;
119 WCHAR szBuffer[20];
120
121 hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
122 hMagBrush = CreateSolidBrush(RGB(255, 0, 255));
123
124 SendDlgItemMessageW(hwndDlg, 14007, WM_GETTEXT, 20, (LPARAM)szBuffer);
125 Result.QuadPart = _wtoi(szBuffer);
126
127 CopyRect(&rect, &drawItem->rcItem);
128 horzsize = rect.right - rect.left;
129 Result.QuadPart = (Result.QuadPart * horzsize) / 100;
130
131 rect.right = rect.left + Result.QuadPart;
132 FillRect(drawItem->hDC, &rect, hMagBrush);
133 rect.left = rect.right;
134 rect.right = drawItem->rcItem.right;
135 FillRect(drawItem->hDC, &rect, hBlueBrush);
136 DeleteObject(hBlueBrush);
137 DeleteObject(hMagBrush);
138 }
139 }
140
141 static
142 void
143 InitializeGeneralDriveDialog(HWND hwndDlg, WCHAR * szDrive)
144 {
145 WCHAR szVolumeName[MAX_PATH+1] = {0};
146 DWORD MaxComponentLength = 0;
147 DWORD FileSystemFlags = 0;
148 WCHAR FileSystemName[MAX_PATH+1] = {0};
149 WCHAR szFormat[50];
150 WCHAR szBuffer[128];
151 BOOL ret;
152 UINT DriveType;
153 ULARGE_INTEGER FreeBytesAvailable;
154 LARGE_INTEGER TotalNumberOfFreeBytes;
155 LARGE_INTEGER TotalNumberOfBytes;
156
157 ret = GetVolumeInformationW(szDrive, szVolumeName, MAX_PATH+1, NULL, &MaxComponentLength, &FileSystemFlags, FileSystemName, MAX_PATH+1);
158 if (ret)
159 {
160 /* set volume label */
161 SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szVolumeName);
162
163 /* set filesystem type */
164 SendDlgItemMessageW(hwndDlg, 14003, WM_SETTEXT, (WPARAM)NULL, (LPARAM)FileSystemName);
165
166 }
167
168 DriveType = GetDriveTypeW(szDrive);
169 if (DriveType == DRIVE_FIXED)
170 {
171
172 if(GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable, (PULARGE_INTEGER)&TotalNumberOfBytes, (PULARGE_INTEGER)&TotalNumberOfFreeBytes))
173 {
174 WCHAR szResult[128];
175 LARGE_INTEGER Result;
176 #ifdef IOCTL_DISK_GET_LENGTH_INFO_IMPLEMENTED
177 HANDLE hVolume;
178 DWORD BytesReturned = 0;
179
180 sprintfW(szResult, L"\\\\.\\%c:", towupper(szDrive[0]));
181 hVolume = CreateFileW(szResult, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
182 if (hVolume != INVALID_HANDLE_VALUE)
183 {
184 ret = DeviceIoControl(hVolume, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (LPVOID)&TotalNumberOfBytes, sizeof(ULARGE_INTEGER), &BytesReturned, NULL);
185 if (ret && StrFormatByteSizeW(LengthInformation.Length.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
186 SendDlgItemMessageW(hwndDlg, 14008, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
187
188 CloseHandle(hVolume);
189 }
190 TRACE("szResult %s hVOlume %p ret %d LengthInformation %ul Bytesreturned %d\n", debugstr_w(szResult), hVolume, ret, LengthInformation.Length.QuadPart, BytesReturned);
191 #else
192 if (ret && StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
193 SendDlgItemMessageW(hwndDlg, 14008, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
194 #endif
195
196 if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
197 SendDlgItemMessageW(hwndDlg, 14004, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
198
199 if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
200 SendDlgItemMessageW(hwndDlg, 14006, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
201
202 Result = GetFreeBytesShare(TotalNumberOfFreeBytes, TotalNumberOfBytes);
203 /* set free bytes percentage */
204 sprintfW(szResult, L"%02d%%", Result.QuadPart);
205 SendDlgItemMessageW(hwndDlg, 14007, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
206 /* store used share amount */
207 Result = LargeIntegerSubtract(ConvertUlongToLargeInteger(100), Result);
208 sprintfW(szResult, L"%02d%%", Result.QuadPart);
209 SendDlgItemMessageW(hwndDlg, 14005, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
210 if (LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
211 SendDlgItemMessageW(hwndDlg, 14002, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer);
212
213 }
214 }
215 /* set drive description */
216 SendDlgItemMessageW(hwndDlg, 14010, WM_GETTEXT, (WPARAM)50, (LPARAM)szFormat);
217 sprintfW(szBuffer, szFormat, szDrive);
218 SendDlgItemMessageW(hwndDlg, 14010, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szBuffer);
219 }
220
221
222 INT_PTR
223 CALLBACK
224 DriveGeneralDlg(
225 HWND hwndDlg,
226 UINT uMsg,
227 WPARAM wParam,
228 LPARAM lParam
229 )
230 {
231 LPPROPSHEETPAGEW ppsp;
232 LPDRAWITEMSTRUCT drawItem;
233 STARTUPINFOW si;
234 PROCESS_INFORMATION pi;
235 WCHAR * lpstr;
236 WCHAR szPath[MAX_PATH];
237 UINT length;
238 LPPSHNOTIFY lppsn;
239
240 switch(uMsg)
241 {
242 case WM_INITDIALOG:
243 ppsp = (LPPROPSHEETPAGEW)lParam;
244 if (ppsp == NULL)
245 break;
246 lpstr = (WCHAR *)ppsp->lParam;
247 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lpstr);
248 InitializeGeneralDriveDialog(hwndDlg, lpstr);
249 return TRUE;
250 case WM_DRAWITEM:
251 drawItem = (LPDRAWITEMSTRUCT)lParam;
252 if (drawItem->CtlID >= 14013 && drawItem->CtlID <= 14015)
253 {
254 PaintStaticControls(hwndDlg, drawItem);
255 return TRUE;
256 }
257 break;
258 case WM_COMMAND:
259 if (LOWORD(wParam) == 14011)
260 {
261 lpstr = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
262 ZeroMemory( &si, sizeof(si) );
263 si.cb = sizeof(si);
264 ZeroMemory( &pi, sizeof(pi) );
265 if (!GetSystemDirectoryW(szPath, MAX_PATH))
266 break;
267 wcscat(szPath, L"\\cleanmgr.exe /D ");
268 length = wcslen(szPath);
269 szPath[length] = lpstr[0];
270 szPath[length+1] = L'\0';
271 if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
272 {
273 CloseHandle(pi.hProcess);
274 CloseHandle(pi.hThread);
275 }
276 break;
277 }
278 case WM_NOTIFY:
279 lppsn = (LPPSHNOTIFY) lParam;
280 if (LOWORD(wParam) == 14001)
281 {
282 if (HIWORD(wParam) == EN_CHANGE)
283 {
284 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
285 }
286 break;
287 }
288 if (lppsn->hdr.code == PSN_APPLY)
289 {
290 lpstr = (LPWSTR)GetWindowLong(hwndDlg, DWLP_USER);
291 if (lpstr && SendDlgItemMessageW(hwndDlg, 14001, WM_GETTEXT, sizeof(szPath)/sizeof(WCHAR), (LPARAM)szPath))
292 {
293 szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0';
294 SetVolumeLabelW(lpstr, szPath);
295 }
296 SetWindowLong( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
297 return TRUE;
298 }
299 break;
300
301 default:
302 break;
303 }
304
305
306 return FALSE;
307 }
308
309 INT_PTR
310 CALLBACK
311 DriveExtraDlg(
312 HWND hwndDlg,
313 UINT uMsg,
314 WPARAM wParam,
315 LPARAM lParam
316 )
317 {
318 STARTUPINFOW si;
319 PROCESS_INFORMATION pi;
320 WCHAR szPath[MAX_PATH];
321 WCHAR szArg[MAX_PATH];
322 WCHAR * szDrive;
323 UINT length;
324 LPPROPSHEETPAGEW ppsp;
325
326 switch (uMsg)
327 {
328 case WM_INITDIALOG:
329 ppsp = (LPPROPSHEETPAGEW)lParam;
330 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam);
331 return TRUE;
332 case WM_COMMAND:
333 ZeroMemory( &si, sizeof(si) );
334 si.cb = sizeof(si);
335 ZeroMemory( &pi, sizeof(pi) );
336 if (!GetSystemDirectoryW(szPath, MAX_PATH))
337 break;
338 szDrive = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
339 switch(LOWORD(wParam))
340 {
341 case 14000:
342 ///
343 /// FIXME
344 /// show checkdsk dialog
345 ///
346 break;
347 case 14001:
348 szArg[0] = L'"';
349 wcscpy(&szArg[1], szPath);
350 wcscat(szPath, L"\\mmc.exe");
351 wcscat(szArg, L"\\dfrg.msc\" ");
352 length = wcslen(szArg);
353 szArg[length] = szDrive[0];
354 szArg[length+1] = L':';
355 szArg[length+2] = L'\0';
356 if (CreateProcessW(szPath, szArg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
357 {
358 CloseHandle(pi.hProcess);
359 CloseHandle(pi.hThread);
360 }
361 break;
362 case 14002:
363 wcscat(szPath, L"\\ntbackup.exe");
364 if (CreateProcessW(szPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
365 {
366 CloseHandle(pi.hProcess);
367 CloseHandle(pi.hThread);
368 }
369 }
370 break;
371 }
372 return FALSE;
373 }
374
375 INT_PTR
376 CALLBACK
377 DriveHardwareDlg(
378 HWND hwndDlg,
379 UINT uMsg,
380 WPARAM wParam,
381 LPARAM lParam
382 )
383 {
384 GUID Guids[1];
385 Guids[0] = GUID_DEVCLASS_DISKDRIVE;
386
387 UNREFERENCED_PARAMETER(lParam);
388 UNREFERENCED_PARAMETER(wParam);
389
390 switch(uMsg)
391 {
392 case WM_INITDIALOG:
393 /* create the hardware page */
394 DeviceCreateHardwarePageEx(hwndDlg,
395 Guids,
396 sizeof(Guids) / sizeof(Guids[0]),
397 0);
398 break;
399 }
400
401 return FALSE;
402 }
403
404 static
405 const
406 struct
407 {
408 LPSTR resname;
409 DLGPROC dlgproc;
410 } PropPages[] =
411 {
412 { "DRIVE_GENERAL_DLG", DriveGeneralDlg },
413 { "DRIVE_EXTRA_DLG", DriveExtraDlg },
414 { "DRIVE_HARDWARE_DLG", DriveHardwareDlg },
415 };
416
417 BOOL
418 CALLBACK
419 AddPropSheetPageProc(HPROPSHEETPAGE hpage, LPARAM lParam)
420 {
421 PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam;
422 if (ppsh != NULL && ppsh->nPages < MAX_PROPERTY_SHEET_PAGE)
423 {
424 ppsh->phpage[ppsh->nPages++] = hpage;
425 return TRUE;
426 }
427 return FALSE;
428 }
429
430 BOOL
431 SH_ShowDriveProperties(WCHAR * drive)
432 {
433 HPSXA hpsx;
434 HPROPSHEETPAGE hpsp[MAX_PROPERTY_SHEET_PAGE];
435 PROPSHEETHEADERW psh;
436 BOOL ret;
437 UINT i;
438 WCHAR szName[MAX_PATH];
439 DWORD dwMaxComponent, dwFileSysFlags;
440
441 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
442 psh.dwSize = sizeof(PROPSHEETHEADERW);
443 //psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE;
444 psh.hwndParent = NULL;
445 psh.nStartPage = 0;
446 psh.phpage = hpsp;
447
448
449 if (GetVolumeInformationW(drive, szName, sizeof(szName)/sizeof(WCHAR), NULL, &dwMaxComponent,
450 &dwFileSysFlags, NULL, 0))
451 {
452 psh.pszCaption = szName;
453 psh.dwFlags |= PSH_PROPTITLE;
454 if (!wcslen(szName))
455 {
456 /* FIXME
457 * check if disk is a really a local hdd
458 */
459 i = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szName, sizeof(szName)/sizeof(WCHAR));
460 if (i > 0 && i < (sizeof(szName)/sizeof(WCHAR)) + 6)
461 {
462 szName[i] = L' ';
463 szName[i+1] = L'(';
464 wcscpy(&szName[i+2], drive);
465 szName[i+4] = L')';
466 szName[i+5] = L'\0';
467 }
468 }
469 }
470
471
472 for (i = 0; i < DRIVE_PROPERTY_PAGES; i++)
473 {
474 HPROPSHEETPAGE hprop = SH_CreatePropertySheetPage(PropPages[i].resname, PropPages[i].dlgproc, (LPARAM)drive, NULL);
475 if (hprop)
476 {
477 hpsp[psh.nPages] = hprop;
478 psh.nPages++;
479 }
480 }
481
482 hpsx = SHCreatePropSheetExtArray(HKEY_CLASSES_ROOT,
483 L"Drive",
484 MAX_PROPERTY_SHEET_PAGE-DRIVE_PROPERTY_PAGES);
485
486 SHAddFromPropSheetExtArray(hpsx,
487 (LPFNADDPROPSHEETPAGE)AddPropSheetPageProc,
488 (LPARAM)&psh);
489
490 ret = PropertySheetW(&psh);
491 if (ret < 0)
492 return FALSE;
493 else
494 return TRUE;
495 }