windows-64-bit-type-safety-20051105
[openafs.git] / src / WINNT / afsapplib / al_progress.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include <WINNT/al_progress.h>
16 #include <commctrl.h>
17
18
19 /*
20  * DEFINITIONS ________________________________________________________________
21  *
22  */
23
24 #define WM_UPDATE_PROGRESS WM_TIMER
25
26
27 /*
28  * PROTOTYPES _________________________________________________________________
29  *
30  */
31
32
33 /*
34  * ROUTINES ___________________________________________________________________
35  *
36  */
37
38 PROGRESSDISPLAY::PROGRESSDISPLAY (HWND hWnd)
39 {
40    Init (hWnd);
41 }
42
43
44 PROGRESSDISPLAY::PROGRESSDISPLAY (HWND hParent, int iddTemplate, DLGPROC dlgproc)
45 {
46    if (dlgproc == 0)
47       dlgproc = (DLGPROC)PROGRESSDISPLAY::ProgressDisplay_StubProc;
48    HWND hWnd = ModelessDialogParam (iddTemplate, hParent, dlgproc, (LPARAM)this);
49    Init (hWnd);
50    m_fCreatedWindow = TRUE;
51 }
52
53
54 PROGRESSDISPLAY::~PROGRESSDISPLAY (void)
55 {
56    m_fFinished = TRUE;
57    SetWindowLongPtr (m_hWnd, DWLP_USER, (LONG)0);
58    DeleteCriticalSection (&m_cs);
59    if (m_fCreatedWindow)
60       DestroyWindow (m_hWnd);
61 }
62
63
64 void PROGRESSDISPLAY::Init (HWND hWnd)
65 {
66    SetWindowLongPtr (hWnd, DWLP_USER, (LONG)this);
67    Subclass_AddHook (hWnd, PROGRESSDISPLAY::ProgressDisplay_HookProc);
68
69    m_msgFinish = 0;
70    m_fFinished = FALSE;
71    m_dwStatus = 0;
72    InitializeCriticalSection (&m_cs);
73    m_hWnd = hWnd;
74    m_fCreatedWindow = FALSE;
75    m_pfnUser = NULL;
76    m_lpUser = 0;
77    m_iProgress = 0;
78    m_cRef = 1;
79
80    GetDlgItemText (m_hWnd, IDC_OPERATION, m_szOperation, cchRESOURCE);
81    GetDlgItemText (m_hWnd, IDC_PROGRESSTEXT, m_szProgressText, cchRESOURCE);
82    SendDlgItemMessage (m_hWnd, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0,100));
83    SetProgressRange (0, 100);
84    SetProgress (0);
85 }
86
87
88 HWND PROGRESSDISPLAY::GetWindow (void)
89 {
90    return m_hWnd;
91 }
92
93 void PROGRESSDISPLAY::GetProgressRange (int *piStart, int *piFinish)
94 {
95    EnterCriticalSection (&m_cs);
96
97    if (piStart)
98       *piStart = m_iProgressStart;
99    if (piFinish)
100       *piFinish = m_iProgressFinish;
101
102    LeaveCriticalSection (&m_cs);
103 }
104
105
106 void PROGRESSDISPLAY::SetProgressRange (int iStart, int iFinish)
107 {
108    EnterCriticalSection (&m_cs);
109
110    m_iProgressStart = iStart;
111    m_iProgressFinish = iFinish;
112    PostMessage (m_hWnd, WM_UPDATE_PROGRESS, 0, 0);
113
114    LeaveCriticalSection (&m_cs);
115 }
116
117
118 int PROGRESSDISPLAY::GetProgress (void)
119 {
120    EnterCriticalSection (&m_cs);
121
122    int iProgress = m_iProgress;
123
124    LeaveCriticalSection (&m_cs);
125    return iProgress;
126 }
127
128
129 void PROGRESSDISPLAY::SetProgress (int iProgress)
130 {
131    EnterCriticalSection (&m_cs);
132
133    m_iProgress = max( m_iProgress, iProgress );
134    m_iProgress = min( max( m_iProgress, m_iProgressStart ), m_iProgressFinish );
135    PostMessage (m_hWnd, WM_UPDATE_PROGRESS, 0, 0);
136
137    LeaveCriticalSection (&m_cs);
138 }
139
140
141 void PROGRESSDISPLAY::GetOperation (LPTSTR pszOperation)
142 {
143    EnterCriticalSection (&m_cs);
144
145    lstrcpy (pszOperation, m_szOperation);
146
147    LeaveCriticalSection (&m_cs);
148 }
149
150
151 void PROGRESSDISPLAY::SetOperation (LPCTSTR pszOperation)
152 {
153    EnterCriticalSection (&m_cs);
154
155    lstrcpy (m_szOperation, pszOperation);
156    PostMessage (m_hWnd, WM_UPDATE_PROGRESS, 0, 0);
157
158    LeaveCriticalSection (&m_cs);
159 }
160
161
162 LPPROGRESSDISPLAY PROGRESSDISPLAY::GetProgressDisplay (HWND hWnd)
163 {
164    LPPROGRESSDISPLAY ppd = NULL;
165
166    try {
167       if ((ppd = (LPPROGRESSDISPLAY)(GetWindowLongPtr (hWnd, DWLP_USER))) != NULL) {
168          if (ppd->m_hWnd != hWnd)
169             ppd = NULL;
170       }
171    } catch(...) {
172       ppd = NULL;
173    }
174
175    return ppd;
176 }
177
178
179 BOOL CALLBACK PROGRESSDISPLAY::ProgressDisplay_StubProc (HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
180 {
181    return FALSE;
182 }
183
184
185 BOOL CALLBACK PROGRESSDISPLAY::ProgressDisplay_HookProc (HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
186 {
187    PVOID oldproc = Subclass_FindNextHook (hWnd, PROGRESSDISPLAY::ProgressDisplay_HookProc);
188
189    switch (msg)
190       {
191       case WM_UPDATE_PROGRESS:
192          if (!wp && !lp)
193             {
194             LPPROGRESSDISPLAY ppd;
195             if ((ppd = PROGRESSDISPLAY::GetProgressDisplay (hWnd)) != NULL)
196                ppd->OnUpdate();
197             return TRUE;
198             }
199          break;
200
201       case WM_DESTROY:
202          Subclass_RemoveHook (hWnd, PROGRESSDISPLAY::ProgressDisplay_HookProc);
203          break;
204       }
205
206    if (oldproc)
207       return CallWindowProc ((WNDPROC)oldproc, hWnd, msg, wp, lp);
208    else
209       return DefWindowProc (hWnd, msg, wp, lp);
210 }
211
212
213 void PROGRESSDISPLAY::SetFinishMessage (int msgFinish)
214 {
215    m_msgFinish = msgFinish;
216 }
217
218
219 void PROGRESSDISPLAY::Show (DWORD (CALLBACK *pfn)(LPPROGRESSDISPLAY ppd, LPARAM lp), LPARAM lp)
220 {
221    m_pfnUser = pfn;
222    m_lpUser = lp;
223
224    InterlockedIncrement (&m_cRef);
225
226    ShowWindow (m_hWnd, SW_SHOW);
227
228    DWORD dwThreadID;
229    HANDLE hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)(PROGRESSDISPLAY::ThreadProc), this, 0, &dwThreadID);
230
231    if (m_msgFinish == 0)
232       {
233       MSG msg;
234       while (GetMessage (&msg, 0, 0, NULL))
235          {
236          if (!IsDialogMessage (m_hWnd, &msg))
237             {
238             TranslateMessage (&msg);
239             DispatchMessage (&msg);
240             }
241
242          EnterCriticalSection (&m_cs);
243          BOOL fBreak = m_fFinished;
244          LeaveCriticalSection (&m_cs);
245          if (fBreak)
246             break;
247          }
248       }
249 }
250
251
252 void PROGRESSDISPLAY::Finish (DWORD dwStatus)
253 {
254    EnterCriticalSection (&m_cs);
255
256    m_fFinished = TRUE;
257    m_dwStatus = dwStatus;
258    if (m_msgFinish)
259       PostMessage (m_hWnd, m_msgFinish, 0, 0);
260    else
261       PostMessage (m_hWnd, WM_UPDATE_PROGRESS, 0, 0);
262
263    LeaveCriticalSection (&m_cs);
264
265    if (InterlockedDecrement (&m_cRef) == 0)
266       Delete (this);
267 }
268
269
270 DWORD PROGRESSDISPLAY::GetStatus (void)
271 {
272    EnterCriticalSection (&m_cs);
273    DWORD dwStatus = (m_fFinished) ? m_dwStatus : ERROR_BUSY;
274    LeaveCriticalSection (&m_cs);
275    return dwStatus;
276 }
277
278
279 void PROGRESSDISPLAY::Close (void)
280 {
281    EnterCriticalSection (&m_cs);
282
283    if (m_fCreatedWindow)
284       {
285       DestroyWindow (m_hWnd);
286       m_hWnd = NULL;
287       }
288
289    LeaveCriticalSection (&m_cs);
290
291    if (InterlockedDecrement (&m_cRef) == 0)
292       Delete (this);
293 }
294
295
296 void PROGRESSDISPLAY::OnUpdate (void)
297 {
298    EnterCriticalSection (&m_cs);
299
300    int perComplete;
301    if (m_iProgressFinish <= m_iProgressStart)
302       perComplete = 100;
303    else
304       perComplete = 100 * (m_iProgress - m_iProgressStart) / (m_iProgressFinish - m_iProgressStart);
305
306    SendDlgItemMessage (m_hWnd, IDC_PROGRESS, PBM_SETPOS, (WPARAM)perComplete, 0);
307
308    LPTSTR pszProgressText = FormatString (m_szProgressText, TEXT("%lu"), perComplete);
309    SetDlgItemText (m_hWnd, IDC_PROGRESSTEXT, pszProgressText);
310    FreeString (pszProgressText);
311
312    SetDlgItemText (m_hWnd, IDC_OPERATION, m_szOperation);
313
314    LeaveCriticalSection (&m_cs);
315 }
316
317
318 DWORD WINAPI PROGRESSDISPLAY::ThreadProc (PVOID lp)
319 {
320    LPPROGRESSDISPLAY ppd;
321    if ((ppd = (LPPROGRESSDISPLAY)lp) != NULL) {
322       DWORD dwStatus;
323
324       try {
325          dwStatus = (*(ppd->m_pfnUser))(ppd, ppd->m_lpUser);
326       } catch(...) {
327          dwStatus = ERROR_PROCESS_ABORTED;
328       }
329
330       ppd->Finish (dwStatus);
331    }
332    return 0;
333 }
334