Source code of Windows XP (NT5)
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.

809 lines
28 KiB

  1. /*
  2. * MSGFILTR.C
  3. *
  4. * This file contains a standard implementation of IMessageFilter
  5. * interface.
  6. * This file is part of the OLE 2.0 User Interface support library.
  7. *
  8. * (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
  9. *
  10. */
  11. #define STRICT 1
  12. #include "ole2ui.h"
  13. #include "msgfiltr.h"
  14. OLEDBGDATA
  15. typedef struct tagOLESTDMESSAGEFILTER {
  16. IMessageFilterVtbl FAR* m_lpVtbl;
  17. UINT m_cRef;
  18. HWND m_hWndParent;
  19. DWORD m_dwInComingCallStatus; // Status to return from
  20. // HandleIncomingCall
  21. HANDLEINCOMINGCALLBACKPROC m_lpfnHandleInComingCallback;
  22. // Callback function
  23. // to selectively handle
  24. // interface method calls
  25. BOOL m_fEnableBusyDialog; // enable RetryRejected
  26. // Call dialog
  27. BOOL m_fEnableNotRespondingDialog; // enable
  28. // MessagePending dialog
  29. MSGPENDINGPROC m_lpfnMessagePendingCallback; // MessagePending
  30. // Callback function
  31. LPFNOLEUIHOOK m_lpfnBusyDialogHookCallback; // Busy dialog hook
  32. LPTSTR m_lpszAppName; // Name of application
  33. // installing filter
  34. HWND m_hWndBusyDialog; // HWND of busy dialog. Used
  35. // to tear down dialog.
  36. BOOL m_bUnblocking;
  37. }OLESTDMESSAGEFILTER, FAR* LPOLESTDMESSAGEFILTER;
  38. /* interface IMessageFilter implementation */
  39. STDMETHODIMP OleStdMsgFilter_QueryInterface(
  40. LPMESSAGEFILTER lpThis, REFIID riid, LPVOID FAR* ppvObj);
  41. STDMETHODIMP_(ULONG) OleStdMsgFilter_AddRef(LPMESSAGEFILTER lpThis);
  42. STDMETHODIMP_(ULONG) OleStdMsgFilter_Release(LPMESSAGEFILTER lpThis);
  43. STDMETHODIMP_(DWORD) OleStdMsgFilter_HandleInComingCall (
  44. LPMESSAGEFILTER lpThis,
  45. DWORD dwCallType,
  46. HTASK htaskCaller,
  47. DWORD dwTickCount,
  48. #ifdef WIN32
  49. LPINTERFACEINFO dwReserved
  50. #else
  51. DWORD dwReserved
  52. #endif
  53. );
  54. STDMETHODIMP_(DWORD) OleStdMsgFilter_RetryRejectedCall (
  55. LPMESSAGEFILTER lpThis,
  56. HTASK htaskCallee,
  57. DWORD dwTickCount,
  58. DWORD dwRejectType
  59. );
  60. STDMETHODIMP_(DWORD) OleStdMsgFilter_MessagePending (
  61. LPMESSAGEFILTER lpThis,
  62. HTASK htaskCallee,
  63. DWORD dwTickCount,
  64. DWORD dwPendingType
  65. );
  66. static IMessageFilterVtbl g_OleStdMessageFilterVtbl = {
  67. OleStdMsgFilter_QueryInterface,
  68. OleStdMsgFilter_AddRef,
  69. OleStdMsgFilter_Release,
  70. OleStdMsgFilter_HandleInComingCall,
  71. OleStdMsgFilter_RetryRejectedCall,
  72. OleStdMsgFilter_MessagePending
  73. };
  74. /* GetTopWindowInWindowsTask
  75. ** -------------------------
  76. ** Get the top most window that has focus in the given task to be
  77. ** used as the parent for the busy dialog. we do this to handle the
  78. ** case where a dialog window is currently up when we need to give
  79. ** the busy dialog. if we use the current assigned parent window
  80. ** (which typically will be the frame window of the app), then the
  81. ** busy dialog will not be modal to the current active dialog
  82. ** window.
  83. */
  84. static HWND GetTopWindowInWindowsTask(HWND hwnd)
  85. {
  86. HWND hwndActive = GetActiveWindow();
  87. if (!hwndActive)
  88. return hwnd;
  89. if (GetWindowTask(hwnd) == GetWindowTask(hwndActive))
  90. return hwndActive;
  91. else
  92. return hwnd;
  93. }
  94. STDAPI_(LPMESSAGEFILTER) OleStdMsgFilter_Create(
  95. HWND hWndParent,
  96. LPTSTR szAppName,
  97. MSGPENDINGPROC lpfnCallback,
  98. LPFNOLEUIHOOK lpfnOleUIHook // Busy dialog hook callback
  99. )
  100. {
  101. LPOLESTDMESSAGEFILTER lpStdMsgFilter;
  102. LPMALLOC lpMalloc;
  103. if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)
  104. return NULL;
  105. lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpMalloc->lpVtbl->Alloc(
  106. lpMalloc, (sizeof(OLESTDMESSAGEFILTER)));
  107. lpMalloc->lpVtbl->Release(lpMalloc);
  108. if (! lpStdMsgFilter) return NULL;
  109. lpStdMsgFilter->m_lpVtbl = &g_OleStdMessageFilterVtbl;
  110. lpStdMsgFilter->m_cRef = 1;
  111. lpStdMsgFilter->m_hWndParent = hWndParent;
  112. lpStdMsgFilter->m_dwInComingCallStatus = SERVERCALL_ISHANDLED;
  113. lpStdMsgFilter->m_lpfnHandleInComingCallback = NULL;
  114. lpStdMsgFilter->m_fEnableBusyDialog = TRUE;
  115. lpStdMsgFilter->m_fEnableNotRespondingDialog = TRUE;
  116. lpStdMsgFilter->m_lpszAppName = szAppName;
  117. lpStdMsgFilter->m_lpfnMessagePendingCallback = lpfnCallback;
  118. lpStdMsgFilter->m_lpfnBusyDialogHookCallback = lpfnOleUIHook;
  119. lpStdMsgFilter->m_hWndBusyDialog = NULL;
  120. lpStdMsgFilter->m_bUnblocking = FALSE;
  121. return (LPMESSAGEFILTER)lpStdMsgFilter;
  122. }
  123. /* OleStdMsgFilter_SetInComingStatus
  124. ** ---------------------------------
  125. ** This is a private function that allows the caller to control what
  126. ** value is returned from the IMessageFilter::HandleInComing method.
  127. **
  128. ** if a HandleInComingCallbackProc is installed by a call to
  129. ** OleStdMsgFilter_SetHandleInComingCallbackProc, then this
  130. ** overrides the dwIncomingCallStatus established by a call to
  131. ** OleStdMsgFilter_SetInComingStatus. Using
  132. ** OleStdMsgFilter_SetInComingStatus allows the app to reject or
  133. ** accept ALL in coming calls. Using a HandleInComingCallbackProc
  134. ** allows the app to selectively handle or reject particular method
  135. ** calls.
  136. */
  137. STDAPI_(void) OleStdMsgFilter_SetInComingCallStatus(
  138. LPMESSAGEFILTER lpThis, DWORD dwInComingCallStatus)
  139. {
  140. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  141. if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
  142. lpStdMsgFilter->m_dwInComingCallStatus = dwInComingCallStatus;
  143. else
  144. OleDbgAssert(
  145. TEXT("OleStdMsgFilter_SetIncomingCallStatus: Invalid IMessageFilter*"));
  146. #if defined( _DEBUG )
  147. {
  148. TCHAR szBuf[80];
  149. TCHAR *szReturn;
  150. switch(dwInComingCallStatus) {
  151. case SERVERCALL_ISHANDLED:
  152. szReturn = TEXT("SERVERCALL_ISHANDLED");
  153. break;
  154. case SERVERCALL_REJECTED:
  155. szReturn = TEXT("SERVERCALL_REJECTED");
  156. break;
  157. case SERVERCALL_RETRYLATER:
  158. szReturn = TEXT("SERVERCALL_RETRYLATER");
  159. break;
  160. default:
  161. szReturn = TEXT("** ERROR: UNKNOWN **");
  162. break;
  163. }
  164. wsprintf(
  165. szBuf,
  166. TEXT("OleStdMsgFilter_SetInComingCallStatus: Status set to %s.\r\n"),
  167. (LPTSTR)szReturn
  168. );
  169. OleDbgOut3(szBuf);
  170. }
  171. #endif
  172. }
  173. /* OleStdMsgFilter_SetHandleInComingCallbackProc
  174. ** ---------------------------------------------
  175. ** This is a private function that allows the caller to install (or
  176. ** de-install) a special callback function to selectively
  177. ** handle/reject specific incoming method calls on particular
  178. ** interfaces.
  179. **
  180. ** if a HandleInComingCallbackProc is installed by a call to
  181. ** OleStdMsgFilter_SetHandleInComingCallbackProc, then this
  182. ** overrides the dwIncomingCallStatus established by a call to
  183. ** OleStdMsgFilter_SetInComingStatus. Using
  184. ** OleStdMsgFilter_SetInComingStatus allows the app to reject or
  185. ** accept ALL in coming calls. Using a HandleInComingCallbackProc
  186. ** allows the app to selectively handle or reject particular method
  187. ** calls.
  188. **
  189. ** to de-install the HandleInComingCallbackProc, call
  190. ** OleStdMsgFilter_SetHandleInComingCallbackProc(NULL);
  191. **
  192. ** Returns previous callback proc in effect.
  193. */
  194. STDAPI_(HANDLEINCOMINGCALLBACKPROC)
  195. OleStdMsgFilter_SetHandleInComingCallbackProc(
  196. LPMESSAGEFILTER lpThis,
  197. HANDLEINCOMINGCALLBACKPROC lpfnHandleInComingCallback)
  198. {
  199. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  200. HANDLEINCOMINGCALLBACKPROC lpfnPrevCallback =
  201. lpStdMsgFilter->m_lpfnHandleInComingCallback;
  202. if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER))) {
  203. lpStdMsgFilter->m_lpfnHandleInComingCallback =
  204. lpfnHandleInComingCallback;
  205. } else {
  206. OleDbgAssert(
  207. TEXT("OleStdMsgFilter_SetIncomingCallStatus: Invalid IMessageFilter*"));
  208. }
  209. #if defined( _DEBUG )
  210. {
  211. if (lpfnHandleInComingCallback)
  212. OleDbgOut3(
  213. TEXT("OleStdMsgFilter_SetHandleInComingCallbackProc SET\r\n"));
  214. else
  215. OleDbgOut3(
  216. TEXT("OleStdMsgFilter_SetHandleInComingCallbackProc CLEARED\r\n"));
  217. }
  218. #endif // _DEBUG
  219. return lpfnPrevCallback;
  220. }
  221. /* OleStdMsgFilter_GetInComingStatus
  222. ** ---------------------------------
  223. ** This is a private function that returns the current
  224. ** incoming call status. Can be used to disable/enable options
  225. ** in the calling application.
  226. **
  227. ** Returns: one of
  228. **
  229. ** SERVERCALL_ISHANDLED
  230. ** SERVERCALL_REJECTED
  231. ** SERVERCALL_RETRYLATER
  232. ** or -1 for ERROR
  233. **
  234. */
  235. STDAPI_(DWORD) OleStdMsgFilter_GetInComingCallStatus(
  236. LPMESSAGEFILTER lpThis)
  237. {
  238. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  239. DWORD dwReturn;
  240. if (!IsBadReadPtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
  241. dwReturn = lpStdMsgFilter->m_dwInComingCallStatus;
  242. else
  243. {
  244. OleDbgAssert(
  245. TEXT("OleStdMsgFilter_GetIncomingCallStatus: Invalid IMessageFilter*"));
  246. dwReturn = (DWORD)-1;
  247. }
  248. #if defined( _DEBUG )
  249. {
  250. TCHAR szBuf[80];
  251. TCHAR *szReturn;
  252. switch(dwReturn) {
  253. case SERVERCALL_ISHANDLED:
  254. szReturn = TEXT("SERVERCALL_ISHANDLED");
  255. break;
  256. case SERVERCALL_REJECTED:
  257. szReturn = TEXT("SERVERCALL_REJECTED");
  258. break;
  259. case SERVERCALL_RETRYLATER:
  260. szReturn = TEXT("SERVERCALL_RETRYLATER");
  261. break;
  262. default:
  263. szReturn = TEXT("-1");
  264. break;
  265. }
  266. wsprintf(
  267. szBuf,
  268. TEXT("OleStdMsgFilter_GetInComingCallStatus returns %s.\r\n"),
  269. (LPTSTR)szReturn
  270. );
  271. OleDbgOut3(szBuf);
  272. }
  273. #endif
  274. return dwReturn;
  275. }
  276. /* OleStdMsgFilter_EnableBusyDialog
  277. ** --------------------------------
  278. ** This function allows the caller to control whether
  279. ** the busy dialog is enabled. this is the dialog put up when
  280. ** IMessageFilter::RetryRejectedCall is called because the server
  281. ** responded SERVERCALL_RETRYLATER or SERVERCALL_REJECTED.
  282. **
  283. ** if the busy dialog is NOT enabled, then the rejected call is
  284. ** immediately canceled WITHOUT prompting the user. in this situation
  285. ** OleStdMsgFilter_RetryRejectedCall always retuns
  286. ** OLESTDCANCELRETRY canceling the outgoing LRPC call.
  287. ** If the busy dialog is enabled, then the user is given the choice
  288. ** of whether to retry, switch to, or cancel.
  289. **
  290. ** Returns previous dialog enable state
  291. */
  292. STDAPI_(BOOL) OleStdMsgFilter_EnableBusyDialog(
  293. LPMESSAGEFILTER lpThis, BOOL fEnable)
  294. {
  295. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  296. BOOL fPrevEnable = lpStdMsgFilter->m_fEnableBusyDialog;
  297. if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
  298. lpStdMsgFilter->m_fEnableBusyDialog = fEnable;
  299. else
  300. OleDbgAssert(
  301. TEXT("OleStdMsgFilter_EnableBusyDialog: Invalid IMessageFilter*"));
  302. #if defined( _DEBUG )
  303. {
  304. TCHAR szBuf[80];
  305. wsprintf(
  306. szBuf,
  307. TEXT("OleStdMsgFilter_EnableBusyDialog: Dialog is %s.\r\n"),
  308. fEnable ? (LPTSTR) TEXT("ENABLED") : (LPTSTR) TEXT("DISABLED")
  309. );
  310. OleDbgOut3(szBuf);
  311. }
  312. #endif
  313. return fPrevEnable;
  314. }
  315. /* OleStdMsgFilter_EnableNotRespondingDialog
  316. ** -----------------------------------------
  317. ** This function allows the caller to control whether
  318. ** the app "NotResponding" (Blocked) dialog is enabled. this is the
  319. ** dialog put up when IMessageFilter::MessagePending is called.
  320. ** If the NotResponding dialog is enabled, then the user is given
  321. ** the choice of whether to retry or switch to, but NOT to cancel.
  322. **
  323. ** Returns previous dialog enable state
  324. */
  325. STDAPI_(BOOL) OleStdMsgFilter_EnableNotRespondingDialog(
  326. LPMESSAGEFILTER lpThis, BOOL fEnable)
  327. {
  328. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  329. BOOL fPrevEnable = lpStdMsgFilter->m_fEnableNotRespondingDialog;
  330. if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER)))
  331. lpStdMsgFilter->m_fEnableNotRespondingDialog = fEnable;
  332. else
  333. OleDbgAssert(
  334. TEXT("OleStdMsgFilter_EnableNotRespondingDialog: Invalid IMessageFilter*"));
  335. #if defined( _DEBUG )
  336. {
  337. TCHAR szBuf[80];
  338. wsprintf(
  339. szBuf,
  340. TEXT("OleStdMsgFilter_EnableNotRespondingDialog: Dialog is %s.\r\n"),
  341. fEnable ? (LPTSTR) TEXT("ENABLED") : (LPTSTR) TEXT("DISABLED")
  342. );
  343. OleDbgOut3(szBuf);
  344. }
  345. #endif
  346. return fPrevEnable;
  347. }
  348. /* OleStdMsgFilter_SetParentWindow
  349. ** -------------------------------
  350. ** This function allows caller to set which window will be used as
  351. ** the parent for the busy dialog.
  352. **
  353. ** OLE2NOTE: it would be inportant for an in-place active server to
  354. ** reset this to its current in-place frame window when in-place
  355. ** activated. if the hWndParent is set to NULL then the dialogs will
  356. ** be parented to the desktop.
  357. **
  358. ** Returns: previous parent window
  359. */
  360. STDAPI_(HWND) OleStdMsgFilter_SetParentWindow(
  361. LPMESSAGEFILTER lpThis, HWND hWndParent)
  362. {
  363. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  364. HWND hWndPrev = lpStdMsgFilter->m_hWndParent;
  365. lpStdMsgFilter->m_hWndParent = hWndParent;
  366. return hWndPrev;
  367. }
  368. STDMETHODIMP OleStdMsgFilter_QueryInterface(
  369. LPMESSAGEFILTER lpThis, REFIID riid, LPVOID FAR* ppvObj)
  370. {
  371. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  372. SCODE scode;
  373. /* Two interfaces supported: IUnknown, IMessageFilter
  374. */
  375. if (IsEqualIID(riid, &IID_IMessageFilter) || IsEqualIID(riid, &IID_IUnknown)) {
  376. lpStdMsgFilter->m_cRef++; // A pointer to this object is returned
  377. *ppvObj = lpThis;
  378. scode = S_OK;
  379. }
  380. else { // unsupported interface
  381. *ppvObj = NULL;
  382. scode = E_NOINTERFACE;
  383. }
  384. return ResultFromScode(scode);
  385. }
  386. STDMETHODIMP_(ULONG) OleStdMsgFilter_AddRef(LPMESSAGEFILTER lpThis)
  387. {
  388. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  389. return ++lpStdMsgFilter->m_cRef;
  390. }
  391. STDMETHODIMP_(ULONG) OleStdMsgFilter_Release(LPMESSAGEFILTER lpThis)
  392. {
  393. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  394. LPMALLOC lpMalloc;
  395. if (--lpStdMsgFilter->m_cRef != 0) // Still used by others
  396. return lpStdMsgFilter->m_cRef;
  397. // Free storage
  398. if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)
  399. return (ULONG)0;
  400. lpMalloc->lpVtbl->Free(lpMalloc, lpStdMsgFilter);
  401. lpMalloc->lpVtbl->Release(lpMalloc);
  402. return (ULONG)0;
  403. }
  404. STDMETHODIMP_(DWORD) OleStdMsgFilter_HandleInComingCall (
  405. LPMESSAGEFILTER lpThis,
  406. DWORD dwCallType,
  407. HTASK htaskCaller,
  408. DWORD dwTickCount,
  409. #ifdef WIN32
  410. LPINTERFACEINFO dwReserved
  411. #else
  412. DWORD dwReserved
  413. #endif
  414. )
  415. {
  416. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  417. /* if a HandleInComingCallbackProc is in effect, then this
  418. ** overrides dwIncomingCallStatus established by a call to
  419. ** OleStdMsgFilter_SetInComingStatus. we will call this
  420. ** callback to allow the app to selectively handle or reject
  421. ** incoming method calls. the LPINTERFACEINFO parameter
  422. ** describes which method is being called.
  423. */
  424. if (lpStdMsgFilter->m_lpfnHandleInComingCallback &&
  425. !IsBadCodePtr((FARPROC)lpStdMsgFilter->m_lpfnHandleInComingCallback)){
  426. return lpStdMsgFilter->m_lpfnHandleInComingCallback(
  427. dwCallType,
  428. htaskCaller,
  429. dwTickCount,
  430. dwReserved
  431. );
  432. }
  433. switch (dwCallType) {
  434. case CALLTYPE_TOPLEVEL:
  435. /* OLE2NOTE: we currently have NO pending outgoing call and
  436. ** there is a new toplevel incoming call.
  437. ** this call may be rejected.
  438. */
  439. return lpStdMsgFilter->m_dwInComingCallStatus;
  440. case CALLTYPE_TOPLEVEL_CALLPENDING:
  441. /* OLE2NOTE: we currently HAVE a pending outgoing call and
  442. ** there is a new toplevel incoming call.
  443. ** this call may be rejected.
  444. */
  445. return lpStdMsgFilter->m_dwInComingCallStatus;
  446. case CALLTYPE_NESTED:
  447. /* OLE2NOTE: we currently HAVE a pending outgoing call and
  448. ** there callback on behalf of the previous outgoing
  449. ** call. this type of call should ALWAYS be handled.
  450. */
  451. return SERVERCALL_ISHANDLED;
  452. case CALLTYPE_ASYNC:
  453. /* OLE2NOTE: we currently have NO pending outgoing call and
  454. ** there is a new asyncronis incoming call.
  455. ** this call can NEVER be rejected. OLE actually ignores
  456. ** the return code in this case and always allows the
  457. ** call through.
  458. */
  459. return SERVERCALL_ISHANDLED; // value returned does not matter
  460. case CALLTYPE_ASYNC_CALLPENDING:
  461. /* OLE2NOTE: we currently HAVE a pending outgoing call and
  462. ** there is a new asyncronis incoming call.
  463. ** this call can NEVER be rejected. OLE ignore the
  464. ** return code in this case.
  465. */
  466. return SERVERCALL_ISHANDLED; // value returned does not
  467. default:
  468. OleDbgAssert(
  469. TEXT("OleStdMsgFilter_HandleInComingCall: Invalid CALLTYPE"));
  470. return lpStdMsgFilter->m_dwInComingCallStatus;
  471. }
  472. }
  473. STDMETHODIMP_(DWORD) OleStdMsgFilter_RetryRejectedCall (
  474. LPMESSAGEFILTER lpThis,
  475. HTASK htaskCallee,
  476. DWORD dwTickCount,
  477. DWORD dwRejectType
  478. )
  479. {
  480. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  481. DWORD dwRet = 0;
  482. UINT uRet;
  483. #if defined( _DEBUG )
  484. TCHAR szBuf[80];
  485. #endif
  486. OLEDBG_BEGIN2(TEXT("OleStdMsgFilter_RetryRejectedCall\r\n"))
  487. /* OLE2NOTE: we should only put up the application busy dialog when
  488. ** the callee has responded SERVERCALL_RETRYLATER. if the
  489. ** dwRejectType is SERVERCALL_REJECTED then there is something
  490. ** seriously wrong with the callee (perhaps a severe low memory
  491. ** situation). we don't want to even try to "Switch To" this app
  492. ** or even try to "Retry".
  493. */
  494. if (dwRejectType == SERVERCALL_RETRYLATER &&
  495. lpStdMsgFilter->m_fEnableBusyDialog) {
  496. OLEUIBUSY bz;
  497. /* OLE2NOTE: we do not want to put up the Busy dialog immediately
  498. ** the when an app says RETRYLATER. we should continue retrying
  499. ** for a while in case the app can un-busy itself in a
  500. ** reasonable amount of time.
  501. */
  502. if (dwTickCount <= (DWORD)OLESTDRETRYDELAY) {
  503. dwRet = 500; // Retry after .5 sec
  504. OLEDBG_END2
  505. return dwRet;
  506. }
  507. /*
  508. ** Set up structure for calling OLEUIBUSY dialog
  509. */
  510. bz.cbStruct = sizeof(OLEUIBUSY);
  511. bz.dwFlags = 0L;
  512. bz.hWndOwner =GetTopWindowInWindowsTask(lpStdMsgFilter->m_hWndParent);
  513. bz.lpszCaption = lpStdMsgFilter->m_lpszAppName;
  514. bz.lpfnHook = lpStdMsgFilter->m_lpfnBusyDialogHookCallback;
  515. bz.lCustData = 0;
  516. bz.hInstance = NULL;
  517. bz.lpszTemplate = NULL;
  518. bz.hResource = 0;
  519. bz.hTask = htaskCallee;
  520. bz.lphWndDialog = NULL; // We don't need the hDlg for this call
  521. uRet = OleUIBusy(&bz);
  522. switch (uRet) {
  523. case OLEUI_BZ_RETRYSELECTED:
  524. dwRet = 0; // Retry immediately
  525. break;
  526. case OLEUI_CANCEL:
  527. dwRet = OLESTDCANCELRETRY; // Cancel pending outgoing call
  528. break;
  529. case OLEUI_BZERR_HTASKINVALID:
  530. // Htask was invalid, return OLESTDRETRYDELAY anyway
  531. dwRet = OLESTDRETRYDELAY; // Retry after <retry delay> msec
  532. #if defined( _DEBUG )
  533. wsprintf(
  534. szBuf,
  535. TEXT("OleStdMsgFilter_RetryRejectedCall, HTASK 0x%x invalid\r\n"),
  536. htaskCallee
  537. );
  538. OleDbgOut3(szBuf);
  539. #endif
  540. break;
  541. }
  542. } else {
  543. dwRet = OLESTDCANCELRETRY; // Cancel pending outgoing call
  544. }
  545. #if defined( _DEBUG )
  546. wsprintf(szBuf,
  547. TEXT("OleStdMsgFilter_RetryRejectedCall returns %d\r\n"),
  548. dwRet);
  549. OleDbgOut3(szBuf);
  550. #endif
  551. OLEDBG_END2
  552. return dwRet;
  553. }
  554. /* a significant message is consider a mouse click or keyboard input. */
  555. #define IS_SIGNIFICANT_MSG(lpmsg) \
  556. ( \
  557. (PeekMessage((lpmsg), NULL, WM_LBUTTONDOWN, WM_LBUTTONDOWN, \
  558. PM_NOREMOVE | PM_NOYIELD)) \
  559. || (PeekMessage((lpmsg), NULL, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, \
  560. PM_NOREMOVE | PM_NOYIELD)) \
  561. || (PeekMessage((lpmsg), NULL, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, \
  562. PM_NOREMOVE | PM_NOYIELD)) \
  563. || (PeekMessage((lpmsg), NULL, WM_NCLBUTTONDBLCLK, WM_NCLBUTTONDBLCLK, \
  564. PM_NOREMOVE | PM_NOYIELD)) \
  565. || (PeekMessage((lpmsg), NULL, WM_KEYDOWN, WM_KEYDOWN, \
  566. PM_NOREMOVE | PM_NOYIELD)) \
  567. || (PeekMessage((lpmsg), NULL, WM_SYSKEYDOWN, WM_SYSKEYDOWN, \
  568. PM_NOREMOVE | PM_NOYIELD)) \
  569. )
  570. STDMETHODIMP_(DWORD) OleStdMsgFilter_MessagePending (
  571. LPMESSAGEFILTER lpThis,
  572. HTASK htaskCallee,
  573. DWORD dwTickCount,
  574. DWORD dwPendingType
  575. )
  576. {
  577. LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;
  578. DWORD dwReturn = PENDINGMSG_WAITDEFPROCESS;
  579. MSG msg;
  580. BOOL fIsSignificantMsg = IS_SIGNIFICANT_MSG(&msg);
  581. UINT uRet;
  582. #if defined( _DEBUG )
  583. TCHAR szBuf[128];
  584. wsprintf(
  585. szBuf,
  586. TEXT("OleStdMsgFilter_MessagePending, dwTickCount = 0x%lX\r\n"),
  587. (DWORD)dwTickCount
  588. );
  589. OleDbgOut4(szBuf);
  590. #endif
  591. /* OLE2NOTE: If our tick count for this call exceeds our standard retry
  592. ** delay, then we need to put up the dialog. We will only
  593. ** consider putting up the dialog if the user has issued a
  594. ** "significant" event (ie. mouse click or keyboard event). a
  595. ** simple mouse move should NOT trigger this dialog.
  596. ** Since our call to
  597. ** OleUIBusy below enters a DialogBox() message loop, there's a
  598. ** possibility that another call will be initiated during the dialog,
  599. ** and this procedure will be re-entered. Just so we don't put up
  600. ** two dialogs at a time, we use the m_bUnblocking varable
  601. ** to keep track of this situation.
  602. */
  603. if (dwTickCount > (DWORD)OLESTDRETRYDELAY && fIsSignificantMsg
  604. && !lpStdMsgFilter->m_bUnblocking)
  605. {
  606. if (lpStdMsgFilter->m_fEnableNotRespondingDialog)
  607. {
  608. OLEUIBUSY bz;
  609. lpStdMsgFilter->m_bUnblocking = TRUE;
  610. // Eat messages in our queue that we do NOT want to be dispatched
  611. while (PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE, PM_REMOVE | PM_NOYIELD));
  612. /* Set up structure for calling OLEUIBUSY dialog,
  613. ** using the "not responding" variety
  614. */
  615. bz.cbStruct = sizeof(OLEUIBUSY);
  616. bz.dwFlags = BZ_NOTRESPONDINGDIALOG;
  617. bz.hWndOwner =GetTopWindowInWindowsTask(lpStdMsgFilter->m_hWndParent);
  618. bz.lpszCaption = lpStdMsgFilter->m_lpszAppName;
  619. bz.lpfnHook = lpStdMsgFilter->m_lpfnBusyDialogHookCallback;
  620. bz.lCustData = 0;
  621. bz.hInstance = NULL;
  622. bz.lpszTemplate = NULL;
  623. bz.hResource = 0;
  624. bz.hTask = htaskCallee;
  625. /* Set up the address to the hWnd in our MsgFilter structure. The
  626. ** call to OleUIBusy will fill this in with the hWnd of the busy
  627. ** dialog box
  628. */
  629. bz.lphWndDialog = (HWND FAR *)&(lpStdMsgFilter->m_hWndBusyDialog);
  630. uRet = OleUIBusy(&bz);
  631. lpStdMsgFilter->m_bUnblocking = FALSE;
  632. return PENDINGMSG_WAITNOPROCESS;
  633. }
  634. #if defined( _DEBUG )
  635. else {
  636. OleDbgOut3(TEXT("OleStdMsgFilter_MessagePending: BLOCKED but dialog Disabled\r\n"));
  637. }
  638. #endif
  639. }
  640. /* If we're already unblocking, we're being re-entered. Don't
  641. ** process message
  642. */
  643. if (lpStdMsgFilter->m_bUnblocking)
  644. return PENDINGMSG_WAITDEFPROCESS;
  645. /* OLE2NOTE: If we have a callback function set up, call it with the
  646. ** current message. If not, tell OLE LPRC mechanism to automatically
  647. ** handle all messages.
  648. */
  649. if (lpStdMsgFilter->m_lpfnMessagePendingCallback &&
  650. !IsBadCodePtr((FARPROC)lpStdMsgFilter->m_lpfnMessagePendingCallback)){
  651. MSG msg;
  652. /* OLE2NOTE: the app provided a MessagePendingCallback
  653. ** function. we will PeekMessage for the first message in
  654. ** the queue and pass it to the app. the app in its callback
  655. ** function can decide to Dispatch this message or it can
  656. ** PeekMessage on its own giving particular message filter
  657. ** criteria. if the app returns TRUE then we return
  658. ** PENDINGMSG_WAITNOPROCESS to OLE telling OLE to leave the
  659. ** message in the queue. If the app returns FALSE, then we
  660. ** return PENDINGMSG_WAITDEFPROCESS to OLE telling OLE to do
  661. ** its default processing with the message. by default OLE
  662. ** dispatches system messages and eats other messages and
  663. ** beeps.
  664. */
  665. if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD)) {
  666. if (lpStdMsgFilter->m_lpfnMessagePendingCallback(&msg)) {
  667. /* TRUE return means that the app processed message.
  668. **
  669. ** NOTE: (CHANGE FROM OLE2.0 VERSION) we leave it up to
  670. ** the callback routine to remove the message if it
  671. ** wants.
  672. */
  673. dwReturn = PENDINGMSG_WAITNOPROCESS;
  674. } else {
  675. /* FALSE means that the app did not process the
  676. ** message. we will let OLE take its
  677. ** default action.
  678. **
  679. ** NOTE: (CHANGE FROM OLE2.0 VERSION) we used to return
  680. ** PENDINGMSG_WAITNOPROCESS to leave the message in
  681. ** the queue; now we return PENDINGMSG_WAITDEFPROCESS
  682. ** to let OLE do default processing.
  683. */
  684. dwReturn = PENDINGMSG_WAITDEFPROCESS;
  685. #if defined( _DEBUG )
  686. wsprintf(
  687. szBuf,
  688. TEXT("Message (0x%x) (wParam=0x%x, lParam=0x%lx) using WAITDEFPROCESS while blocked\r\n"),
  689. msg.message,
  690. msg.lParam,
  691. msg.wParam
  692. );
  693. OleDbgOut2(szBuf);
  694. #endif // _DEBUG
  695. }
  696. }
  697. }
  698. return dwReturn;
  699. }