///////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1998 Active Voice Corporation. All Rights Reserved. // // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation. // // Other brand and product names used herein are trademarks of their respective owners. // // The entire program and user interface including the structure, sequence, selection, // and arrangement of the dialog, the exclusively "yes" and "no" choices represented // by "1" and "2," and each dialog message are protected by copyrights registered in // the United States and by international treaties. // // Protected by one or more of the following United States patents: 5,070,526, 5,488,650, // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054. // // Active Voice Corporation // Seattle, Washington // USA // ///////////////////////////////////////////////////////////////////////////////////////// //// // nbox.c - notify box functions //// #include "winlocal.h" #include #include "nbox.h" #include "escbutt.h" #include "gfx.h" #include "mem.h" #include "str.h" #include "trace.h" #include "wnd.h" //// // private definitions //// #define NBOXCLASS TEXT("NBoxClass") #define NBOXMAXCOLUMNS 60 #define NBOXMAXROWS 20 // nbox control struct // typedef struct NBOX { DWORD dwVersion; HINSTANCE hInst; HTASK hTask; LPTSTR lpszText; DWORD dwFlags; HWND hwndNBox; BOOL fVisible; HWND hwndCancel; BOOL fCancelled; HWND hwndFocusOld; HCURSOR hCursorOld; } NBOX, FAR *LPNBOX; // helper functions // LRESULT DLLEXPORT CALLBACK NBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static BOOL NBoxOnNCCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct); static void NBoxOnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); static void NBoxOnPaint(HWND hwnd); static LPNBOX NBoxGetPtr(HNBOX hNBox); static HNBOX NBoxGetHandle(LPNBOX lpNBox); //// // public functions //// // NBoxCreate - notify box constructor // (i) must be NBOX_VERSION // (i) instance handle of calling module // (i) window which will own the notify box // NULL desktop window // (i) message to be displayed // (i) notify box caption // NULL no caption // (i) pushbutton text, if NB_CANCEL specified // NULL use default text ("Cancel") // (i) control flags // NB_CANCEL notify box includes Cancel pushbutton // NB_TASKMODAL disable parent task's top-level windows // NB_HOURGLASS show hourglass cursor while notify box visible // return notify box handle (NULL if error) // // NOTE: NBoxCreate creates the window but does not show it. // See NBoxShow and NBoxHide. // The size of the notify box is determined by the number of // lines in , and the length of the longest line. // HNBOX DLLEXPORT WINAPI NBoxCreate(DWORD dwVersion, HINSTANCE hInst, HWND hwndParent, LPCTSTR lpszText, LPCTSTR lpszTitle, LPCTSTR lpszButtonText, DWORD dwFlags) { BOOL fSuccess = TRUE; LPNBOX lpNBox = NULL; WNDCLASS wc; int nRows; int nColumns; int cxChar; int cyChar; if (dwVersion != NBOX_VERSION) fSuccess = TraceFALSE(NULL); else if (hInst == NULL) fSuccess = TraceFALSE(NULL); else if (lpszText == NULL) fSuccess = TraceFALSE(NULL); else if ((lpNBox = (LPNBOX) MemAlloc(NULL, sizeof(NBOX), 0)) == NULL) fSuccess = TraceFALSE(NULL); else { lpNBox->dwVersion = dwVersion; lpNBox->hInst = hInst; lpNBox->hTask = GetCurrentTask(); lpNBox->lpszText = NULL; lpNBox->dwFlags = dwFlags; lpNBox->hwndNBox = NULL; lpNBox->fVisible = FALSE; lpNBox->hwndCancel = NULL; lpNBox->fCancelled = FALSE; lpNBox->hwndFocusOld = NULL; lpNBox->hCursorOld = NULL; if (hwndParent == NULL) hwndParent = GetDesktopWindow(); if ((lpNBox->lpszText = StrDup(lpszText)) == NULL) fSuccess = TraceFALSE(NULL); } // register notify box class unless it has been already // if (fSuccess && GetClassInfo(lpNBox->hInst, NBOXCLASS, &wc) == 0) { wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = (HICON) NULL; wc.lpszMenuName = NULL; wc.hInstance = lpNBox->hInst; wc.lpszClassName = NBOXCLASS; wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wc.lpfnWndProc = NBoxWndProc; wc.style = 0L; wc.cbWndExtra = sizeof(lpNBox); wc.cbClsExtra = 0; if (!RegisterClass(&wc)) fSuccess = TraceFALSE(NULL); } // create a notify box window // if (fSuccess && (lpNBox->hwndNBox = CreateWindowEx( WS_EX_DLGMODALFRAME, NBOXCLASS, (LPTSTR) lpszTitle, WS_POPUP | (lpszTitle == NULL ? 0 : WS_CAPTION), // | WS_DLGFRAME, 0, 0, 0, 0, // we will calculate size and position later #if 1 hwndParent, #else (HWND) NULL, #endif (HMENU) NULL, lpNBox->hInst, lpNBox)) == NULL) { fSuccess = TraceFALSE(NULL); } // calculate avg char width and height // if (fSuccess) { HDC hdc = NULL; TEXTMETRIC tm; if ((hdc = GetDC(hwndParent)) == NULL) fSuccess = TraceFALSE(NULL); else if (!GetTextMetrics(hdc, &tm)) fSuccess = TraceFALSE(NULL); else { cxChar = tm.tmAveCharWidth; cyChar = tm.tmHeight + tm.tmExternalLeading; } if (hdc != NULL && !ReleaseDC(hwndParent, hdc)) fSuccess = TraceFALSE(NULL); } if (fSuccess) { // calculate size of text // if (StrGetRowColumnCount(lpszText, &nRows, &nColumns) != 0) fSuccess = TraceFALSE(NULL); nRows = min(nRows, NBOXMAXROWS); nColumns = min(nColumns, NBOXMAXCOLUMNS); } if (fSuccess) { int cxNBox; int cyNBox; int cxCancel; int cyCancel; int xCancel; int yCancel; // calculate window size // cxNBox = (nColumns + 10) * cxChar + 2 * GetSystemMetrics(SM_CXBORDER); cyNBox = (nRows + 4) * cyChar + 2 * GetSystemMetrics(SM_CYBORDER); // increase notify box size to accomodate caption // if (lpszTitle != NULL) cyNBox += GetSystemMetrics(SM_CYCAPTION); if (lpNBox->dwFlags & NB_CANCEL) { // calculate cancel button size // cxCancel = (40 * (int) LOWORD(GetDialogBaseUnits())) / 4; cyCancel = (14 * (int) HIWORD(GetDialogBaseUnits())) / 8; // increase notify box size to accomodate CANCEL button // cxNBox = max(cxNBox, cxCancel); cyNBox += cyCancel * 2; // calculate cancel button position // xCancel = (cxNBox - cxCancel) / 2; yCancel = (cyNBox - (cyCancel * 2)); // modify cancel button position to accomodate caption // if (lpszTitle != NULL) yCancel -= GetSystemMetrics(SM_CYCAPTION); } // set window size // if (!SetWindowPos(lpNBox->hwndNBox, NULL, 0, 0, cxNBox, cyNBox, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER)) fSuccess = TraceFALSE(NULL); // center the window on its parent // else if (WndCenterWindow(lpNBox->hwndNBox, hwndParent, 0, 0) != 0) fSuccess = TraceFALSE(NULL); else if ((lpNBox->dwFlags & NB_CANCEL)) { // create cancel button as child of notify box // if ((lpNBox->hwndCancel = CreateWindowEx( 0L, TEXT("BUTTON"), lpszButtonText == NULL ? TEXT("Cancel") : lpszButtonText, WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, xCancel, yCancel, cxCancel, cyCancel, (HWND) lpNBox->hwndNBox, (HMENU) IDCANCEL, lpNBox->hInst, NULL)) == NULL) { fSuccess = TraceFALSE(NULL); } // subclass the cancel button, so the escape key pushes it // else if (EscButtInit(lpNBox->hwndCancel, 0) != 0) fSuccess = TraceFALSE(NULL); } } if (!fSuccess) { NBoxDestroy(NBoxGetHandle(lpNBox)); lpNBox = NULL; } return fSuccess ? NBoxGetHandle(lpNBox) : NULL; } // NBoxDestroy - notify box destructor // (i) handle returned from NBoxCreate // return 0 if success // int DLLEXPORT WINAPI NBoxDestroy(HNBOX hNBox) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if (NBoxHide(hNBox) != 0) fSuccess = TraceFALSE(NULL); else if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); else { // destroy text string // if (lpNBox->lpszText != NULL && StrDupFree(lpNBox->lpszText) != 0) fSuccess = TraceFALSE(NULL); else lpNBox->lpszText = NULL; // destroy cancel button // if (lpNBox->hwndCancel != NULL) { if (EscButtTerm(lpNBox->hwndCancel) != 0) fSuccess = TraceFALSE(NULL); if (!DestroyWindow(lpNBox->hwndCancel)) fSuccess = TraceFALSE(NULL); else lpNBox->hwndCancel = NULL; } // destroy notify box // if (lpNBox->hwndNBox != NULL && !DestroyWindow(lpNBox->hwndNBox)) fSuccess = TraceFALSE(NULL); else lpNBox->hwndNBox = NULL; // destroy control struct // if ((lpNBox = MemFree(NULL, lpNBox)) != NULL) fSuccess = TraceFALSE(NULL); } return fSuccess ? 0 : -1; } // NBoxShow - show notify box // (i) handle returned from NBoxCreate // return 0 if success // int DLLEXPORT WINAPI NBoxShow(HNBOX hNBox) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); else if (lpNBox->fVisible) ; // already visible, so no need to do anything else else { HWND hwndParent = GetParent(lpNBox->hwndNBox); // disable other windows in this task if necessary // if (lpNBox->dwFlags & NB_TASKMODAL) { HTASK hTaskParent; if (hwndParent != NULL) hTaskParent = GetWindowTask(hwndParent); else hTaskParent = lpNBox->hTask; if (WndEnableTaskWindows(hTaskParent, FALSE, lpNBox->hwndNBox) != 0) TraceFALSE(NULL); // not a fatal error } // otherwise just disable parent of notify box // else if (hwndParent != NULL) EnableWindow(hwndParent, FALSE); if (fSuccess) { // show the window // ShowWindow(lpNBox->hwndNBox, TRUE ? SW_SHOW : SW_SHOWNA); UpdateWindow(lpNBox->hwndNBox); lpNBox->fVisible = TRUE; // set focus to cancel button if necessary // if (lpNBox->dwFlags & NB_CANCEL && lpNBox->hwndCancel != NULL) lpNBox->hwndFocusOld = SetFocus(lpNBox->hwndCancel); } // display hourglass cursor if specified // if (fSuccess && lpNBox->dwFlags & NB_HOURGLASS) lpNBox->hCursorOld = GfxShowHourglass(lpNBox->hwndNBox); } return fSuccess ? 0 : -1; } // NBoxHide - hide notify box // (i) handle returned from NBoxCreate // return 0 if success // int DLLEXPORT WINAPI NBoxHide(HNBOX hNBox) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); else if (!lpNBox->fVisible) ; // already hidden, so no need to do anything else else { HWND hwndParent = GetParent(lpNBox->hwndNBox); // enable other windows in this task if necessary // if (lpNBox->dwFlags & NB_TASKMODAL) { HTASK hTaskParent; if (hwndParent != NULL) hTaskParent = GetWindowTask(hwndParent); else hTaskParent = lpNBox->hTask; if (WndEnableTaskWindows(hTaskParent, TRUE, NULL) != 0) TraceFALSE(NULL); // not a fatal error } // otherwise just enable parent of notify box // else if (hwndParent != NULL) EnableWindow(hwndParent, TRUE); if (fSuccess) { // hide the window // ShowWindow(lpNBox->hwndNBox, SW_HIDE); UpdateWindow(lpNBox->hwndNBox); lpNBox->fVisible = FALSE; // remove focus from cancel button if necessary // if (lpNBox->dwFlags & NB_CANCEL && lpNBox->hwndCancel != NULL && GetFocus() == lpNBox->hwndCancel) SetFocus(lpNBox->hwndFocusOld); } // hide hourglass, restore old cursor // if (fSuccess && lpNBox->dwFlags & NB_HOURGLASS) { if (GfxHideHourglass(lpNBox->hCursorOld) != 0) fSuccess = TraceFALSE(NULL); else lpNBox->hCursorOld = NULL; } } return fSuccess ? 0 : -1; } // NBoxIsVisible - get visible flag // (i) handle returned from NBoxCreate // return TRUE if notify box is visible, FALSE if hidden // int DLLEXPORT WINAPI NBoxIsVisible(HNBOX hNBox) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); return fSuccess ? lpNBox->fVisible : FALSE; } // NBoxGetWindowHandle - get notify box window handle // (i) handle returned from NBoxCreate // return window handle (NULL if error) // HWND DLLEXPORT WINAPI NBoxGetWindowHandle(HNBOX hNBox) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); return fSuccess ? lpNBox->hwndNBox : NULL; } // NBoxSetText - set notify box message text // (i) handle returned from NBoxCreate // (i) message to be displayed // NULL do not modify text // (i) notify box caption // NULL do not modify caption // return 0 if success // // NOTE: The size of the notify box is not changed by this function, // even if is larger than when NBoxCreate() was called. // int DLLEXPORT WINAPI NBoxSetText(HNBOX hNBox, LPCTSTR lpszText, LPCTSTR lpszTitle) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); else { if (lpszTitle != NULL) { // set new title // SetWindowText(lpNBox->hwndNBox, lpszTitle); } if (lpszText != NULL) { // dispose of previous text // if (lpNBox->lpszText != NULL) { if (StrDupFree(lpNBox->lpszText) != 0) fSuccess = TraceFALSE(NULL); else lpNBox->lpszText = NULL; } // set new text // if ((lpNBox->lpszText = StrDup(lpszText)) == NULL) fSuccess = TraceFALSE(NULL); } // update the display // if (fSuccess) { RECT rc; // assume entire client area needs to be painted // GetClientRect(lpNBox->hwndNBox, &rc); // adjust client rect so cancel button is no repainted // if (lpNBox->dwFlags & NB_CANCEL) { int cyCancel = (14 * (int) HIWORD(GetDialogBaseUnits())) / 8; rc.bottom -= cyCancel * 2; } InvalidateRect(lpNBox->hwndNBox, &rc, TRUE); UpdateWindow(lpNBox->hwndNBox); } } return fSuccess ? 0 : -1; } // NBoxIsCancelled - get cancel flag, set when Cancel button pushed // (i) handle returned from NBoxCreate // return TRUE if notify box Cancel button pushed // BOOL DLLEXPORT WINAPI NBoxIsCancelled(HNBOX hNBox) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); return fSuccess ? lpNBox->fCancelled : FALSE; } // NBoxSetCancelled - set cancel flag // (i) handle returned from NBoxCreate // (i) new value for cancel flag // return 0 if success // int DLLEXPORT WINAPI NBoxSetCancelled(HNBOX hNBox, BOOL fCancelled) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = NBoxGetPtr(hNBox)) == NULL) fSuccess = TraceFALSE(NULL); else lpNBox->fCancelled = fCancelled; return fSuccess ? 0 : -1; } //// // helper functions //// // NBoxWndProc - window procedure for notify box // LRESULT DLLEXPORT CALLBACK NBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL fSuccess = TRUE; LRESULT lResult; switch (msg) { case WM_NCCREATE: lResult = (LRESULT) HANDLE_WM_NCCREATE(hwnd, wParam, lParam, NBoxOnNCCreate); break; case WM_COMMAND: lResult = (LRESULT) HANDLE_WM_COMMAND(hwnd, wParam, lParam, NBoxOnCommand); break; case WM_PAINT: lResult = (LRESULT) HANDLE_WM_PAINT(hwnd, wParam, lParam, NBoxOnPaint); break; default: lResult = DefWindowProc(hwnd, msg, wParam, lParam); break; } return lResult; } // NBoxOnNCCreate - handler for WM_NCCREATE message // static BOOL NBoxOnNCCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct) { LPNBOX lpNBox = (LPNBOX) lpCreateStruct->lpCreateParams; lpNBox->hwndNBox = hwnd; // store lpNBox in window extra bytes // SetWindowLongPtr(hwnd, 0, (LONG_PTR) lpNBox); return FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, DefWindowProc); } // NBoxOnCommand - handler for WM_COMMAND message // static void NBoxOnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { // retrieve lpNBox from window extra bytes // LPNBOX lpNBox = (LPNBOX) GetWindowLongPtr(hwnd, 0); if (id == IDCANCEL) if (codeNotify == BN_CLICKED) lpNBox->fCancelled = TRUE; return; } // NBoxOnPaint - handler for WM_PAINT message // static void NBoxOnPaint(HWND hwnd) { BOOL fSuccess = TRUE; HDC hdc; PAINTSTRUCT ps; TEXTMETRIC tm; int cxChar; int cyChar; COLORREF crBkColorOld; COLORREF crTextColorOld; int nRows; int nColumns; // retrieve lpNBox from window extra bytes // LPNBOX lpNBox = (LPNBOX) GetWindowLongPtr(hwnd, 0); hdc = BeginPaint(hwnd, &ps); if (!GetTextMetrics(hdc, &tm)) fSuccess = TraceFALSE(NULL); else { cxChar = tm.tmAveCharWidth; cyChar = tm.tmHeight + tm.tmExternalLeading; // set foreground and background text colors // crBkColorOld = SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); crTextColorOld = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); if (StrGetRowColumnCount(lpNBox->lpszText, &nRows, &nColumns) != 0) fSuccess = TraceFALSE(NULL); else { int iRow; for (iRow = 0; iRow < nRows; ++iRow) { TCHAR szRow[NBOXMAXCOLUMNS + 1]; if (StrGetRow(lpNBox->lpszText, iRow, szRow, SIZEOFARRAY(szRow)) != 0) fSuccess = TraceFALSE(NULL); else { int x = 5 * cxChar; int y = (iRow + 2) * cyChar; if (!TextOut(hdc, x, y, szRow, StrLen(szRow))) fSuccess = TraceFALSE(NULL); } } } // // Restore foreground and background in the right place // // restore foreground and background text colors // SetBkColor(hdc, crBkColorOld); SetTextColor(hdc, crTextColorOld); } // // Call EndPaint just BeginPaint succeded // if( hdc ) EndPaint(hwnd, &ps); return; } // NBoxGetPtr - verify that nbox handle is valid, // (i) handle returned from NBoxInit // return corresponding nbox pointer (NULL if error) // static LPNBOX NBoxGetPtr(HNBOX hNBox) { BOOL fSuccess = TRUE; LPNBOX lpNBox; if ((lpNBox = (LPNBOX) hNBox) == NULL) fSuccess = TraceFALSE(NULL); else if (IsBadWritePtr(lpNBox, sizeof(NBOX))) fSuccess = TraceFALSE(NULL); #ifdef CHECKTASK // make sure current task owns the nbox handle // else if (lpNBox->hTask != GetCurrentTask()) fSuccess = TraceFALSE(NULL); #endif return fSuccess ? lpNBox : NULL; } // NBoxGetHandle - verify that nbox pointer is valid, // (i) pointer to NBOX struct // return corresponding nbox handle (NULL if error) // static HNBOX NBoxGetHandle(LPNBOX lpNBox) { BOOL fSuccess = TRUE; HNBOX hNBox; if ((hNBox = (HNBOX) lpNBox) == NULL) fSuccess = TraceFALSE(NULL); return fSuccess ? hNBox : NULL; }