Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

421 lines
15 KiB

  1. /*
  2. * BUSY.CPP
  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. #include "precomp.h"
  10. #include "common.h"
  11. #include "utility.h"
  12. OLEDBGDATA
  13. // Internally used structure
  14. typedef struct tagBUSY
  15. {
  16. // Keep these items first as the Standard* functions depend on it here.
  17. LPOLEUIBUSY lpOBZ; // Original structure passed.
  18. UINT nIDD; // IDD of dialog (used for help info)
  19. /*
  20. * What we store extra in this structure besides the original caller's
  21. * pointer are those fields that we need to modify during the life of
  22. * the dialog or that we don't want to change in the original structure
  23. * until the user presses OK.
  24. */
  25. DWORD dwFlags; // Flags passed in
  26. HWND hWndBlocked; // HWND of app which is blocking
  27. } BUSY, *PBUSY, FAR *LPBUSY;
  28. // Internal function prototypes
  29. // BUSY.CPP
  30. INT_PTR CALLBACK BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
  31. BOOL GetTaskInfo(HWND hWnd, HTASK htask, LPTSTR* lplpszWindowName, HWND* lphWnd);
  32. void BuildBusyDialogString(HWND, DWORD, int, LPTSTR);
  33. BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam);
  34. void MakeWindowActive(HWND hWndSwitchTo);
  35. /*
  36. * OleUIBusy
  37. *
  38. * Purpose:
  39. * Invokes the standard OLE "Server Busy" dialog box which
  40. * notifies the user that the server application is not receiving
  41. * messages. The dialog then asks the user to either cancel
  42. * the operation, switch to the task which is blocked, or continue
  43. * waiting.
  44. *
  45. * Parameters:
  46. * lpBZ LPOLEUIBUSY pointing to the in-out structure
  47. * for this dialog.
  48. *
  49. * Return Value:
  50. * OLEUI_BZERR_HTASKINVALID : Error
  51. * OLEUI_BZ_SWITCHTOSELECTED : Success, user selected "switch to"
  52. * OLEUI_BZ_RETRYSELECTED : Success, user selected "retry"
  53. * OLEUI_CANCEL : Success, user selected "cancel"
  54. */
  55. STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY lpOBZ)
  56. {
  57. HGLOBAL hMemDlg = NULL;
  58. UINT uRet = UStandardValidation((LPOLEUISTANDARD)lpOBZ, sizeof(OLEUIBUSY),
  59. &hMemDlg);
  60. // Error out if the standard validation failed
  61. if (OLEUI_SUCCESS != uRet)
  62. return uRet;
  63. // Error out if our secondary validation failed
  64. if (OLEUI_ERR_STANDARDMIN <= uRet)
  65. {
  66. return uRet;
  67. }
  68. // Invoke the dialog.
  69. uRet = UStandardInvocation(BusyDialogProc, (LPOLEUISTANDARD)lpOBZ,
  70. hMemDlg, MAKEINTRESOURCE(IDD_BUSY));
  71. return uRet;
  72. }
  73. /*
  74. * BusyDialogProc
  75. *
  76. * Purpose:
  77. * Implements the OLE Busy dialog as invoked through the OleUIBusy function.
  78. *
  79. * Parameters:
  80. * Standard
  81. *
  82. * Return Value:
  83. * Standard
  84. *
  85. */
  86. INT_PTR CALLBACK BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
  87. {
  88. // Declare Win16/Win32 compatible WM_COMMAND parameters.
  89. COMMANDPARAMS(wID, wCode, hWndMsg);
  90. // This will fail under WM_INITDIALOG, where we allocate it.
  91. UINT uRet = 0;
  92. LPBUSY lpBZ = (LPBUSY)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
  93. // If the hook processed the message, we're done.
  94. if (0 != uRet)
  95. return (INT_PTR)uRet;
  96. // Process the temination message
  97. if (iMsg == uMsgEndDialog)
  98. {
  99. EndDialog(hDlg, wParam);
  100. return TRUE;
  101. }
  102. // Process our special "close" message. If we get this message,
  103. // this means that the call got unblocked, so we need to
  104. // return OLEUI_BZ_CALLUNBLOCKED to our calling app.
  105. if (iMsg == uMsgCloseBusyDlg)
  106. {
  107. SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_CALLUNBLOCKED, 0L);
  108. return TRUE;
  109. }
  110. switch (iMsg)
  111. {
  112. case WM_DESTROY:
  113. if (lpBZ)
  114. {
  115. StandardCleanup(lpBZ, hDlg);
  116. }
  117. break;
  118. case WM_INITDIALOG:
  119. FBusyInit(hDlg, wParam, lParam);
  120. return TRUE;
  121. case WM_ACTIVATEAPP:
  122. {
  123. /* try to bring down our Busy/NotResponding dialog as if
  124. ** the user entered RETRY.
  125. */
  126. BOOL fActive = (BOOL)wParam;
  127. if (fActive)
  128. {
  129. // If this is the app BUSY case, then bring down our
  130. // dialog when switching BACK to our app
  131. if (lpBZ && !(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
  132. SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);
  133. }
  134. else
  135. {
  136. // If this is the app NOT RESPONDING case, then bring down
  137. // our dialog when switching AWAY to another app
  138. if (lpBZ && (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
  139. SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);
  140. }
  141. }
  142. return TRUE;
  143. case WM_COMMAND:
  144. switch (wID)
  145. {
  146. case IDC_BZ_SWITCHTO:
  147. {
  148. BOOL fNotRespondingDlg =
  149. (BOOL)(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG);
  150. HWND hwndTaskList = hDlg;
  151. // If this is the app not responding case, then we want
  152. // to bring down the dialog when "SwitchTo" is selected.
  153. // If the app is busy (RetryRejectedCall situation) then
  154. // we do NOT want to bring down the dialog. this is
  155. // the OLE2.0 user model design.
  156. if (fNotRespondingDlg)
  157. {
  158. hwndTaskList = GetParent(hDlg);
  159. if (hwndTaskList == NULL)
  160. hwndTaskList = GetDesktopWindow();
  161. PostMessage(hDlg, uMsgEndDialog,
  162. OLEUI_BZ_SWITCHTOSELECTED, 0L);
  163. }
  164. // If user selects "Switch To...", switch activation
  165. // directly to the window which is causing the problem.
  166. if (IsWindow(lpBZ->hWndBlocked))
  167. MakeWindowActive(lpBZ->hWndBlocked);
  168. else
  169. PostMessage(hwndTaskList, WM_SYSCOMMAND, SC_TASKLIST, 0);
  170. }
  171. break;
  172. case IDC_BZ_RETRY:
  173. SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_RETRYSELECTED, 0L);
  174. break;
  175. case IDCANCEL:
  176. SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
  177. break;
  178. }
  179. break;
  180. }
  181. return FALSE;
  182. }
  183. /*
  184. * FBusyInit
  185. *
  186. * Purpose:
  187. * WM_INITIDIALOG handler for the Busy dialog box.
  188. *
  189. * Parameters:
  190. * hDlg HWND of the dialog
  191. * wParam WPARAM of the message
  192. * lParam LPARAM of the message
  193. *
  194. * Return Value:
  195. * BOOL Value to return for WM_INITDIALOG.
  196. */
  197. BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
  198. {
  199. HFONT hFont;
  200. LPBUSY lpBZ = (LPBUSY)LpvStandardInit(hDlg, sizeof(BUSY), &hFont);
  201. // PvStandardInit sent a termination to us already.
  202. if (NULL == lpBZ)
  203. return FALSE;
  204. // Our original structure is in lParam
  205. LPOLEUIBUSY lpOBZ = (LPOLEUIBUSY)lParam;
  206. // Copy it to our instance of the structure (in lpBZ)
  207. lpBZ->lpOBZ = lpOBZ;
  208. lpBZ->nIDD = IDD_BUSY;
  209. //Copy other information from lpOBZ that we might modify.
  210. lpBZ->dwFlags = lpOBZ->dwFlags;
  211. // Set default information
  212. lpBZ->hWndBlocked = NULL;
  213. // Insert HWND of our dialog into the address pointed to by
  214. // lphWndDialog. This can be used by the app who called
  215. // OleUIBusy to bring down the dialog with uMsgCloseBusyDialog
  216. if (lpOBZ->lphWndDialog &&
  217. !IsBadWritePtr(lpOBZ->lphWndDialog, sizeof(HWND)))
  218. {
  219. *lpOBZ->lphWndDialog = hDlg;
  220. }
  221. // Update text in text box --
  222. // GetTaskInfo will return two pointers, one to the task name
  223. // (file name) and one to the window name. We need to call
  224. // OleStdFree on these when we're done with them. We also
  225. // get the HWND which is blocked in this call
  226. //
  227. // In the case where this call fails, a default message should already
  228. // be present in the dialog template, so no action is needed
  229. LPTSTR lpWindowName;
  230. if (GetTaskInfo(hDlg, lpOBZ->hTask, &lpWindowName, &lpBZ->hWndBlocked))
  231. {
  232. // Build string to present to user, place in IDC_BZ_MESSAGE1 control
  233. BuildBusyDialogString(hDlg, lpBZ->dwFlags, IDC_BZ_MESSAGE1, lpWindowName);
  234. OleStdFree(lpWindowName);
  235. }
  236. // Update icon with the system "exclamation" icon
  237. HICON hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
  238. SendDlgItemMessage(hDlg, IDC_BZ_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
  239. // Disable/Enable controls
  240. if ((lpBZ->dwFlags & BZ_DISABLECANCELBUTTON) ||
  241. (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
  242. {
  243. // Disable cancel for "not responding" dialog
  244. StandardEnableDlgItem(hDlg, IDCANCEL, FALSE);
  245. }
  246. if (lpBZ->dwFlags & BZ_DISABLESWITCHTOBUTTON)
  247. StandardEnableDlgItem(hDlg, IDC_BZ_SWITCHTO, FALSE);
  248. if (lpBZ->dwFlags & BZ_DISABLERETRYBUTTON)
  249. StandardEnableDlgItem(hDlg, IDC_BZ_RETRY, FALSE);
  250. // Call the hook with lCustData in lParam
  251. UStandardHook((LPVOID)lpBZ, hDlg, WM_INITDIALOG, wParam, lpOBZ->lCustData);
  252. // Update caption if lpszCaption was specified
  253. if (lpBZ->lpOBZ->lpszCaption && !IsBadReadPtr(lpBZ->lpOBZ->lpszCaption, 1))
  254. {
  255. SetWindowText(hDlg, lpBZ->lpOBZ->lpszCaption);
  256. }
  257. return TRUE;
  258. }
  259. /*
  260. * BuildBusyDialogString
  261. *
  262. * Purpose:
  263. * Builds the string that will be displayed in the dialog from the
  264. * task name and window name parameters.
  265. *
  266. * Parameters:
  267. * hDlg HWND of the dialog
  268. * dwFlags DWORD containing flags passed into dialog
  269. * iControl Control ID to place the text string
  270. * lpTaskName LPSTR pointing to name of task (e.g. C:\TEST\TEST.EXE)
  271. * lpWindowName LPSTR for name of window
  272. *
  273. * Caveats:
  274. * The caller of this function MUST de-allocate the lpTaskName and
  275. * lpWindowName pointers itself with OleStdFree
  276. *
  277. * Return Value:
  278. * void
  279. */
  280. void BuildBusyDialogString(
  281. HWND hDlg, DWORD dwFlags, int iControl, LPTSTR lpWindowName)
  282. {
  283. // Load the format string out of stringtable, choose a different
  284. // string depending on what flags are passed in to the dialog
  285. UINT uiStringNum;
  286. if (dwFlags & BZ_NOTRESPONDINGDIALOG)
  287. uiStringNum = IDS_BZRESULTTEXTNOTRESPONDING;
  288. else
  289. uiStringNum = IDS_BZRESULTTEXTBUSY;
  290. TCHAR szFormat[256];
  291. if (LoadString(_g_hOleStdResInst, uiStringNum, szFormat, 256) == 0)
  292. return;
  293. // Build the string. The format string looks like this:
  294. // "This action cannot be completed because the "%1" application
  295. // is [busy | not responding]. Choose \"Switch To\" to correct the
  296. // problem."
  297. TCHAR szMessage[512];
  298. FormatString1(szMessage, szFormat, lpWindowName, 512);
  299. SetDlgItemText(hDlg, iControl, szMessage);
  300. }
  301. /*
  302. * GetTaskInfo()
  303. *
  304. * Purpose: Gets information about the specified task and places the
  305. * module name, window name and top-level HWND for the task in the specified
  306. * pointers
  307. *
  308. * NOTE: The two string pointers allocated in this routine are
  309. * the responsibility of the CALLER to de-allocate.
  310. *
  311. * Parameters:
  312. * hWnd HWND who called this function
  313. * htask HTASK which we want to find out more info about
  314. * lplpszTaskName Location that the module name is returned
  315. * lplpszWindowName Location where the window name is returned
  316. *
  317. */
  318. BOOL GetTaskInfo(
  319. HWND hWnd, HTASK htask, LPTSTR* lplpszWindowName, HWND* lphWnd)
  320. {
  321. if (htask == NULL)
  322. return FALSE;
  323. // initialize 'out' parameters
  324. *lplpszWindowName = NULL;
  325. // Now, enumerate top-level windows in system
  326. HWND hwndNext = GetWindow(hWnd, GW_HWNDFIRST);
  327. while (hwndNext)
  328. {
  329. // See if we can find a non-owned top level window whose
  330. // hInstance matches the one we just got passed. If we find one,
  331. // we can be fairly certain that this is the top-level window for
  332. // the task which is blocked.
  333. DWORD dwProcessID;
  334. DWORD dwThreadID = GetWindowThreadProcessId(hwndNext, &dwProcessID);
  335. if ((hwndNext != hWnd) &&
  336. (dwThreadID == HandleToUlong(htask)) &&
  337. (IsWindowVisible(hwndNext)) && !GetWindow(hwndNext, GW_OWNER))
  338. {
  339. // We found our window! Alloc space for new strings
  340. LPTSTR lpszWN;
  341. if ((lpszWN = (LPTSTR)OleStdMalloc(MAX_PATH_SIZE)) == NULL)
  342. break;
  343. // We found the window we were looking for, copy info to
  344. // local vars
  345. GetWindowText(hwndNext, lpszWN, MAX_PATH);
  346. // Note: the task name cannot be retrieved with the Win32 API.
  347. // everything was successful. Set string pointers to point to our data.
  348. *lplpszWindowName = lpszWN;
  349. *lphWnd = hwndNext;
  350. return TRUE;
  351. }
  352. hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
  353. }
  354. return FALSE;
  355. }
  356. /*
  357. * MakeWindowActive()
  358. *
  359. * Purpose: Makes specified window the active window.
  360. *
  361. */
  362. void MakeWindowActive(HWND hWndSwitchTo)
  363. {
  364. // If it's iconic, we need to restore it.
  365. if (IsIconic(hWndSwitchTo))
  366. ShowWindow(hWndSwitchTo, SW_RESTORE);
  367. // Move the new window to the top of the Z-order
  368. SetForegroundWindow(GetLastActivePopup(hWndSwitchTo));
  369. }