|
|
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.