|
|
1.1 root 1: /*
2: * BUSY.C
3: *
4: * Implements the OleUIBusy function which invokes the "Server Busy"
5: * dialog.
6: *
7: * Copyright (c)1992 Microsoft Corporation, All Right Reserved
8: */
9:
10: #define STRICT 1
11: #include "ole2ui.h"
12: #include "common.h"
13: #include "utility.h"
14: #include "busy.h"
15: #include <ctype.h> // for tolower() and toupper()
16:
17: #ifndef WIN32
18: #include <toolhelp.h>
19: #endif
20:
21:
22: /*
23: * OleUIBusy
24: *
25: * Purpose:
26: * Invokes the standard OLE "Server Busy" dialog box which
27: * notifies the user that the server application is not receiving
28: * messages. The dialog then asks the user to either cancel
29: * the operation, switch to the task which is blocked, or continue
30: * waiting.
31: *
32: * Parameters:
33: * lpBZ LPOLEUIBUSY pointing to the in-out structure
34: * for this dialog.
35: *
36: * Return Value:
37: * OLEUI_BZERR_HTASKINVALID : Error
38: * OLEUI_BZ_SWITCHTOSELECTED : Success, user selected "switch to"
39: * OLEUI_BZ_RETRYSELECTED : Success, user selected "retry"
40: * OLEUI_CANCEL : Success, user selected "cancel"
41: */
42:
43: STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY lpOBZ)
44: {
45: UINT uRet = 0;
46: HGLOBAL hMemDlg=NULL;
47:
48: #if defined( NT_BUG )
49:
50: uRet=UStandardValidation((LPOLEUISTANDARD)lpOBZ, sizeof(OLEUIBUSY)
51: , &hMemDlg);
52:
53: // Error out if the standard validation failed
54: if (OLEUI_SUCCESS!=uRet)
55: return uRet;
56:
57: #if !defined( WIN32 )
58: // Validate HTASK
59: if (!IsTask(lpOBZ->hTask))
60: uRet = OLEUI_BZERR_HTASKINVALID;
61: #endif
62:
63: // Error out if our secondary validation failed
64: if (OLEUI_ERR_STANDARDMIN <= uRet)
65: {
66: if (NULL!=hMemDlg)
67: FreeResource(hMemDlg);
68:
69: return uRet;
70: }
71:
72: // Invoke the dialog.
73: uRet=UStandardInvocation(BusyDialogProc, (LPOLEUISTANDARD)lpOBZ,
74: hMemDlg, MAKEINTRESOURCE(IDD_BUSY));
75: #endif
76:
77: return uRet;
78: }
79:
80:
81: /*
82: * BusyDialogProc
83: *
84: * Purpose:
85: * Implements the OLE Busy dialog as invoked through the OleUIBusy function.
86: *
87: * Parameters:
88: * Standard
89: *
90: * Return Value:
91: * Standard
92: *
93: */
94:
95: BOOL CALLBACK EXPORT BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
96: {
97: LPBUSY lpBZ;
98: UINT uRet = 0;
99:
100: //Declare Win16/Win32 compatible WM_COMMAND parameters.
101: COMMANDPARAMS(wID, wCode, hWndMsg);
102:
103: //This will fail under WM_INITDIALOG, where we allocate it.
104: lpBZ=(LPBUSY)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
105:
106: //If the hook processed the message, we're done.
107: if (0!=uRet)
108: return (BOOL)uRet;
109:
110: //Process the temination message
111: if (iMsg==uMsgEndDialog)
112: {
113: BusyCleanup(hDlg);
114: StandardCleanup(lpBZ, hDlg);
115: EndDialog(hDlg, wParam);
116: return TRUE;
117: }
118:
119: // Process our special "close" message. If we get this message,
120: // this means that the call got unblocked, so we need to
121: // return OLEUI_BZ_CALLUNBLOCKED to our calling app.
122: if (iMsg == uMsgCloseBusyDlg)
123: {
124: SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_CALLUNBLOCKED, 0L);
125: return TRUE;
126: }
127:
128: switch (iMsg)
129: {
130: case WM_INITDIALOG:
131: FBusyInit(hDlg, wParam, lParam);
132: return TRUE;
133:
134: case WM_COMMAND:
135: switch (wID)
136: {
137: case IDBZ_SWITCHTO:
138:
139: // If user selects "Switch To...", switch activation
140: // directly to the window which is causing the problem.
141: if (IsWindow(lpBZ->hWndBlocked))
142: MakeWindowActive(lpBZ->hWndBlocked);
143: else
144: StartTaskManager(); // Fail safe: Start Task Manager
145:
146: // If this is the app not responding case, then we want
147: // to bring down the dialog when "SwitchTo" is selected.
148: // If the app is busy (RetryRejectedCall situation) then
149: // we do NOT want to bring down the dialog. this is
150: // the OLE2.0 user model design.
151: if (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG)
152: SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_SWITCHTOSELECTED, 0L);
153: break;
154:
155: case IDBZ_RETRY:
156: SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_RETRYSELECTED, 0L);
157: break;
158:
159: case IDCANCEL:
160: SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
161: break;
162: }
163: break;
164: }
165: return FALSE;
166: }
167:
168:
169: /*
170: * FBusyInit
171: *
172: * Purpose:
173: * WM_INITIDIALOG handler for the Busy dialog box.
174: *
175: * Parameters:
176: * hDlg HWND of the dialog
177: * wParam WPARAM of the message
178: * lParam LPARAM of the message
179: *
180: * Return Value:
181: * BOOL Value to return for WM_INITDIALOG.
182: */
183:
184: BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
185: {
186: LPBUSY lpBZ;
187: LPOLEUIBUSY lpOBZ;
188: HFONT hFont;
189: LPSTR lpTaskName;
190: LPSTR lpWindowName;
191: HICON hIcon;
192:
193: lpBZ=(LPBUSY)LpvStandardInit(hDlg, sizeof(OLEUIBUSY), TRUE, &hFont);
194:
195: // PvStandardInit sent a termination to us already.
196: if (NULL==lpBZ)
197: return FALSE;
198:
199: // Our original structure is in lParam
200: lpOBZ = (LPOLEUIBUSY)lParam;
201:
202: // Copy it to our instance of the structure (in lpBZ)
203: lpBZ->lpOBZ=lpOBZ;
204:
205: //Copy other information from lpOBZ that we might modify.
206: lpBZ->dwFlags = lpOBZ->dwFlags;
207:
208: // Set default information
209: lpBZ->hWndBlocked = NULL;
210:
211: // Insert HWND of our dialog into the address pointed to by
212: // lphWndDialog. This can be used by the app who called
213: // OleUIBusy to bring down the dialog with uMsgCloseBusyDialog
214: if (lpOBZ->lphWndDialog &&
215: !IsBadWritePtr((VOID FAR *)lpOBZ->lphWndDialog, sizeof(HWND)))
216: {
217: *lpOBZ->lphWndDialog = hDlg;
218: }
219:
220: // Update text in text box --
221: // GetTaskInfo will return two pointers, one to the task name
222: // (file name) and one to the window name. We need to call
223: // IMallocMemFree on these when we're done with them. We also
224: // get the HWND which is blocked in this call
225: //
226: // In the case where this call fails, a default message should already
227: // be present in the dialog template, so no action is needed
228:
229: if (GetTaskInfo(hDlg, lpOBZ->hTask, &lpTaskName, &lpWindowName, &lpBZ->hWndBlocked))
230: {
231: // Build string to present to user, place in IDBZ_MESSAGE1 control
232: BuildBusyDialogString(hDlg, lpBZ->dwFlags, IDBZ_MESSAGE1, lpTaskName, lpWindowName);
233: IMallocMemFree(lpTaskName);
234: IMallocMemFree(lpWindowName);
235: }
236:
237: // Update icon with the system "exclamation" icon
238: hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
239: SendDlgItemMessage(hDlg, IDBZ_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
240:
241: // Disable/Enable controls
242: if ((lpBZ->dwFlags & BZ_DISABLECANCELBUTTON) ||
243: (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG)) // Disable cancel for "not responding" dialog
244: EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
245:
246: if (lpBZ->dwFlags & BZ_DISABLESWITCHTOBUTTON)
247: EnableWindow(GetDlgItem(hDlg, IDBZ_SWITCHTO), FALSE);
248:
249: if (lpBZ->dwFlags & BZ_DISABLERETRYBUTTON)
250: EnableWindow(GetDlgItem(hDlg, IDBZ_RETRY), FALSE);
251:
252: // Call the hook with lCustData in lParam
253: UStandardHook((LPVOID)lpBZ, hDlg, WM_INITDIALOG, wParam, lpOBZ->lCustData);
254:
255: // Update caption if lpszCaption was specified
256: if (lpBZ->lpOBZ->lpszCaption && !IsBadReadPtr(lpBZ->lpOBZ->lpszCaption, 1)
257: && lpBZ->lpOBZ->lpszCaption[0] != '\0')
258: SetWindowText(hDlg, (LPSTR)lpBZ->lpOBZ->lpszCaption);
259:
260: return TRUE;
261: }
262:
263:
264: /*
265: * BuildBusyDialogString
266: *
267: * Purpose:
268: * Builds the string that will be displayed in the dialog from the
269: * task name and window name parameters.
270: *
271: * Parameters:
272: * hDlg HWND of the dialog
273: * dwFlags DWORD containing flags passed into dialog
274: * iControl Control ID to place the text string
275: * lpTaskName LPSTR pointing to name of task (e.g. C:\TEST\TEST.EXE)
276: * lpWindowName LPSTR for name of window
277: *
278: * Caveats:
279: * The caller of this function MUST de-allocate the lpTaskName and
280: * lpWindowName pointers itself with IMallocMemFree.
281: *
282: * Return Value:
283: * void
284: */
285:
286: void BuildBusyDialogString(HWND hDlg, DWORD dwFlags, int iControl, LPSTR lpTaskName, LPSTR lpWindowName)
287: {
288: LPSTR pszT, psz1, psz2, psz3;
289: UINT cch;
290: LPSTR pszDot, pszSlash;
291: UINT uiStringNum;
292:
293: /*
294: * We need scratch memory for loading the stringtable string,
295: * the task name, and constructing the final string. We therefore
296: * allocate three buffers as large as the maximum message
297: * length (512) plus the object type, guaranteeing that we have enough
298: * in all cases.
299: */
300: cch=512;
301:
302: // Use OLE-supplied allocation
303: if ((pszT = IMallocMemAlloc((DWORD)(3*cch))) == NULL)
304: return;
305:
306: psz1=pszT;
307: psz2=psz1+cch;
308: psz3=psz2+cch;
309:
310: // Parse base name out of path name, use psz2 for the task
311: // name to display
312:
313: _fstrcpy(psz2, lpTaskName);
314: pszDot = _fstrrchr(psz2, '.');
315: if (pszDot != NULL)
316: *pszDot = '\0'; // Null terminate at the DOT
317:
318: pszSlash = _fstrrchr(psz2, '\\'); // Find last backslash in path
319: if (pszSlash != NULL)
320: psz2 = pszSlash + 1; // Nuke everything up to this point
321:
322: #ifdef LOWERCASE_NAME
323: // Compile this with /DLOWERCASE_NAME if you want the lower-case
324: // module name to be displayed in the dialog rather than the
325: // all-caps name.
326: {
327: int i,l;
328:
329: // Now, lowercase all letters except first one
330: l = _fstrlen(psz2);
331: for(i=0;i<l;i++)
332: psz2[i] = tolower(psz2[i]);
333:
334: psz2[0] = toupper(psz2[0]);
335: }
336: #endif
337:
338: // Check size of lpWindowName. We can reasonably fit about 80
339: // characters into the text control, so truncate more than 80 chars
340: if (_fstrlen(lpWindowName) > 80)
341: lpWindowName[80] = '\0';
342:
343: // Load the format string out of stringtable, choose a different
344: // string depending on what flags are passed in to the dialog
345: if (dwFlags & BZ_NOTRESPONDINGDIALOG)
346: uiStringNum = IDS_BZRESULTTEXTNOTRESPONDING;
347: else
348: uiStringNum = IDS_BZRESULTTEXTBUSY;
349:
350: if (LoadString(ghInst, uiStringNum, psz1, cch) == 0)
351: return;
352:
353: // Build the string. The format string looks like this:
354: // "This action cannot be completed because the '%s' application
355: // (%s) is [busy | not responding]. Choose \"Switch To\" to activate '%s' and
356: // correct the problem."
357:
358: wsprintf(psz3, psz1, (LPSTR)psz2, (LPSTR)lpWindowName, (LPSTR)psz2);
359: SetDlgItemText(hDlg, iControl, (LPSTR)psz3);
360: IMallocMemFree(pszT);
361:
362: return;
363: }
364:
365:
366:
367: /*
368: * BusyCleanup
369: *
370: * Purpose:
371: * Performs busy-specific cleanup before termination.
372: *
373: * Parameters:
374: * hDlg HWND of the dialog box so we can access controls.
375: *
376: * Return Value:
377: * None
378: */
379: void BusyCleanup(HWND hDlg)
380: {
381: return;
382: }
383:
384:
385:
386: /*
387: * GetTaskInfo()
388: *
389: * Purpose: Gets information about the specified task and places the
390: * module name, window name and top-level HWND for the task in the specified
391: * pointers
392: *
393: * NOTE: The two string pointers allocated in this routine are
394: * the responsibility of the CALLER to de-allocate.
395: *
396: * Parameters:
397: * hWnd HWND who called this function
398: * htask HTASK which we want to find out more info about
399: * lplpszTaskName Location that the module name is returned
400: * lplpszWindowName Location where the window name is returned
401: *
402: */
403:
404: BOOL GetTaskInfo(HWND hWnd, HTASK htask, LPSTR FAR* lplpszTaskName, LPSTR FAR*lplpszWindowName, HWND FAR*lphWnd)
405: {
406: BOOL fRet = FALSE;
407: #if !defined( WIN32 )
408: TASKENTRY te;
409: #endif
410: HWND hwndNext;
411: LPSTR lpszTN = NULL;
412: LPSTR lpszWN = NULL;
413: HWND hwndFind = NULL;
414:
415: // Clear out return values in case of error
416: *lplpszTaskName = NULL;
417: *lplpszWindowName = NULL;
418:
419: #if !defined( WIN32 )
420: te.dwSize = sizeof(TASKENTRY);
421: if (TaskFindHandle(&te, htask))
422: #endif
423: {
424: // Now, enumerate top-level windows in system
425: hwndNext = GetWindow(hWnd, GW_HWNDFIRST);
426: while (hwndNext)
427: {
428: // See if we can find a non-owned top level window whose
429: // hInstance matches the one we just got passed. If we find one,
430: // we can be fairly certain that this is the top-level window for
431: // the task which is blocked.
432: //
433: // REVIEW: Will this filter hold true for InProcServer DLL-created
434: // windows?
435: //
436: if ((hwndNext != hWnd) &&
437: #if !defined( WIN32 )
438: (GetWindowWord(hwndNext, GWW_HINSTANCE) == (WORD)te.hInst) &&
439: #else
440: (GetWindowThreadProcessId(hwndNext,NULL) == htask) &&
441: #endif
442: (IsWindowVisible(hwndNext)) &&
443: !GetWindow(hwndNext, GW_OWNER))
444: {
445: // We found our window! Alloc space for new strings
446: if ((lpszTN = IMallocMemAlloc(OLEUI_CCHPATHMAX)) == NULL)
447: return TRUE; // continue task window enumeration
448:
449: if ((lpszWN = IMallocMemAlloc(OLEUI_CCHPATHMAX)) == NULL)
450: return TRUE; // continue task window enumeration
451:
452: // We found the window we were looking for, copy info to
453: // local vars
454: GetWindowText(hwndNext, lpszWN, OLEUI_CCHPATHMAX);
455: #if !defined( WIN32 )
456: lstrcpyn(lpszTN, te.szModule, OLEUI_CCHPATHMAX);
457: #else
458: /* WIN32 NOTE: we are not able to get a module name
459: ** given a thread process id on WIN32. the best we
460: ** can do is use the window title as the module/app
461: ** name.
462: */
463: lstrcpyn(lpszTN, lpszWN, OLEUI_CCHPATHMAX);
464: #endif
465: hwndFind = hwndNext;
466:
467: fRet = TRUE;
468: goto OKDone;
469: }
470:
471: hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
472: }
473: }
474:
475: OKDone:
476:
477: // OK, everything was successful. Set string pointers to point to
478: // our data.
479:
480: *lplpszTaskName = lpszTN;
481: *lplpszWindowName = lpszWN;
482: *lphWnd = hwndFind;
483:
484: return fRet;
485: }
486:
487:
488: /*
489: * IMallocMemAlloc()
490: *
491: * Purpose: Allocates dwSize bytes of memory using the OLE-supplied
492: * memory allocation.
493: *
494: * Parameters:
495: * dwSize Size of memory requested
496: *
497: * Returns:
498: * void FAR * Pointer to new memory, or NULL if failed
499: *
500: */
501:
502: void FAR * IMallocMemAlloc(DWORD dwSize)
503: {
504: LPMALLOC pIMalloc;
505: LPSTR pszT;
506:
507: // Use OLE-supplied allocation
508: if (CoGetMalloc(MEMCTX_TASK, &pIMalloc) != NOERROR)
509: return NULL;
510:
511: pszT=(LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, dwSize);
512: pIMalloc->lpVtbl->Release(pIMalloc);
513: return pszT;
514: }
515:
516:
517: /*
518: * IMallocMemFree()
519: *
520: * Purpose: Frees memory allocated with IMallocMemAlloc()
521: *
522: * Parameters:
523: * ptr Pointer to memory to free
524: *
525: * Returns:
526: * SCODE Return code from CoGetMalloc
527: */
528:
529: SCODE IMallocMemFree(void FAR *ptr)
530: {
531: SCODE sc;
532: LPMALLOC pIMalloc;
533:
534: sc = GetScode(CoGetMalloc(MEMCTX_TASK, &pIMalloc));
535: if (SUCCEEDED(sc))
536: {
537: pIMalloc->lpVtbl->Free(pIMalloc, ptr);
538: pIMalloc->lpVtbl->Release(pIMalloc);
539: }
540: return sc;
541:
542: }
543:
544:
545: /*
546: * StartTaskManager()
547: *
548: * Purpose: Starts Task Manager. Used to bring up task manager to
549: * assist in switching to a given blocked task.
550: *
551: */
552:
553: StartTaskManager()
554: {
555: WinExec("taskman.exe", SW_SHOW);
556: return TRUE;
557: }
558:
559:
560:
561: /*
562: * MakeWindowActive()
563: *
564: * Purpose: Makes specified window the active window.
565: *
566: */
567:
568: void MakeWindowActive(HWND hWndSwitchTo)
569: {
570: // Move the new window to the top of the Z-order
571: SetWindowPos(hWndSwitchTo, HWND_TOP, 0, 0, 0, 0,
572: SWP_NOSIZE | SWP_NOMOVE);
573:
574: // If it's iconic, we need to restore it.
575: if (IsIconic(hWndSwitchTo))
576: ShowWindow(hWndSwitchTo, SW_RESTORE);
577: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.