1 #include "Unfrag.h"
2 #include "MainDialog.h"
3 #include "resource.h"
4 #include "Fraginator.h"
5 #include "Defragment.h"
6 #include "ReportDialog.h"
7 
8 
9 vector<wstring> DrivesList;
10 LRESULT AnalyzeID;
11 LRESULT FastID;
12 LRESULT ExtensiveID;
13 bool QuitWhenDone;
14 bool Stopping;
15 
16 
17 LRESULT PriHighID;
18 LRESULT PriAboveNormID;
19 LRESULT PriNormalID;
20 LRESULT PriBelowNormID;
21 LRESULT PriIdleID;
22 
23 
24 static void             InitDialog       (HWND Dlg);
25 void             UpdateDefragInfo (HWND Dlg);
26 void             UpdatePriority   (HWND Dlg);
27 wstring           GetDefaultTitle  (void);
28 wstring           GetDefragTitle   (void);
29 void             SetDisables      (HWND Dlg);
30 INT_PTR CALLBACK MainDialogProc   (HWND Dlg, UINT Msg, WPARAM WParam, LPARAM LParam);
31 
32 
33 static void InitDialog (HWND Dlg)
34 {
35     // Make internal list
36     DWORD DriveMask;
37     HWND  DlgItem;
38     size_t d;
39 
40     // Clear out wisecracks line for now
41     SetDlgItemText (Dlg, IDC_WISECRACKS, L"\"Defrag, baby!\"");
42 
43     // Make list of logical drives
44     DrivesList.resize (0);
45     DriveMask = GetLogicalDrives ();
46 
47     for (d = 0; d < 26; d++)
48     {
49         if (DriveMask & (1 << d))
50         {
51             wstring Name;
52 
53             Name = (wchar_t)(L'A' + d);
54             Name += L':';
55             DrivesList.push_back (Name);
56         }
57     }
58 
59     // Give list to dropdown list
60     DlgItem = GetDlgItem (Dlg, IDC_DRIVES_LIST);
61     SendMessage (DlgItem, CB_RESETCONTENT, 0, 0);
62     for (d = 0; d < DrivesList.size(); d++)
63     {
64         SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) DrivesList[d].c_str());
65     }
66 
67     // Put in defrag methods
68     DlgItem = GetDlgItem (Dlg, IDC_METHODS_LIST);
69     SendMessage (DlgItem, CB_RESETCONTENT, 0, 0);
70     AnalyzeID   = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"Analyze Only");
71     FastID      = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"Fast Defrag");
72     ExtensiveID = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"Extensive Defrag");
73 
74     // Set up process priorities
75     DlgItem = GetDlgItem (Dlg, IDC_PRIORITY_LIST);
76     SendMessage (Dlg, CB_RESETCONTENT, 0, 0);
77     PriHighID      = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"High");
78     PriAboveNormID = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"Above Normal");
79     PriNormalID    = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"Normal");
80     PriBelowNormID = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"Below Normal");
81     PriIdleID      = SendMessage (DlgItem, CB_ADDSTRING, 0, (LPARAM) L"Idle");
82     UpdatePriority (Dlg);
83 
84     // Reset texts and progress meters
85     SendDlgItemMessage (Dlg, IDC_STATUS,   WM_SETTEXT,   0, (LPARAM) L"");
86     SendDlgItemMessage (Dlg, IDC_PERCENT,  WM_SETTEXT,   0, (LPARAM) L"");
87     SendDlgItemMessage (Dlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM (0, 10000));
88     SendDlgItemMessage (Dlg, IDC_PROGRESS, PBM_SETPOS,   0, 0);
89 
90     return;
91 }
92 
93 
94 void UpdateDefragInfo (HWND Dlg)
95 {
96     wchar_t PercentText[100];
97     static double OldPercent = 200.0f;
98     static wstring OldStatus = L"Non";
99     wstring NewStatus;
100     double NewPercent;
101 
102     if (Defrag == NULL)
103         return;
104 
105     NewPercent = Defrag->GetStatusPercent ();
106     if (NewPercent > 100.0f)
107         NewPercent = 100.0f;
108     if (NewPercent < 0.0f)
109         NewPercent = 0.0f;
110     if (NewPercent != OldPercent)
111     {
112         swprintf (PercentText, L"%6.2f%%", NewPercent);
113         SendDlgItemMessage (Dlg, IDC_PERCENT, WM_SETTEXT, 0, (LPARAM) PercentText);
114         SendDlgItemMessage (Dlg, IDC_PROGRESS, PBM_SETPOS,
115             (WPARAM) (int)(NewPercent * 100.0f), 0);
116         OldPercent = NewPercent;
117     }
118 
119     NewStatus = Defrag->GetStatusString ();
120     if (NewStatus != OldStatus)
121     {   // Change & characters to && to avoid underlining
122         wstring Status;
123         wstring::iterator it;
124 
125         Status = NewStatus;
126         it = Status.begin ();
127         while (it < Status.end())
128         {
129             if (*it == L'&')
130             {
131                 Status.insert (it, 1, L'&');
132                 it++;
133             }
134 
135             it++;
136         }
137 
138         SendDlgItemMessage (Dlg, IDC_STATUS, WM_SETTEXT, 0,
139             (LPARAM) Status.c_str());
140 
141         OldStatus = NewStatus;
142     }
143 
144     return;
145 }
146 
147 
148 wstring GetDefaultTitle (void)
149 {
150     wstring DefaultText;
151 
152     DefaultText = wstring(wstring(APPNAME_GUI) + wstring(L" v") + wstring(APPVER_STR) +
153                   wstring(L" (C) 2000 by Rick Brewster"));
154 
155     return (DefaultText);
156 }
157 
158 
159 wstring GetDefragTitle (void)
160 {
161     wstring DefragText;
162     wchar_t Percent[10];
163 
164     swprintf (Percent, L"%.2f%%", Defrag->GetStatusPercent());
165 
166     DefragText = GetDefaultTitle ();
167     if (Defrag != NULL)
168     {
169         DefragText = wstring(Percent) + wstring (L" - ") + Defrag->GetVolume().GetRootPath() +
170             wstring (L" - ") + DefragText;
171     }
172 
173     return (DefragText);
174 }
175 
176 
177 void SetDisables (HWND Dlg)
178 {
179     // If a defrag is in process, set L'Start' button to say L'Stop' and disable
180     // the Select Drive and Select Action controls
181     if (Defrag != NULL  &&  !Defrag->IsDoneYet()  &&  !Defrag->HasError())
182     {
183         SendMessage (GetDlgItem (Dlg, IDC_STARTSTOP), WM_SETTEXT, 0, (LPARAM) L"Stop");
184         EnableWindow (GetDlgItem (Dlg, IDC_DRIVES_LIST), FALSE);
185         EnableWindow (GetDlgItem (Dlg, IDC_METHODS_LIST), FALSE);
186     }
187     else
188     {
189         SendMessage (GetDlgItem (Dlg, IDC_STARTSTOP), WM_SETTEXT, 0, (LPARAM) L"Start");
190         EnableWindow (GetDlgItem (Dlg, IDC_STARTSTOP), TRUE);
191         EnableWindow (GetDlgItem (Dlg, IDC_QUIT), TRUE);
192         EnableWindow (GetDlgItem (Dlg, IDC_DRIVES_LIST), TRUE);
193         EnableWindow (GetDlgItem (Dlg, IDC_METHODS_LIST), TRUE);
194     }
195 
196     return;
197 }
198 
199 
200 void UpdatePriority (HWND Dlg)
201 {
202     LRESULT Id;
203     DWORD Priority;
204 
205     Id = SendDlgItemMessage (Dlg, IDC_PRIORITY_LIST, CB_GETCURSEL, 0, 0);
206 
207     if (Id == PriHighID)
208         Priority = HIGH_PRIORITY_CLASS;
209     else
210     if (Id == PriAboveNormID)
211         Priority = ABOVE_NORMAL_PRIORITY_CLASS;
212     else
213     if (Id == PriNormalID)
214         Priority = NORMAL_PRIORITY_CLASS;
215     else
216     if (Id == PriBelowNormID)
217         Priority = BELOW_NORMAL_PRIORITY_CLASS;
218     else
219     if (Id == PriIdleID)
220         Priority = IDLE_PRIORITY_CLASS;
221     else
222         return;
223 
224     SetPriorityClass (GetCurrentProcess(), Priority);
225     return;
226 }
227 
228 
229 // Save settings (ie, process priority and defrag type options)
230 bool GetRegKeys (HKEY *RegKeyResult)
231 {
232     HKEY RegKey;
233     LONG Error;
234 
235     Error = RegCreateKeyEx
236     (
237         HKEY_CURRENT_USER,
238         L"Software\\Fraginator",
239         0,
240         NULL,
241         REG_OPTION_NON_VOLATILE,
242         KEY_ALL_ACCESS,
243         NULL,
244         &RegKey,
245         NULL
246     );
247 
248     if (Error != ERROR_SUCCESS)
249         return (false);
250 
251     *RegKeyResult = RegKey;
252     return (true);
253 }
254 
255 
256 bool DoneRegKey (HKEY RegKey)
257 {
258     RegCloseKey (RegKey);
259     return (true);
260 }
261 
262 
263 void SaveSettings (HWND Dlg)
264 {
265     LRESULT DefragID;
266     DWORD   DefragVal;
267     LRESULT PriID;
268     DWORD   PriVal;
269     HKEY    RegKey;
270 
271     DefragID = SendDlgItemMessage (Dlg, IDC_METHODS_LIST, CB_GETCURSEL, 0, 0);
272     PriID    = SendDlgItemMessage (Dlg, IDC_PRIORITY_LIST, CB_GETCURSEL, 0, 0);
273 
274     // Action
275     if (DefragID == AnalyzeID)
276         DefragVal = (DWORD) DefragAnalyze;
277     else
278     if (DefragID == FastID)
279         DefragVal = (DWORD) DefragFast;
280     else
281     if (DefragID == ExtensiveID)
282         DefragVal = (DWORD) DefragExtensive;
283 
284     // Process Priority
285     if (PriID == PriHighID)
286         PriVal = HIGH_PRIORITY_CLASS;
287     else
288     if (PriID == PriAboveNormID)
289         PriVal = ABOVE_NORMAL_PRIORITY_CLASS;
290     else
291     if (PriID == PriNormalID)
292         PriVal = NORMAL_PRIORITY_CLASS;
293     else
294     if (PriID == PriBelowNormID)
295         PriVal = BELOW_NORMAL_PRIORITY_CLASS;
296     else
297     if (PriID == PriIdleID)
298         PriVal = IDLE_PRIORITY_CLASS;
299 
300     if (!GetRegKeys (&RegKey))
301         return;
302 
303     RegSetValueEx
304     (
305         RegKey,
306         L"Default Action",
307         0,
308         REG_DWORD,
309         (CONST BYTE *)&DefragVal,
310         sizeof (DefragVal)
311     );
312 
313     RegSetValueEx
314     (
315         RegKey,
316         L"Process Priority",
317         0,
318         REG_DWORD,
319         (CONST BYTE *)&PriVal,
320         sizeof (PriVal)
321     );
322 
323     DoneRegKey (RegKey);
324     return;
325 }
326 
327 
328 void LoadSettings (HWND Dlg)
329 {
330     DefragType DType;
331     DWORD      DTypeVal;
332     LRESULT    DefragID;
333     DWORD      PriVal;
334     LRESULT    PriID;
335     HKEY       RegKey;
336     DWORD      RegType;
337     DWORD      RegSize;
338     LONG       Error;
339 
340     if (!GetRegKeys (&RegKey))
341         return;
342 
343     RegSize = sizeof (DTypeVal);
344     RegType = REG_DWORD;
345 
346     Error = RegQueryValueEx
347     (
348         RegKey,
349         L"Default Action",
350         0,
351         &RegType,
352         (BYTE *)&DTypeVal,
353         &RegSize
354     );
355 
356     if (Error != ERROR_SUCCESS)
357         DTypeVal = DefragAnalyze;
358 
359     Error = RegQueryValueEx
360     (
361         RegKey,
362         L"Process Priority",
363         0,
364         &RegType,
365         (BYTE *)&PriVal,
366         &RegSize
367     );
368 
369     DoneRegKey (RegKey);
370 
371     if (Error != ERROR_SUCCESS)
372         PriVal = NORMAL_PRIORITY_CLASS;
373 
374     DType = (DefragType) DTypeVal;
375     switch (DType)
376     {
377         default:
378         case DefragAnalyze:
379             DefragID = AnalyzeID;
380             break;
381 
382         case DefragFast:
383             DefragID = FastID;
384             break;
385 
386         case DefragExtensive:
387             DefragID = ExtensiveID;
388             break;
389     }
390 
391     switch (PriVal)
392     {
393         case HIGH_PRIORITY_CLASS:
394             PriID = PriHighID;
395             break;
396 
397         case ABOVE_NORMAL_PRIORITY_CLASS:
398             PriID = PriAboveNormID;
399             break;
400 
401         default:
402         case NORMAL_PRIORITY_CLASS:
403             PriID = PriNormalID;
404             break;
405 
406         case BELOW_NORMAL_PRIORITY_CLASS:
407             PriID = PriBelowNormID;
408             break;
409 
410         case IDLE_PRIORITY_CLASS:
411             PriID = PriIdleID;
412             break;
413     }
414 
415     SendDlgItemMessage (Dlg, IDC_PRIORITY_LIST, CB_SETCURSEL, PriID,    0);
416     SendDlgItemMessage (Dlg, IDC_METHODS_LIST,  CB_SETCURSEL, DefragID, 0);
417     return;
418 }
419 
420 
421 #define IDLETIME 25
422 wstring OldWindowText = L"";
423 
424 INT_PTR CALLBACK MainDialogProc (HWND Dlg, UINT Msg, WPARAM WParam, LPARAM LParam)
425 {
426     static bool ReEntrance = false;
427 
428     switch (Msg)
429     {
430         case WM_INITDIALOG:
431             Stopping = false;
432             SetWindowText (Dlg, GetDefaultTitle().c_str());
433             SetDisables (Dlg);
434             InitDialog (Dlg);
435             SetTimer (Dlg, 1, IDLETIME, NULL);
436             SetClassLong (Dlg, GCL_HICON, (LONG) LoadIcon (GlobalHInstance, MAKEINTRESOURCE(IDI_ICON)));
437             QuitWhenDone = false;
438             LoadSettings (Dlg);
439             UpdatePriority (Dlg);
440             return (1);
441 
442 
443         case WM_TIMER:
444             if (Defrag != NULL  &&  !ReEntrance)
445             {
446                 wstring NewTitle;
447 
448                 SendMessage (Dlg, WM_UPDATEINFO, 0, 0);
449 
450                 NewTitle = GetDefragTitle ();
451                 if (NewTitle != OldWindowText)
452                 {
453                     OldWindowText = NewTitle;
454                     SetWindowText (Dlg, NewTitle.c_str());
455                 }
456 
457                 if (Defrag->IsDoneYet()  ||  Defrag->HasError())
458                 {   // This is the code executed when defragging is finished (or stopped :)
459                     if (Defrag->GetDefragType() == DefragAnalyze  &&
460                         !Defrag->HasError()  &&
461                         !Stopping)
462                     {   // Show report
463                         ReEntrance = true;
464 
465                         DialogBoxParam (GlobalHInstance, MAKEINTRESOURCE (IDD_REPORT),
466                             Dlg, ReportDialogProc, (LPARAM) Defrag);
467 
468                         ReEntrance = false;
469                     }
470 
471                     delete Defrag;
472                     Defrag = NULL;
473                     SetDisables (Dlg);
474                     SetWindowText (Dlg, GetDefaultTitle().c_str());
475 
476                     Stopping = false;
477 
478                     if (QuitWhenDone)
479                         SendMessage (GetDlgItem (Dlg, IDC_QUIT), BM_CLICK, 0, 0);
480                 }
481             }
482 
483             SetTimer (Dlg, 1, IDLETIME, NULL);
484             return (0);
485 
486 
487         case WM_UPDATEINFO:
488             UpdateDefragInfo (Dlg);
489             return (1);
490 
491 
492         case WM_CLOSE:
493             SendMessage (GetDlgItem (Dlg, IDC_QUIT), BM_CLICK, 0, 0);
494             return (1);
495 
496 
497         case WM_COMMAND:
498             switch (LOWORD(WParam))
499             {
500                 case IDC_PRIORITY_LIST:
501                     UpdatePriority (Dlg);
502                     return (1);
503 
504 
505                 case ID_MAIN_HELP:
506                     ShellExecute (Dlg, L"open", L"Fraginator.chm", L"", L".", SW_SHOW);
507                     return (1);
508 
509 
510                 case IDC_QUIT:
511                     if (Defrag == NULL)
512                     {   // This is the code executing when quitting
513                         SaveSettings (Dlg);
514                         EndDialog (Dlg, 0);
515                     }
516                     else
517                     {   // Tell defragging to finish and disable our button
518                         QuitWhenDone = true;
519                         SendMessage (GetDlgItem (Dlg, IDC_STARTSTOP), BM_CLICK, 0, 0);
520                         EnableWindow (GetDlgItem (Dlg, IDC_QUIT), FALSE);
521                     }
522                     return (1);
523 
524 
525                 case IDC_STARTSTOP:
526                     if (Defrag == NULL)
527                     {   // L"Start"
528                         wchar_t Drive[10];
529                         LRESULT ID;
530                         DefragType Method;
531                         HANDLE H;
532 
533                         if (Defrag != NULL)
534                             return (1);
535 
536                         SendMessage (GetDlgItem (Dlg, IDC_DRIVES_LIST), WM_GETTEXT,
537                             sizeof (Drive) - 1, (LPARAM) Drive);
538 
539                         if (wcslen(Drive) != 2  ||  Drive[1] != L':')
540                             return (1);
541 
542                         ID = SendMessage (GetDlgItem (Dlg, IDC_METHODS_LIST), CB_GETCURSEL, 0, 0);
543                         Method = DefragInvalid;
544                         if (ID == AnalyzeID)
545                             Method = DefragAnalyze;
546                         else
547                         if (ID == FastID)
548                             Method = DefragFast;
549                         else
550                         if (ID == ExtensiveID)
551                             Method = DefragExtensive;
552 
553                         if (Method != DefragInvalid)
554                         {
555                             Defrag = StartDefragThread (Drive, Method, H);
556                             Defrag->SetDoLimitLength (false);
557                             SetWindowText (Dlg, GetDefragTitle().c_str());
558                             SetDisables (Dlg);
559                         }
560                     }
561                     else
562                     {   // L"Stop"
563                         Stopping = true;
564                         Defrag->Stop ();
565                         EnableWindow (GetDlgItem (Dlg, IDC_STARTSTOP), FALSE);
566                         EnableWindow (GetDlgItem (Dlg, IDC_QUIT), FALSE);
567                     }
568                     return (1);
569             }
570     }
571 
572     // Otherwise, return 0 to say we did not process the message.
573     return (0);
574 }
575