422 lines
15 KiB
C++
422 lines
15 KiB
C++
/*
|
|
* BUSY.CPP
|
|
*
|
|
* Implements the OleUIBusy function which invokes the "Server Busy"
|
|
* dialog.
|
|
*
|
|
* Copyright (c)1992 Microsoft Corporation, All Right Reserved
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "utility.h"
|
|
|
|
OLEDBGDATA
|
|
|
|
// Internally used structure
|
|
typedef struct tagBUSY
|
|
{
|
|
// Keep these items first as the Standard* functions depend on it here.
|
|
LPOLEUIBUSY lpOBZ; // Original structure passed.
|
|
UINT nIDD; // IDD of dialog (used for help info)
|
|
|
|
/*
|
|
* What we store extra in this structure besides the original caller's
|
|
* pointer are those fields that we need to modify during the life of
|
|
* the dialog or that we don't want to change in the original structure
|
|
* until the user presses OK.
|
|
*/
|
|
DWORD dwFlags; // Flags passed in
|
|
HWND hWndBlocked; // HWND of app which is blocking
|
|
|
|
} BUSY, *PBUSY, FAR *LPBUSY;
|
|
|
|
// Internal function prototypes
|
|
// BUSY.CPP
|
|
|
|
INT_PTR CALLBACK BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
|
|
BOOL GetTaskInfo(HWND hWnd, HTASK htask, LPTSTR* lplpszWindowName, HWND* lphWnd);
|
|
void BuildBusyDialogString(HWND, DWORD, int, LPTSTR);
|
|
BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam);
|
|
void MakeWindowActive(HWND hWndSwitchTo);
|
|
|
|
/*
|
|
* OleUIBusy
|
|
*
|
|
* Purpose:
|
|
* Invokes the standard OLE "Server Busy" dialog box which
|
|
* notifies the user that the server application is not receiving
|
|
* messages. The dialog then asks the user to either cancel
|
|
* the operation, switch to the task which is blocked, or continue
|
|
* waiting.
|
|
*
|
|
* Parameters:
|
|
* lpBZ LPOLEUIBUSY pointing to the in-out structure
|
|
* for this dialog.
|
|
*
|
|
* Return Value:
|
|
* OLEUI_BZERR_HTASKINVALID : Error
|
|
* OLEUI_BZ_SWITCHTOSELECTED : Success, user selected "switch to"
|
|
* OLEUI_BZ_RETRYSELECTED : Success, user selected "retry"
|
|
* OLEUI_CANCEL : Success, user selected "cancel"
|
|
*/
|
|
STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY lpOBZ)
|
|
{
|
|
HGLOBAL hMemDlg = NULL;
|
|
UINT uRet = UStandardValidation((LPOLEUISTANDARD)lpOBZ, sizeof(OLEUIBUSY),
|
|
&hMemDlg);
|
|
|
|
// Error out if the standard validation failed
|
|
if (OLEUI_SUCCESS != uRet)
|
|
return uRet;
|
|
|
|
// Error out if our secondary validation failed
|
|
if (OLEUI_ERR_STANDARDMIN <= uRet)
|
|
{
|
|
return uRet;
|
|
}
|
|
|
|
// Invoke the dialog.
|
|
uRet = UStandardInvocation(BusyDialogProc, (LPOLEUISTANDARD)lpOBZ,
|
|
hMemDlg, MAKEINTRESOURCE(IDD_BUSY));
|
|
return uRet;
|
|
}
|
|
|
|
/*
|
|
* BusyDialogProc
|
|
*
|
|
* Purpose:
|
|
* Implements the OLE Busy dialog as invoked through the OleUIBusy function.
|
|
*
|
|
* Parameters:
|
|
* Standard
|
|
*
|
|
* Return Value:
|
|
* Standard
|
|
*
|
|
*/
|
|
INT_PTR CALLBACK BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Declare Win16/Win32 compatible WM_COMMAND parameters.
|
|
COMMANDPARAMS(wID, wCode, hWndMsg);
|
|
|
|
// This will fail under WM_INITDIALOG, where we allocate it.
|
|
UINT uRet = 0;
|
|
LPBUSY lpBZ = (LPBUSY)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);
|
|
|
|
// If the hook processed the message, we're done.
|
|
if (0 != uRet)
|
|
return (INT_PTR)uRet;
|
|
|
|
// Process the temination message
|
|
if (iMsg == uMsgEndDialog)
|
|
{
|
|
EndDialog(hDlg, wParam);
|
|
return TRUE;
|
|
}
|
|
|
|
// Process our special "close" message. If we get this message,
|
|
// this means that the call got unblocked, so we need to
|
|
// return OLEUI_BZ_CALLUNBLOCKED to our calling app.
|
|
if (iMsg == uMsgCloseBusyDlg)
|
|
{
|
|
SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_CALLUNBLOCKED, 0L);
|
|
return TRUE;
|
|
}
|
|
|
|
switch (iMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
if (lpBZ)
|
|
{
|
|
StandardCleanup(lpBZ, hDlg);
|
|
}
|
|
break;
|
|
case WM_INITDIALOG:
|
|
FBusyInit(hDlg, wParam, lParam);
|
|
return TRUE;
|
|
|
|
case WM_ACTIVATEAPP:
|
|
{
|
|
/* try to bring down our Busy/NotResponding dialog as if
|
|
** the user entered RETRY.
|
|
*/
|
|
BOOL fActive = (BOOL)wParam;
|
|
if (fActive)
|
|
{
|
|
// If this is the app BUSY case, then bring down our
|
|
// dialog when switching BACK to our app
|
|
if (lpBZ && !(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
|
|
SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);
|
|
}
|
|
else
|
|
{
|
|
// If this is the app NOT RESPONDING case, then bring down
|
|
// our dialog when switching AWAY to another app
|
|
if (lpBZ && (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
|
|
SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch (wID)
|
|
{
|
|
case IDC_BZ_SWITCHTO:
|
|
{
|
|
BOOL fNotRespondingDlg =
|
|
(BOOL)(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG);
|
|
HWND hwndTaskList = hDlg;
|
|
|
|
// If this is the app not responding case, then we want
|
|
// to bring down the dialog when "SwitchTo" is selected.
|
|
// If the app is busy (RetryRejectedCall situation) then
|
|
// we do NOT want to bring down the dialog. this is
|
|
// the OLE2.0 user model design.
|
|
if (fNotRespondingDlg)
|
|
{
|
|
hwndTaskList = GetParent(hDlg);
|
|
if (hwndTaskList == NULL)
|
|
hwndTaskList = GetDesktopWindow();
|
|
PostMessage(hDlg, uMsgEndDialog,
|
|
OLEUI_BZ_SWITCHTOSELECTED, 0L);
|
|
}
|
|
|
|
// If user selects "Switch To...", switch activation
|
|
// directly to the window which is causing the problem.
|
|
if (IsWindow(lpBZ->hWndBlocked))
|
|
MakeWindowActive(lpBZ->hWndBlocked);
|
|
else
|
|
PostMessage(hwndTaskList, WM_SYSCOMMAND, SC_TASKLIST, 0);
|
|
}
|
|
break;
|
|
|
|
case IDC_BZ_RETRY:
|
|
SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_RETRYSELECTED, 0L);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* FBusyInit
|
|
*
|
|
* Purpose:
|
|
* WM_INITIDIALOG handler for the Busy dialog box.
|
|
*
|
|
* Parameters:
|
|
* hDlg HWND of the dialog
|
|
* wParam WPARAM of the message
|
|
* lParam LPARAM of the message
|
|
*
|
|
* Return Value:
|
|
* BOOL Value to return for WM_INITDIALOG.
|
|
*/
|
|
BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HFONT hFont;
|
|
LPBUSY lpBZ = (LPBUSY)LpvStandardInit(hDlg, sizeof(BUSY), &hFont);
|
|
|
|
// PvStandardInit sent a termination to us already.
|
|
if (NULL == lpBZ)
|
|
return FALSE;
|
|
|
|
// Our original structure is in lParam
|
|
LPOLEUIBUSY lpOBZ = (LPOLEUIBUSY)lParam;
|
|
|
|
// Copy it to our instance of the structure (in lpBZ)
|
|
lpBZ->lpOBZ = lpOBZ;
|
|
lpBZ->nIDD = IDD_BUSY;
|
|
|
|
//Copy other information from lpOBZ that we might modify.
|
|
lpBZ->dwFlags = lpOBZ->dwFlags;
|
|
|
|
// Set default information
|
|
lpBZ->hWndBlocked = NULL;
|
|
|
|
// Insert HWND of our dialog into the address pointed to by
|
|
// lphWndDialog. This can be used by the app who called
|
|
// OleUIBusy to bring down the dialog with uMsgCloseBusyDialog
|
|
if (lpOBZ->lphWndDialog &&
|
|
!IsBadWritePtr(lpOBZ->lphWndDialog, sizeof(HWND)))
|
|
{
|
|
*lpOBZ->lphWndDialog = hDlg;
|
|
}
|
|
|
|
// Update text in text box --
|
|
// GetTaskInfo will return two pointers, one to the task name
|
|
// (file name) and one to the window name. We need to call
|
|
// OleStdFree on these when we're done with them. We also
|
|
// get the HWND which is blocked in this call
|
|
//
|
|
// In the case where this call fails, a default message should already
|
|
// be present in the dialog template, so no action is needed
|
|
|
|
LPTSTR lpWindowName;
|
|
if (GetTaskInfo(hDlg, lpOBZ->hTask, &lpWindowName, &lpBZ->hWndBlocked))
|
|
{
|
|
// Build string to present to user, place in IDC_BZ_MESSAGE1 control
|
|
BuildBusyDialogString(hDlg, lpBZ->dwFlags, IDC_BZ_MESSAGE1, lpWindowName);
|
|
OleStdFree(lpWindowName);
|
|
}
|
|
|
|
// Update icon with the system "exclamation" icon
|
|
HICON hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
|
|
SendDlgItemMessage(hDlg, IDC_BZ_ICON, STM_SETICON, (WPARAM)hIcon, 0L);
|
|
|
|
// Disable/Enable controls
|
|
if ((lpBZ->dwFlags & BZ_DISABLECANCELBUTTON) ||
|
|
(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))
|
|
{
|
|
// Disable cancel for "not responding" dialog
|
|
StandardEnableDlgItem(hDlg, IDCANCEL, FALSE);
|
|
}
|
|
|
|
if (lpBZ->dwFlags & BZ_DISABLESWITCHTOBUTTON)
|
|
StandardEnableDlgItem(hDlg, IDC_BZ_SWITCHTO, FALSE);
|
|
|
|
if (lpBZ->dwFlags & BZ_DISABLERETRYBUTTON)
|
|
StandardEnableDlgItem(hDlg, IDC_BZ_RETRY, FALSE);
|
|
|
|
// Call the hook with lCustData in lParam
|
|
UStandardHook((LPVOID)lpBZ, hDlg, WM_INITDIALOG, wParam, lpOBZ->lCustData);
|
|
|
|
// Update caption if lpszCaption was specified
|
|
if (lpBZ->lpOBZ->lpszCaption && !IsBadReadPtr(lpBZ->lpOBZ->lpszCaption, 1))
|
|
{
|
|
SetWindowText(hDlg, lpBZ->lpOBZ->lpszCaption);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* BuildBusyDialogString
|
|
*
|
|
* Purpose:
|
|
* Builds the string that will be displayed in the dialog from the
|
|
* task name and window name parameters.
|
|
*
|
|
* Parameters:
|
|
* hDlg HWND of the dialog
|
|
* dwFlags DWORD containing flags passed into dialog
|
|
* iControl Control ID to place the text string
|
|
* lpTaskName LPSTR pointing to name of task (e.g. C:\TEST\TEST.EXE)
|
|
* lpWindowName LPSTR for name of window
|
|
*
|
|
* Caveats:
|
|
* The caller of this function MUST de-allocate the lpTaskName and
|
|
* lpWindowName pointers itself with OleStdFree
|
|
*
|
|
* Return Value:
|
|
* void
|
|
*/
|
|
void BuildBusyDialogString(
|
|
HWND hDlg, DWORD dwFlags, int iControl, LPTSTR lpWindowName)
|
|
{
|
|
// Load the format string out of stringtable, choose a different
|
|
// string depending on what flags are passed in to the dialog
|
|
UINT uiStringNum;
|
|
if (dwFlags & BZ_NOTRESPONDINGDIALOG)
|
|
uiStringNum = IDS_BZRESULTTEXTNOTRESPONDING;
|
|
else
|
|
uiStringNum = IDS_BZRESULTTEXTBUSY;
|
|
|
|
TCHAR szFormat[256];
|
|
if (LoadString(_g_hOleStdResInst, uiStringNum, szFormat, 256) == 0)
|
|
return;
|
|
|
|
// Build the string. The format string looks like this:
|
|
// "This action cannot be completed because the "%1" application
|
|
// is [busy | not responding]. Choose \"Switch To\" to correct the
|
|
// problem."
|
|
|
|
TCHAR szMessage[512];
|
|
FormatString1(szMessage, szFormat, lpWindowName);
|
|
SetDlgItemText(hDlg, iControl, szMessage);
|
|
}
|
|
|
|
/*
|
|
* GetTaskInfo()
|
|
*
|
|
* Purpose: Gets information about the specified task and places the
|
|
* module name, window name and top-level HWND for the task in the specified
|
|
* pointers
|
|
*
|
|
* NOTE: The two string pointers allocated in this routine are
|
|
* the responsibility of the CALLER to de-allocate.
|
|
*
|
|
* Parameters:
|
|
* hWnd HWND who called this function
|
|
* htask HTASK which we want to find out more info about
|
|
* lplpszTaskName Location that the module name is returned
|
|
* lplpszWindowName Location where the window name is returned
|
|
*
|
|
*/
|
|
BOOL GetTaskInfo(
|
|
HWND hWnd, HTASK htask, LPTSTR* lplpszWindowName, HWND* lphWnd)
|
|
{
|
|
if (htask == NULL)
|
|
return FALSE;
|
|
|
|
// initialize 'out' parameters
|
|
*lplpszWindowName = NULL;
|
|
|
|
// Now, enumerate top-level windows in system
|
|
HWND hwndNext = GetWindow(hWnd, GW_HWNDFIRST);
|
|
while (hwndNext)
|
|
{
|
|
// See if we can find a non-owned top level window whose
|
|
// hInstance matches the one we just got passed. If we find one,
|
|
// we can be fairly certain that this is the top-level window for
|
|
// the task which is blocked.
|
|
DWORD dwProcessID;
|
|
DWORD dwThreadID = GetWindowThreadProcessId(hwndNext, &dwProcessID);
|
|
if ((hwndNext != hWnd) &&
|
|
(dwThreadID == HandleToUlong(htask)) &&
|
|
(IsWindowVisible(hwndNext)) && !GetWindow(hwndNext, GW_OWNER))
|
|
{
|
|
// We found our window! Alloc space for new strings
|
|
LPTSTR lpszWN;
|
|
if ((lpszWN = (LPTSTR)OleStdMalloc(MAX_PATH_SIZE)) == NULL)
|
|
break;
|
|
|
|
// We found the window we were looking for, copy info to
|
|
// local vars
|
|
GetWindowText(hwndNext, lpszWN, MAX_PATH);
|
|
|
|
// Note: the task name cannot be retrieved with the Win32 API.
|
|
|
|
// everything was successful. Set string pointers to point to our data.
|
|
*lplpszWindowName = lpszWN;
|
|
*lphWnd = hwndNext;
|
|
return TRUE;
|
|
}
|
|
hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* MakeWindowActive()
|
|
*
|
|
* Purpose: Makes specified window the active window.
|
|
*
|
|
*/
|
|
void MakeWindowActive(HWND hWndSwitchTo)
|
|
{
|
|
// If it's iconic, we need to restore it.
|
|
if (IsIconic(hWndSwitchTo))
|
|
ShowWindow(hWndSwitchTo, SW_RESTORE);
|
|
|
|
// Move the new window to the top of the Z-order
|
|
SetForegroundWindow(GetLastActivePopup(hWndSwitchTo));
|
|
}
|