/* ----------------------------------------------------------------------

	CNFTEST sample for Microsoft ActiveX Conferencing

	Copyright (c) 1996, Microsoft Corporation
	All rights reserved.


	util.c

	Generic utility routines not specific to this application

---------------------------------------------------------------------- */

#include "main.h"
#include "shlobj.h"

static char _szAppName[] = "CnfTest";
static char _szIniName[] = "CnfTest.ini";



/*  D I S P A T C H  M S G */
/*-------------------------------------------------------------------------
	%%Function: DispatchMsg

	Search the message table and call the appropriate routine.
-------------------------------------------------------------------------*/
LRESULT DispatchMsg(LPMSD lpmsd, HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam)
{
	for (; ; lpmsd++) {
		if ((lpmsd->uMsg == 0) || (lpmsd->uMsg == uMsg)) {
			return lpmsd->pfnmsg(hwnd, uMsg, wparam, lparam);
		}
	}

	NotReached();
}


/*  D I S P A T C H  C M D */
/*-------------------------------------------------------------------------
	%%Function: DispatchCmd

	Search the command table and call the appropriate routine.
-------------------------------------------------------------------------*/
LRESULT DispatchCmd(LPCMD lpcmd, HWND hwnd, WPARAM wparam, LPARAM lparam)
{
	WORD wCmd = GET_WM_COMMAND_ID(wparam, lparam);

	for (; ; lpcmd++) {
		if ((lpcmd->wCmd == 0) || (lpcmd->wCmd == wCmd)) {
			lpcmd->pfncmd(hwnd, wCmd,
					GET_WM_COMMAND_CMD(wparam, lparam),
					GET_WM_COMMAND_HWND(wparam, lparam));
			break;
		}
	}

	return 0L;
}


/*  G E T  I N I  B O O L */
/*-------------------------------------------------------------------------
	%%Function: GetIniBool

	Get the boolean data for an entry
-------------------------------------------------------------------------*/
BOOL GetIniBool(LPSTR szEntry, BOOL fDefault)
{
	return GetPrivateProfileInt(_szAppName, szEntry, fDefault, _szIniName) != 0;
}

/*  G E T  I N I  I N T */
/*-------------------------------------------------------------------------
	%%Function: GetIniInt

	Get the numeric data for an entry
-------------------------------------------------------------------------*/
DWORD GetIniInt(LPSTR szEntry, DWORD dwDefault)
{
	return GetPrivateProfileInt(_szAppName, szEntry, dwDefault, _szIniName);
}

/*  G E T  I N I  S T R */
/*-------------------------------------------------------------------------
	%%Function: GetIniStr

	Get the string data for an entry
-------------------------------------------------------------------------*/
LPSTR GetIniStr(LPSTR szEntry, LPSTR szDefault)
{
	int    cch;
	LPVOID lpv;
	char   sz[MAX_PATH];

	cch = GetPrivateProfileString(_szAppName, szEntry, szDefault, sz, MAX_PATH, _szIniName);
	if (cch == 0)
	{
		if (NULL == szDefault)
			return NULL;

		cch = lstrlen(szDefault);
		lstrcpy(sz, szDefault);
	}
	cch++; // include chNull

	lpv = LpvAlloc(cch);
	if (lpv == NULL)
		return NULL;

	lstrcpyn(lpv, sz, cch);

	return lpv;
}


/* G E T  I N I  H E X */
/*-------------------------------------------------------------------------
	%%Function: GetIniHex

	Convert the hex data into binary.
	If no entry is found, lpv isn't modified
-------------------------------------------------------------------------*/
VOID GetIniHex(LPSTR szEntry, LPVOID lpv, int cb)
{
	char sz[MAX_PATH];

	if (GetPrivateProfileString(_szAppName, szEntry, lpNil, sz, MAX_PATH, _szIniName) != 0) {
		HexToData(sz, lpv, cb);
	}
}





/*  W R I T E  I N I  S T R */
/*-------------------------------------------------------------------------
	%%Function: WriteIniStr

	Write the data to an entry in the ini file
-------------------------------------------------------------------------*/
VOID WriteIniStr(LPSTR szEntry, LPSTR szData)
{
	WritePrivateProfileString(_szAppName, szEntry, szData, _szIniName);
}


/*  W R I T E  I N I  I N T */
/*-------------------------------------------------------------------------
	%%Function: WriteIniInt

	Write the numeric data to an entry in the ini file
-------------------------------------------------------------------------*/
VOID WriteIniInt(LPSTR szEntry, DWORD dw)
{
	char szData[32];

	wsprintf(szData, "%d", dw);
	WritePrivateProfileString(_szAppName, szEntry, szData, _szIniName);
}



/*  W R I T E  I N I  B O O L */
/*-------------------------------------------------------------------------
	%%Function: WriteIniBool

	Write the boolean value to an entry in the registery
-------------------------------------------------------------------------*/
VOID WriteIniBool(LPSTR szEntry, BOOL f)
{
	WritePrivateProfileString(_szAppName, szEntry, f ? "1" : "0", _szIniName);
}


/* W R I T E  I N I  H E X */
/*-------------------------------------------------------------------------
	%%Function: WriteIniHex

-------------------------------------------------------------------------*/
VOID WriteIniHex(LPSTR szEntry, LPVOID lpv, int cb)
{
	char   sz[MAX_PATH];

	DataToHex(lpv, sz, cb);

	WriteIniStr(szEntry, sz);
}


/*  C E N T E R  W I N D O W */
/*-------------------------------------------------------------------------
	%%Function: CenterWindow

	Center a window over another window.
-------------------------------------------------------------------------*/
VOID CenterWindow(HWND hwndChild, HWND hwndParent)
{
	int   xNew, yNew;
	int   cxChild, cyChild;
	int   cxParent, cyParent;
	int   cxScreen, cyScreen;
	RECT  rcChild, rcParent;
	HDC   hdc;

	// Get the Height and Width of the child window
	GetWindowRect(hwndChild, &rcChild);
	cxChild = rcChild.right - rcChild.left;
	cyChild = rcChild.bottom - rcChild.top;

	// Get the Height and Width of the parent window
	GetWindowRect(hwndParent, &rcParent);
	cxParent = rcParent.right - rcParent.left;
	cyParent = rcParent.bottom - rcParent.top;

	// Get the display limits
	hdc = GetDC(hwndChild);
	if (hdc == NULL) {
		// major problems - move window to 0,0
		xNew = yNew = 0;
	} else {
		cxScreen = GetDeviceCaps(hdc, HORZRES);
		cyScreen = GetDeviceCaps(hdc, VERTRES);
		ReleaseDC(hwndChild, hdc);

		if (hwndParent == hwndNil) {
			cxParent = cxScreen;
			cyParent = cyScreen;
			SetRect(&rcParent, 0, 0, cxScreen, cyScreen);
		}

		// Calculate new X position, then adjust for screen
		xNew = rcParent.left + ((cxParent - cxChild) / 2);
		if (xNew < 0) {
			xNew = 0;
		} else if ((xNew + cxChild) > cxScreen) {
			xNew = cxScreen - cxChild;
		}

		// Calculate new Y position, then adjust for screen
		yNew = rcParent.top  + ((cyParent - cyChild) / 2);
		if (yNew < 0) {
			yNew = 0;
		} else if ((yNew + cyChild) > cyScreen) {
			yNew = cyScreen - cyChild;
		}

	}

	SetWindowPos(hwndChild, NULL, xNew, yNew,	0, 0,
		SWP_NOSIZE | SWP_NOZORDER);
}


/*  L P V  A  L L O C */
/*-------------------------------------------------------------------------
	%%Function: LpvAlloc

	Return a pointer to an allocated array of bytes
-------------------------------------------------------------------------*/
LPVOID LpvAlloc(int cb)
{
	return LocalAlloc(LMEM_FIXED, cb);
}


/*  F R E E  P L P V */
/*-------------------------------------------------------------------------
	%%Function: FreePlpv

	Free the data pointed to by plpv and set *plpv to NULL
-------------------------------------------------------------------------*/
VOID FreePlpv(LPVOID plpv)
{
	if ((plpv == NULL) || (*(VOID FAR * FAR *)plpv == NULL)) {
		return;
	}

	LocalFree(*(VOID FAR * FAR *)plpv);
	*(VOID FAR * FAR *)plpv = NULL;
}


/*  D E F  C M D  P R O C */
/*-------------------------------------------------------------------------
	%%Function: DefCmdProc

	Default command procedure.
-------------------------------------------------------------------------*/
VOID DefCmdProc(HWND hwnd, WORD wCmd, WORD w2, HWND hwndCtrl)
{
	Log2(LOG_NORMAL, "DefCmdProc reached: wCmd=0x%08X, w2=0x%08X", wCmd, w2);
}



/*  C H  F R O M  H E X */
/*-------------------------------------------------------------------------
	%%Function: ChFromHex

	Convert from Hex data to ascii character
-------------------------------------------------------------------------*/
char ChFromHex(LPSTR lpch)
{
	int i = 0;
	int cch = 2;
	char ch;

	while (cch-- > 0) {
		ch = *lpch++;
		if (ch >= 'A') {
			i = (i*16) + (ch - ('A'-10));
		} else {
			i = (i*16) + (ch - '0');
		}
	}

	return (char) i;
}


/*  H E X  T O  D A T A */
/*-------------------------------------------------------------------------
	%%Function: HexToData

	Convert from Hex data to ascii character
-------------------------------------------------------------------------*/
VOID HexToData(LPSTR lpchSrc, LPVOID lpvDest, int cb)
{
	CHAR * lpchDest = lpvDest;

	CharUpperBuff(lpchSrc, cb);

	while (cb-- > 0)
	{
		*lpchDest++ = ChFromHex(lpchSrc);
		lpchSrc += 2;
	}
}


/*  H E X  T O  B I N */
/*-------------------------------------------------------------------------
	%%Function: HexToBin

	Convert from Hex data to ascii character
-------------------------------------------------------------------------*/
LPSTR HexToBin(LPSTR lpchSrc, LPVOID lpvDest, int cb)
{
	CHAR * lpchDest = ((CHAR *) lpvDest) + cb;

	CharUpperBuff(lpchSrc, cb);

	while (cb-- > 0)
	{
		lpchDest--;
		*lpchDest = ChFromHex(lpchSrc);
		lpchSrc += 2;
	}
	return lpchSrc;
}


/*  D A T A  T O  H E X */
/*-------------------------------------------------------------------------
	%%Function: DataToHex

-------------------------------------------------------------------------*/
VOID DataToHex(LPSTR lpchSrc, LPSTR lpchDest, int cb)
{
	unsigned char ch;

	if (lpchSrc == lpNil)
	{
//		Log(LOG_ALWAYS, "DataToHex - lpSrc == lpNil");
		SetEmptySz(lpchDest);
		return;
	}

	while (cb-- > 0) {
		ch = 0x00FF & (unsigned char) (*lpchSrc++);
		wsprintf(lpchDest, "%02X", ch);
		lpchDest += 2;
	}
}




/* S E T  M E N U  C H E C K */
/*----------------------------------------------------------------------------
	%%Function: SetMenuCheck

	Set the menu item's check mark.

----------------------------------------------------------------------------*/
VOID SetMenuCheck(UINT idm, BOOL fCheck)
{
	CheckMenuItem(ghMenu, idm,
		fCheck ? (MF_CHECKED  | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
}



/* M A Y B E   D E L E T E   O B J E C T */
/*----------------------------------------------------------------------------
	%%Function: MaybeDeleteObject

	Check usage count, delete if we can
----------------------------------------------------------------------------*/
VOID MaybeDeleteObject(HGDIOBJ * phgdi)
{
	if (*phgdi == hgdiNil)
		return;

	DeleteObject(*phgdi);
	*phgdi = hgdiNil;	
}


static char _szAssertTitle[] = "CnfTest Assert";


/*  A S S E R T  P R O C */
/*-------------------------------------------------------------------------
	%%Function: AssertProc

-------------------------------------------------------------------------*/
VOID FAR PASCAL AssertProc(LPSTR lpszMsg, LPSTR lpszAssert, LPSTR lpszFile, UINT line)
{
	char szBuffer[MAX_PATH];
	int  id;
	static BOOL _fInAssert = fFalse;

	wsprintf((LPSTR)szBuffer,
		"Assert: %s\nFile %s, Line %d",
		(lpszMsg && *lpszMsg) ? lpszMsg  : lpszAssert,
		lpszFile ? lpszFile : "", line);

	OutputDebugString(szBuffer);

	if (_fInAssert) {
		return;
	}
	_fInAssert = fTrue;

	do {
		id = MessageBox(NULL, (LPSTR)szBuffer, (LPSTR)_szAssertTitle,
					MB_ICONHAND | MB_ABORTRETRYIGNORE | MB_SYSTEMMODAL);

		switch (id)
		{
		case IDRETRY:
			DebugBreak();
			break;
		case IDABORT:
			FatalAppExit(0, (LPSTR)szBuffer);
			break;
		case IDIGNORE:
		default:
			break;
		}
	} while (id == IDRETRY);

	_fInAssert = fFalse;
}


/*  L O G */
/*-------------------------------------------------------------------------
	%%Function: Log

-------------------------------------------------------------------------*/
VOID Log(DWORD grf, LPSTR lpsz)
{
	int i;

	if (((grf & gPref.grfLog) == 0) || (ghwndMsg == hwndNil))
	{
		return;
	}

	// write the string to the Message window
	i = SendMessage(ghwndMsg, LB_ADDSTRING, 0, (LPARAM) lpsz);
	if( grf == LOG_ERROR )
		SendMessage(ghwndMsg, LB_SETITEMDATA, (WPARAM)i, (LPARAM)255);
	else
		SendMessage(ghwndMsg, LB_SETITEMDATA, (WPARAM)i, (LPARAM)0);

	PostMessage(ghwndMsg, WM_VSCROLL, SB_BOTTOM, 0);
}


/* C L E A R  L O G */
/*----------------------------------------------------------------------------
	%%Function: ClearLog

	Clear the log screen

----------------------------------------------------------------------------*/
VOID ClearLog(void)
{
	SendMessage(ghwndMsg, LB_RESETCONTENT, 0, 0);
}

/* L O G  T E S T  S T A R T */
/*----------------------------------------------------------------------------
	%%Function: LogTestStart

	Start a test by clearing the log and displaying the string.

----------------------------------------------------------------------------*/
VOID LogTestStart(LPSTR sz)
{
	Log1(LOG_ALWAYS, "==> Running Test %s", sz);
}


/*  L O G  T E S T  S T O P */
/*----------------------------------------------------------------------------
	%%Function: LogTestStop

----------------------------------------------------------------------------*/
VOID LogTestStop(LPSTR sz)
{
	Log1(LOG_ALWAYS, "==> Test %s Complete", sz);
}

/*  L O G  T E S T  C A N C E L */
/*----------------------------------------------------------------------------
	%%Function: LogTestCancel

----------------------------------------------------------------------------*/
VOID LogTestCancel(LPSTR sz)
{
	Log1(LOG_ALWAYS, "==> Test %s Canceled", sz);
}


/*  L O G  R E S U L T */
/*----------------------------------------------------------------------------
	%%Function: LogResult

----------------------------------------------------------------------------*/
VOID LogResult(LPSTR sz, DWORD dwTest, DWORD dwResult)
{
	Log3((dwResult == CONFERR_SUCCESS ? LOG_NORMAL : LOG_ERROR), "%s Test %d Result=%s", sz, dwTest, GetConferrString(dwResult));
}


static char _szFilter[] = "All Files\0*.*\0Text Files (*.txt)\0*.TXT\0";



/*  F  G E T  F I L E  N A M E */
/*----------------------------------------------------------------------------
	%%Function: FGetFileName

----------------------------------------------------------------------------*/
BOOL FGetFileName(LPSTR szFileName)
{
	OPENFILENAME ofn;

	SetEmptySz(szFileName);
	ClearStruct(&ofn);

	ofn.lStructSize   = sizeof(OPENFILENAME);
	ofn.hwndOwner     = ghwndMain;
	ofn.hInstance     = (HANDLE) ghInst;
	ofn.lpstrFilter   = _szFilter;
	ofn.nFilterIndex  = 1L;
	ofn.lpstrFile     = (LPSTR) szFileName;
	ofn.nMaxFile      = MAX_PATH; // really sizeof(szFileName)
	ofn.lpstrTitle    = "Pick a file to send";
	ofn.lpstrInitialDir = NULL;
	ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;

	if (!GetOpenFileName(&ofn))
		return fFalse;

	return fTrue;
}



/*  F  G E T  D I R E C T O R Y */
/*----------------------------------------------------------------------------
	%%Function: FGetDirectory

----------------------------------------------------------------------------*/
BOOL FGetDirectory(LPSTR szDir)
{
	BOOL  fRet;
	CHAR  szPath[MAX_PATH];
	LPITEMIDLIST pidl;
	LPITEMIDLIST pidlRoot;
	LPMALLOC lpMalloc;

	BROWSEINFO bi = {
		ghwndMain,
		NULL,
		szPath,
		"Select a Directory",
		BIF_RETURNONLYFSDIRS,
		NULL, 0L, 0	};

	if (0 != SHGetSpecialFolderLocation(HWND_DESKTOP, CSIDL_DRIVES, &pidlRoot))
		return fFalse;
	if (NULL == pidlRoot)
		return fFalse;

	bi.pidlRoot = pidlRoot;
	pidl = SHBrowseForFolder(&bi);

	if (NULL != pidl)
		fRet = SHGetPathFromIDList(pidl, szDir);
	else
		fRet = fFalse;

	// Get the shell's allocator to free PIDLs
	if (!SHGetMalloc(&lpMalloc) && (NULL != lpMalloc))
	{
		if (NULL != pidlRoot)
		{
			lpMalloc->lpVtbl->Free(lpMalloc, pidlRoot);
		}

		if (NULL != pidl)
		{
			lpMalloc->lpVtbl->Free(lpMalloc, pidl);
		}

		lpMalloc->lpVtbl->Release(lpMalloc);
	}

	return fRet;
}



/*  G E T  R A D I O  B U T T O N */
/*----------------------------------------------------------------------------
	%%Function: GetRadioButton

----------------------------------------------------------------------------*/
int GetRadioButton(HWND hdlg, int idrFirst, int idrLast)
{
	int id;

	for (id = idrFirst; id <= idrLast; id++)
	{
		if (IsDlgButtonChecked(hdlg, id))
			return id;
	}
	return idrFirst;
}


/*  G U I D  T O  S Z */
/*----------------------------------------------------------------------------
	%%Function: GuidToSz

	Convert the guid to a hex string.
	Assumes lpchDest has space for at least sizeof(GUID)*2+1 chars.

	Note the difference between this and UuidToString (or StringFromGUID2)
----------------------------------------------------------------------------*/
VOID GuidToSz(GUID * pguid, LPSTR lpchDest)
{
	int i;

	ASSERT(NULL != pguid);
	ASSERT(NULL != lpchDest);

	lstrcpy(lpchDest, "--------------------------------");

	wsprintf(lpchDest, "%08X%04X%04X", pguid->Data1, pguid->Data2, pguid->Data3);
	lpchDest += 8+4+4;
	for (i = 0; i < 8; i++)
	{
		wsprintf(lpchDest, "%02X", pguid->Data4[i]);
		lpchDest += 2;
	}
}


/*  S Z  T O  G U I D */
/*----------------------------------------------------------------------------
	%%Function: SzToGuid

----------------------------------------------------------------------------*/
VOID SzToGuid(LPSTR lpchSrc, GUID * pguid)
{
	if (FEmptySz(lpchSrc) || (CchSz(lpchSrc) < sizeof(GUID)*2))
	{
		ClearStruct(pguid);
		return;
	}

	ClearStruct(pguid);

	lpchSrc = HexToBin(lpchSrc, &pguid->Data1, sizeof(pguid->Data1));
	lpchSrc = HexToBin(lpchSrc, &pguid->Data2, sizeof(pguid->Data2));
	lpchSrc = HexToBin(lpchSrc, &pguid->Data3, sizeof(pguid->Data3));
	HexToData(lpchSrc, pguid->Data4, sizeof(pguid->Data4));
}
	




