/////////////////////////////////////////////////////////////////////////////////////////
//
// 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 <stdlib.h>

#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
//		<dwVersion>			(i) must be NBOX_VERSION
// 		<hInst>				(i) instance handle of calling module
//		<hwndParent>		(i) window which will own the notify box
//			NULL				desktop window
//		<lpszText>			(i) message to be displayed
//		<lpszTitle>			(i) notify box caption
//			NULL				no caption
//		<lpszButtonText>	(i) pushbutton text, if NB_CANCEL specified
//			NULL				use default text ("Cancel")
//		<dwFlags>			(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 <lpszText>, 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
//		<hNBox>				(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
//		<hNBox>				(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
//		<hNBox>				(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
//		<hNBox>				(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
//		<hNBox>				(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
//		<hNBox>				(i) handle returned from NBoxCreate
//		<lpszText>			(i) message to be displayed
//			NULL				do not modify text
//		<lpszTitle>			(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 <lpszText> 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
//		<hNBox>				(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
//		<hNBox>				(i) handle returned from NBoxCreate
//		<fCancelled>		(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,
//		<hNBox>				(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,
//		<lpNBox>				(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;
}