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