// Utils.cpp : Utility functions
//
#include "stdafx.h" // Precompiled header file
#include "NGMacros.h" // Library header
#include "NGUtils.h" // Library header
#include "NGRegistry.h" // CNGRegistry class
#include <afxPriv.h> // For AFX_NOTIFY declaration
#include <lmcons.h> // For UNLEN definition
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Define this to check the results of CombinePath() against the equivalent shlwapi funtions
#define _VERIFY_PATHCOMBINE
#ifndef _DEBUG
#ifdef _VERIFY_PATHCOMBINE
#undef _VERIFY_PATHCOMBINE
#endif
#endif
/////////////////////////////////////////////////////////////////////////////
// Helper functions
NGLIB_EXT_API BOOL SetHelpFileName(const CString& sFileName)
{
BOOL bResult = FALSE;
CWinApp* pApp = AfxGetApp();
if (NULL != pApp)
{
CString sHelpFilePath = GetAppStartDir() +
_T("\\") +
sFileName;
// Note: If you assign a value to m_pszHelpFilePath, it must be dynamically
// allocated on the heap. The CWinApp destructor calls free( ) with
// this pointer. Also, free the memory associated with the current
// pointer before assigning a new value:
// First free the string allocated by MFC at CWinApp startup.
// The string is allocated before InitInstance is called.
free((void*)pApp->m_pszHelpFilePath);
// Change the name of the helpfile.
// The CWinApp destructor will free the memory.
pApp->m_pszHelpFilePath = _tcsdup(sHelpFilePath);
bResult = TRUE;
}
return bResult;
}
/*****************************************************************************
* Return the start directory of the current application
*
*****************************************************************************/
NGLIB_EXT_API CString GetAppStartDir(void)
{
CString sExe;
LPTSTR pszName = sExe.GetBuffer(_MAX_PATH);
::GetModuleFileName(AfxGetApp()->m_hInstance, pszName, _MAX_PATH);
sExe.ReleaseBuffer();
int nLastSlash = sExe.ReverseFind( _T('\\') );
CString sPath = sExe.Left(nLastSlash);
return sPath;
}
/*****************************************************************************
* Add a "Run Once" key to the registry
*
* The specified command line will be executed when the system is next
* restarted.
*
*****************************************************************************/
NGLIB_EXT_API BOOL AddRunOnceKey(const CString& rsAppName, const CString& rsCmdLine)
{
CString sKey = _T("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\");
CString sValue = rsAppName + _T(" ") + rsCmdLine;
CNGRegistry Reg;
Reg.SetEntry(sKey, sValue);
return TRUE;
}
// Set the text in pane 0 of the status bar
NGLIB_EXT_API BOOL SetStatusBarText(const CString& rsText, UINT uID /*= AFX_IDW_STATUS_BAR*/)
{
CWnd* pMainFrame = AfxGetMainWnd();
ASSERT_VALID(pMainFrame);
CWnd* pWnd = pMainFrame->GetDescendantWindow(uID, TRUE);
if (pWnd != NULL)
{
pWnd->SetWindowText(rsText);
return TRUE;
}
return FALSE;
}
/*****************************************************************************
* Send a WM_COMMAND message to a defined CCmdTarget
*
* Note: the message WILL NOT touch Windows itself or the message pump
* since it will be dispatched directly into the message map by CCmdTarget
*
*****************************************************************************/
NGLIB_EXT_API BOOL SendCommandMsg(CCmdTarget* pTarget, UINT uID)
{
ASSERT(NULL != pTarget);
ASSERT(uID != 0);
if (pTarget != NULL)
{
return pTarget->OnCmdMsg(uID, CN_COMMAND, NULL, NULL);
}
return FALSE;
}
/*****************************************************************************
* Send a WM_NOTIFY message to a defined CCmdTarget
*
* Note: the message WILL NOT touch Windows itself or the message pump
* since it will be dispatched directly into the message map by CCmdTarget
*
*****************************************************************************/
NGLIB_EXT_API BOOL SendNotifyMsg(CCmdTarget* pTarget,
UINT uID,
int nCode,
NMHDR* pNMHDR,
LRESULT* pResult)
{
ASSERT(NULL != pTarget);
ASSERT(NULL != pNMHDR);
pNMHDR->idFrom = uID;
pNMHDR->code = nCode;
AFX_NOTIFY notify;
notify.pResult = pResult;
notify.pNMHDR = pNMHDR;
return pTarget->OnCmdMsg(pNMHDR->idFrom, MAKELONG(pNMHDR->code, WM_NOTIFY), ¬ify, NULL);
}
/*****************************************************************************
* Bit twiddling routines
*****************************************************************************/
unsigned long SetBit(unsigned long nData, UINT nBitNo, BOOL bBitState)
{
unsigned long nMask = 1 << nBitNo;
if (bBitState)
nData = nData | nMask;
else
nData = nData & (ULONG_MAX - nMask);
return (nData);
}
BOOL GetBit(unsigned long nData, UINT nBitNo)
{
if (nData & (unsigned long) (1 << nBitNo))
return (TRUE);
return (FALSE);
}
/******************************************************************************
* String manipulation routines
*
******************************************************************************/
// Remove tabs from the given string
NGLIB_EXT_API CString UnTabify(const CString& rsData, int nTabWidth /*= 4*/)
{
CString sResult;
for (int nPos = 0; nPos < rsData.GetLength(); nPos++)
{
if (_T('\t') == rsData[nPos])
{
sResult += CString(_T(' '), nTabWidth - (nPos % nTabWidth) );
}
else
sResult += rsData[nPos];
}
TRACE1("tabbed string : %s\n", rsData);
TRACE1("detabbed string : %s\n", sResult);
return sResult;
}
// Return source string up to, but not including, target
NGLIB_EXT_API CString Before(const CString& rsSource, LPCTSTR pszTarget)
{
int nTargetPos = rsSource.Find(pszTarget);
if (-1 == nTargetPos)
return rsSource; // target not present; return all
return rsSource.Left(nTargetPos);
}
// Return source string after, but not including, target
NGLIB_EXT_API CString After(const CString& rsSource, LPCTSTR pszTarget)
{
int nTargetPos = rsSource.Find(pszTarget);
if (-1 != nTargetPos) // Found?
{
int nChars = rsSource.GetLength() - (nTargetPos + lstrlen(pszTarget));
if (nChars > 0) // Something after the target...
return (rsSource.Right(nChars));
}
return _T(""); // Nowt after target
}
// Return source string between two target strings
NGLIB_EXT_API CString Between(const CString& rsSource, LPCTSTR pszStartAfter, LPCTSTR pszStopBefore)
{
return Before(After(rsSource, pszStartAfter), pszStopBefore);
}
// Chomp the next parameter out of the given string
// consuming it in the process
NGLIB_EXT_API CString Chomp(CString& rsSource, LPCTSTR pszDelimiter /*= ","*/)
{
CString sParam;
// Loop until we've either found a non-null parameter or we run out of string
while (!rsSource.IsEmpty())
{
// Extract string up to, but not including, delimiter
sParam = Before(rsSource, pszDelimiter);
// Remove the parameter and delimiter from the original string
rsSource = After(rsSource, sParam + pszDelimiter);
if ( !sParam.IsEmpty() )
break;
}
return sParam;
}
// return pos of next none white space char, starting at nPos
NGLIB_EXT_API int FindNoneWhiteSpace(LPCTSTR pszData, int nPos)
{
if (NULL == pszData)
{
return -1;
}
while (_T('\0') != pszData[nPos])
{
if (!_istspace(pszData[nPos]))
{
break;
}
nPos++;
}
if (_T('\0') == pszData[nPos])
{
nPos = -1;
}
return nPos;
}
// Strip trailing decimal points from numeric strings
// NOTE: NOT EXPORTED (implementation only)
void StripPeriod(CString& sTarget)
{
if (_T(".") == sTarget.Right(1))
sTarget = Before(sTarget, _T("."));
}
// Convert int to CString
NGLIB_EXT_API CString IntToStr(int i)
{
char cTemp[15];
CString sResult = itoa(i, cTemp, 10);
StripPeriod(sResult);
return sResult;
}
// Convert long to CString
NGLIB_EXT_API CString IntToStr(long i)
{
char cTemp[15];
CString sResult = ltoa(i, cTemp, 10);
StripPeriod(sResult);
return (sResult);
}
// Convert unsigned integer to CString
NGLIB_EXT_API CString UIntToStr(unsigned int i)
{
unsigned long lVal = (unsigned long) i;
return (UIntToStr(lVal));
}
// Convert unsigned long (i.e. DWORD) to CString
NGLIB_EXT_API CString UIntToStr(unsigned long i)
{
char cTemp[15];
CString sResult = ultoa(i, cTemp, 10);
StripPeriod(sResult);
return (sResult);
}
// Convert unsigned integer to Hex CString
NGLIB_EXT_API CString HexUIntToStr(unsigned int i, int nMinWidth /* = 0 */)
{
unsigned long lVal = (unsigned long) i;
return (HexUIntToStr(lVal, nMinWidth));
}
// Convert unsigned long (i.e. DWORD) to Hex CString
NGLIB_EXT_API CString HexUIntToStr(unsigned long i, int nMinWidth /* = 0 */)
{
char cTemp[15];
CString sResult = ultoa(i, cTemp, 16);
StripPeriod(sResult);
sResult.MakeUpper();
int nPadChars = nMinWidth - sResult.GetLength() - 2;
if (nPadChars > 0)
sResult = CString('0', nPadChars) + sResult;
return ("0x" + sResult);
}
// Convert double to CString
NGLIB_EXT_API CString FloatToStr(double f, int nDigits /*= 15 */)
{
char buffer[50]; // Reserve space for up to 50 chars
if (_gcvt(f, nDigits, buffer))
{
CString sResult = buffer;
StripPeriod(sResult);
return (sResult);
}
else
return ("");
}
// Convert float to CString
NGLIB_EXT_API CString FloatToStr(float f, int nDigits /*= 7 */)
{
return (FloatToStr((double) f, nDigits));
}
NGLIB_EXT_API BOOL IsNumeric(LPCTSTR pszValue, double* pdValue /*= NULL*/)
{
double dValue = 0;
if (pszValue != NULL)
{
while ( (*pszValue == _T(' ')) || (*pszValue == _T('\t') ) )
{
pszValue++; // Eat leading white space
}
TCHAR chFirst = pszValue[0];
dValue = _tcstod(pszValue, (TCHAR**)&pszValue);
if ( (dValue == 0.0) && (chFirst != _T('0') ) )
{
return FALSE; // could not convert
}
while ( (*pszValue == _T(' ')) || (*pszValue == _T('\t') ) )
{
pszValue++;
}
if (*pszValue != _T('\0') )
{
return FALSE; // not terminated properly
}
if (pdValue != NULL)
{
*pdValue = dValue;
}
return TRUE;
}
return FALSE;
}
NGLIB_EXT_API BOOL IsEven(int n)
{
return ( 2*(n/2) == n);
}
NGLIB_EXT_API BOOL IsOdd(int n)
{
return !IsEven(n);
}
/*****************************************************************************
* Rounding functions
*****************************************************************************/
// This function will round a number upwards if it's modulus is greater
// than or equal to 0.5 or round it down if it is less than 0.5
NGLIB_EXT_API double Round(double dVal)
{
double dRemainder = fabs(fmod(dVal, 1) * (int)10);
if (dVal > 0)
{
if (dRemainder >= (int)5)
return ceil(dVal);
return floor(dVal);
}
if (dRemainder >= (int)5) // Negative numbers require special treatment
return floor(dVal);
return ceil(dVal);
}
// Round to a specified number of decimal places
NGLIB_EXT_API double Round(double dVal, UINT nDecPlaces)
{
double dFactor = pow(10.0, (double)nDecPlaces);
return ( Round( dVal * dFactor) / dFactor);
}
// Retrieves the name of this PC
NGLIB_EXT_API CString GetComputerName(void)
{
DWORD dwSize = _MAX_PATH;
CString sName;
LPTSTR pszBuffer = sName.GetBuffer(dwSize);
if (::GetComputerName(pszBuffer, &dwSize))
{
sName.ReleaseBuffer();
return sName;
}
return _T("");
}
// Retrieves the name of the currently logged on user
NGLIB_EXT_API CString GetUserName(void)
{
DWORD dwSize = UNLEN + 1;
CString sUserName;
LPTSTR pszBuffer = sUserName.GetBuffer(dwSize);
if (::GetUserName(pszBuffer, &dwSize))
{
sUserName.ReleaseBuffer();
return sUserName;
}
return _T("");
}
// Retrieves the resolution of the screen, in pixels
NGLIB_EXT_API CSize GetDisplayResolution(void)
{
ASSERT(NULL != AfxGetMainWnd());
CClientDC dc(AfxGetMainWnd());
return CSize(dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES) );
}
// Retrieves the SIZE of the screen, in mm
NGLIB_EXT_API CSize GetDisplaySize(void)
{
ASSERT(NULL != AfxGetMainWnd());
CClientDC dc(AfxGetMainWnd());
return CSize(dc.GetDeviceCaps(HORZSIZE), dc.GetDeviceCaps(VERTSIZE) );
}
// Return colour depth in bits
NGLIB_EXT_API int GetColourDepth(void)
{
int nDepth = -1;
HDC hdc = ::GetDC(NULL);
if (hdc != NULL)
{
nDepth = ::GetDeviceCaps(hdc, BITSPIXEL);
::ReleaseDC(NULL, hdc);
}
return nDepth;
}
// Return TRUE if screen deivce supports 256 colors or better
NGLIB_EXT_API BOOL Is256ColorSupported(void)
{
BOOL bRetval = FALSE;
HDC hdc = ::GetDC(NULL);
if (hdc != NULL)
{
if (::GetDeviceCaps(hdc, BITSPIXEL) >= 8)
{
bRetval = TRUE;
}
::ReleaseDC(NULL, hdc);
}
return bRetval;
}
NGLIB_EXT_API BOOL FileExists(const CString& sFileName)
{
CFile f;
CFileException e;
BOOL bExists = f.Open( sFileName,
CFile::modeRead |
CFile::shareDenyNone,
&e);
if (bExists)
{
f.Close();
}
return bExists;
}
NGLIB_EXT_API BOOL FolderExists(const CString& sDirName)
{
return (::GetFileAttributes(sDirName) == FILE_ATTRIBUTE_DIRECTORY);
}
// This function does the same thing as PathCombine() in Shlwapi.dll but using CStrings
NGLIB_EXT_API CString CombinePath(const CString& sFolder,
const CString& sRelativePath)
{
CString sResult = sFolder;
sResult.TrimRight( _T("\\") );
int nFolderEnd = -1;
int nPathStart = 0;
while (TRUE)
{
if (sRelativePath.Mid(nPathStart, 3) == _T("..\\") )
{
// For each leading "..\", strip a folder from sFolder
nPathStart +=3;
nFolderEnd = sResult.ReverseFind( _T('\\') );
sResult = sResult.Left(nFolderEnd);
}
else if (sRelativePath.Mid(nPathStart, 2) == _T(".\\") )
{
// Just ignore .\ as a starting folder
nPathStart+=2;
}
else
{
break;
}
}
if (sRelativePath.GetLength() > nPathStart)
{
sResult += _T("\\") + sRelativePath.Mid(nPathStart);
}
#ifdef _VERIFY_PATHCOMBINE
// Test against the value returned by shlwapi's PathCombine()
CString sPathCombineResult;
LPTSTR pszBuffer = sPathCombineResult.GetBuffer(_MAX_PATH);
::PathCombine( pszBuffer,
sFolder,
sRelativePath);
sPathCombineResult.ReleaseBuffer();
ASSERT(sPathCombineResult == sResult);
#endif
return sResult;
}
NGLIB_EXT_API int LoadRtfString(HMODULE hInst,
UINT nID,
LPTSTR lpszBuf,
UINT nMaxBuf)
{
DWORD dwSize = 0;
// Load text into display
HRSRC hInfo = ::FindResource(hInst, MAKEINTRESOURCE(nID), _T("RTF"));
if (hInfo != NULL)
{
HGLOBAL hInfoMem = ::LoadResource(hInst, hInfo);
dwSize = ::SizeofResource(hInst, hInfo);
if (dwSize <= (DWORD)nMaxBuf * sizeof(TCHAR) )
{
LPBYTE pData = (LPBYTE)::LockResource(hInfoMem);
memcpy( (LPVOID)lpszBuf, (LPVOID)pData, dwSize);
}
else
{
dwSize = 0;
}
}
return (int)dwSize;
}
// Taken from AfxLoadString()
NGLIB_EXT_API int LoadRtfString(UINT nID,
LPTSTR lpszBuf,
UINT nMaxBuf)
{
ASSERT(AfxIsValidAddress(lpszBuf, nMaxBuf*sizeof(TCHAR)));
LPCTSTR lpszName = MAKEINTRESOURCE(nID);
HINSTANCE hInst;
int nLen;
// first check the main module state
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
if (!pModuleState->m_bSystem)
{
hInst = AfxGetResourceHandle();
if (::FindResource(hInst, lpszName, _T("RTF")) != NULL &&
(nLen = ::LoadRtfString(hInst, nID, lpszBuf, nMaxBuf)) != 0)
{
// found a non-zero string in app
return nLen;
}
}
// check non-system DLLs in proper order
AfxLockGlobals(CRIT_DYNLINKLIST);
for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
pDLL = pDLL->m_pNextDLL)
{
if (!pDLL->m_bSystem && (hInst = pDLL->m_hResource) != NULL &&
::FindResource(hInst, lpszName, _T("RTF")) != NULL &&
(nLen = ::LoadRtfString(hInst, nID, lpszBuf, nMaxBuf)) != 0)
{
AfxUnlockGlobals(CRIT_DYNLINKLIST);
return nLen;
}
}
AfxUnlockGlobals(CRIT_DYNLINKLIST);
// check language specific DLL next
hInst = pModuleState->m_appLangDLL;
if (hInst != NULL && ::FindResource(hInst, lpszName, _T("RTF")) != NULL &&
(nLen = ::LoadRtfString(hInst, nID, lpszBuf, nMaxBuf)) != 0)
{
// found a non-zero string in language DLL
return nLen;
}
// check the system module state
if (pModuleState->m_bSystem)
{
hInst = AfxGetResourceHandle();
if (::FindResource(hInst, lpszName, _T("RTF")) != NULL &&
(nLen = ::LoadRtfString(hInst, nID, lpszBuf, nMaxBuf)) != 0)
{
// found a non-zero string in app
return nLen;
}
}
// check system DLLs in proper order
AfxLockGlobals(CRIT_DYNLINKLIST);
for (pDLL = pModuleState->m_libraryList; pDLL != NULL; pDLL = pDLL->m_pNextDLL)
{
if (pDLL->m_bSystem && (hInst = pDLL->m_hResource) != NULL &&
::FindResource(hInst, lpszName, _T("RTF")) != NULL &&
(nLen = ::LoadRtfString(hInst, nID, lpszBuf, nMaxBuf)) != 0)
{
AfxUnlockGlobals(CRIT_DYNLINKLIST);
return nLen;
}
}
AfxUnlockGlobals(CRIT_DYNLINKLIST);
// did not find it
lpszBuf[0] = '\0';
return 0;
}
NGLIB_EXT_API CString LoadRtfString(UINT uID)
{
CString sText;
int nMaxBuf = 16384; // Pick a number, any number
LPTSTR pszText = sText.GetBuffer(nMaxBuf);
int nCount = ::LoadRtfString(uID, pszText, nMaxBuf);
sText.ReleaseBuffer(nCount);
return sText;
}