mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1649 lines
36 KiB
1649 lines
36 KiB
//
|
|
// Copyright (c) Microsoft Corporation 1993-1995
|
|
//
|
|
// rovcomm.c
|
|
//
|
|
// This files contains common utility and helper functions.
|
|
//
|
|
// History:
|
|
// 08-06-93 ScottH Transferred from twin code
|
|
// 04-26-95 ScottH Transferred and expanded from Briefcase code
|
|
// 09-21-95 ScottH Ported to NT
|
|
//
|
|
|
|
|
|
#include "proj.h"
|
|
#include "rovcomm.h"
|
|
|
|
#include <debugmem.h>
|
|
|
|
|
|
extern CHAR const FAR c_szNewline[];
|
|
|
|
#define DEBUG_PRINT_BUFFER_LEN 1030
|
|
|
|
#ifdef WINNT
|
|
|
|
//
|
|
// These are some helper functions for handling Unicode strings
|
|
//
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: This function converts a wide-char string to a multi-byte
|
|
string.
|
|
|
|
If pszBuf is non-NULL and the converted string can fit in
|
|
pszBuf, then *ppszAnsi will point to the given buffer.
|
|
Otherwise, this function will allocate a buffer that can
|
|
hold the converted string.
|
|
|
|
If pszWide is NULL, then *ppszAnsi will be freed. Note
|
|
that pszBuf must be the same pointer between the call
|
|
that converted the string and the call that frees the
|
|
string.
|
|
|
|
Returns: TRUE
|
|
FALSE (if out of memory)
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC AnsiFromUnicode(
|
|
LPSTR * ppszAnsi,
|
|
LPCWSTR pwszWide, // NULL to clean up
|
|
LPSTR pszBuf,
|
|
int cchBuf)
|
|
{
|
|
BOOL bRet;
|
|
|
|
// Convert the string?
|
|
if (pwszWide)
|
|
{
|
|
// Yes; determine the converted string length
|
|
int cch;
|
|
LPSTR psz;
|
|
|
|
cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, NULL, 0, NULL, NULL);
|
|
|
|
// String too big, or is there no buffer?
|
|
if (cch > cchBuf || NULL == pszBuf)
|
|
{
|
|
// Yes; allocate space
|
|
cchBuf = cch + 1;
|
|
psz = (LPSTR)ALLOCATE_MEMORY( CbFromCchA(cchBuf));
|
|
}
|
|
else
|
|
{
|
|
// No; use the provided buffer
|
|
ASSERT(pszBuf);
|
|
psz = pszBuf;
|
|
}
|
|
|
|
if (psz)
|
|
{
|
|
// Convert the string
|
|
cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, psz, cchBuf, NULL, NULL);
|
|
bRet = (0 < cch);
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
*ppszAnsi = psz;
|
|
}
|
|
else
|
|
{
|
|
// No; was this buffer allocated?
|
|
if (*ppszAnsi && pszBuf != *ppszAnsi)
|
|
{
|
|
// Yes; clean up
|
|
FREE_MEMORY(*ppszAnsi);
|
|
*ppszAnsi = NULL;
|
|
}
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: This function converts a multi-byte string to a
|
|
wide-char string.
|
|
|
|
If pszBuf is non-NULL and the converted string can fit in
|
|
pszBuf, then *ppszWide will point to the given buffer.
|
|
Otherwise, this function will allocate a buffer that can
|
|
hold the converted string.
|
|
|
|
If pszAnsi is NULL, then *ppszWide will be freed. Note
|
|
that pszBuf must be the same pointer between the call
|
|
that converted the string and the call that frees the
|
|
string.
|
|
|
|
Returns: TRUE
|
|
FALSE (if out of memory)
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC UnicodeFromAnsi(
|
|
LPWSTR * ppwszWide,
|
|
LPCSTR pszAnsi, // NULL to clean up
|
|
LPWSTR pwszBuf,
|
|
int cchBuf)
|
|
{
|
|
BOOL bRet;
|
|
|
|
// Convert the string?
|
|
if (pszAnsi)
|
|
{
|
|
// Yes; determine the converted string length
|
|
int cch;
|
|
LPWSTR pwsz;
|
|
int cchAnsi = lstrlenA(pszAnsi)+1;
|
|
|
|
cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, NULL, 0);
|
|
|
|
// String too big, or is there no buffer?
|
|
if (cch > cchBuf || NULL == pwszBuf)
|
|
{
|
|
// Yes; allocate space
|
|
cchBuf = cch + 1;
|
|
pwsz = (LPWSTR)ALLOCATE_MEMORY( CbFromCchW(cchBuf));
|
|
}
|
|
else
|
|
{
|
|
// No; use the provided buffer
|
|
ASSERT(pwszBuf);
|
|
pwsz = pwszBuf;
|
|
}
|
|
|
|
if (pwsz)
|
|
{
|
|
// Convert the string
|
|
cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, pwsz, cchBuf);
|
|
bRet = (0 < cch);
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
*ppwszWide = pwsz;
|
|
}
|
|
else
|
|
{
|
|
// No; was this buffer allocated?
|
|
if (*ppwszWide && pwszBuf != *ppwszWide)
|
|
{
|
|
// Yes; clean up
|
|
FREE_MEMORY(*ppwszWide);
|
|
*ppwszWide = NULL;
|
|
}
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
#endif // WINNT
|
|
|
|
|
|
#ifndef NOSTRING
|
|
// WARNING: all of these APIs do not setup DS, so you can not access
|
|
// any data in the default data seg of this DLL.
|
|
//
|
|
// do not create any global variables... talk to chrisg if you don't
|
|
// understand this
|
|
|
|
//#define STDCALL
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Case sensitive character comparison for DBCS
|
|
|
|
Returns: FALSE if they match, TRUE if no match
|
|
Cond: --
|
|
*/
|
|
BOOL NEAR ChrCmp(
|
|
WORD w1,
|
|
WORD wMatch)
|
|
{
|
|
/* Most of the time this won't match, so test it first for speed.
|
|
*/
|
|
if (LOBYTE(w1) == LOBYTE(wMatch))
|
|
{
|
|
if (IsDBCSLeadByte(LOBYTE(w1)))
|
|
{
|
|
return(w1 != wMatch);
|
|
}
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Case insensitive character comparison for DBCS
|
|
|
|
Returns: FALSE if match, TRUE if not
|
|
Cond: --
|
|
*/
|
|
BOOL NEAR ChrCmpI(
|
|
WORD w1,
|
|
WORD wMatch)
|
|
{
|
|
CHAR sz1[3], sz2[3];
|
|
|
|
if (IsDBCSLeadByte(sz1[0] = LOBYTE(w1)))
|
|
{
|
|
sz1[1] = HIBYTE(w1);
|
|
sz1[2] = '\0';
|
|
}
|
|
else
|
|
sz1[1] = '\0';
|
|
|
|
*(WORD FAR *)sz2 = wMatch;
|
|
sz2[2] = '\0';
|
|
return lstrcmpiA(sz1, sz2);
|
|
}
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: strnicmp
|
|
|
|
Swiped from the C 7.0 runtime sources.
|
|
|
|
Returns:
|
|
Cond:
|
|
*/
|
|
int PUBLIC lstrnicmp(
|
|
LPCSTR psz1,
|
|
LPCSTR psz2,
|
|
UINT count)
|
|
{
|
|
int ch1;
|
|
int ch2;
|
|
int result = 0;
|
|
|
|
if (count)
|
|
{
|
|
do
|
|
{
|
|
ch1 = (int)LOWORD(AnsiLower((LPSTR)MAKELONG(*psz1, 0)));
|
|
ch2 = (int)LOWORD(AnsiLower((LPSTR)MAKELONG(*psz2, 0)));
|
|
psz1 = AnsiNext(psz1);
|
|
psz2 = AnsiNext(psz2);
|
|
} while (--count && ch1 && ch2 && !ChrCmp((WORD)ch1, (WORD)ch2));
|
|
result = ch1 - ch2;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: strncmp
|
|
|
|
Swiped from the C 7.0 runtime sources.
|
|
|
|
Returns:
|
|
Cond:
|
|
*/
|
|
int PUBLIC lstrncmp(
|
|
LPCSTR psz1,
|
|
LPCSTR psz2,
|
|
UINT count)
|
|
{
|
|
int ch1;
|
|
int ch2;
|
|
int result = 0;
|
|
|
|
if (count)
|
|
{
|
|
do
|
|
{
|
|
ch1 = (int)*psz1;
|
|
ch2 = (int)*psz2;
|
|
psz1 = AnsiNext(psz1);
|
|
psz2 = AnsiNext(psz2);
|
|
} while (--count && ch1 && ch2 && !ChrCmp((WORD)ch1, (WORD)ch2));
|
|
result = ch1 - ch2;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
#endif // WIN32
|
|
|
|
|
|
#ifdef WINNT
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char wrapper for AnsiToIntA.
|
|
|
|
Returns: see AnsiToIntA
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC AnsiToIntW(
|
|
LPCWSTR pwszString,
|
|
int FAR * piRet)
|
|
{
|
|
CHAR szBuf[MAX_BUF];
|
|
LPSTR pszString;
|
|
BOOL bRet;
|
|
|
|
pszString = NULL;
|
|
bRet = AnsiFromUnicode(&pszString, pwszString, szBuf, ARRAYSIZE(szBuf));
|
|
|
|
if (bRet)
|
|
{
|
|
if (pszString == NULL)
|
|
{
|
|
bRet = FALSE;
|
|
} else
|
|
{
|
|
bRet = AnsiToIntA(pszString, piRet);
|
|
AnsiFromUnicode(&pszString, NULL, szBuf, 0);
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char wrapper for AnsiChrA.
|
|
|
|
Returns: see AnsiChrA
|
|
Cond: --
|
|
*/
|
|
LPWSTR PUBLIC AnsiChrW(
|
|
LPCWSTR pwsz,
|
|
WORD wMatch)
|
|
{
|
|
for ( ; *pwsz; pwsz = CharNextW(pwsz))
|
|
{
|
|
if (!ChrCmp(*(WORD FAR *)pwsz, wMatch))
|
|
return (LPWSTR)pwsz;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#endif // WINNT
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Find last occurrence (case sensitive) of wide
|
|
character in wide-char string.
|
|
|
|
Returns: Pointer to the last occurrence of character in
|
|
string or NULL if character is not found.
|
|
Cond: --
|
|
*/
|
|
LPWSTR
|
|
PUBLIC
|
|
AnsiRChrW(
|
|
LPCWSTR pwsz,
|
|
WORD wMatch)
|
|
{
|
|
LPWSTR pwszEnd;
|
|
|
|
if (pwsz && *pwsz)
|
|
{
|
|
for (pwszEnd = (LPWSTR)pwsz + lstrlen(pwsz) - 1;
|
|
pwsz <= pwszEnd;
|
|
pwszEnd = CharPrevW(pwsz, pwszEnd))
|
|
{
|
|
if (!ChrCmp(*(WORD FAR *)pwszEnd, wMatch))
|
|
return(pwszEnd);
|
|
|
|
// CharPrevW() won't go to char preceding pwsz...
|
|
if (pwsz == pwszEnd)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: My verion of atoi. Supports hexadecimal too.
|
|
|
|
If this function returns FALSE, *piRet is set to 0.
|
|
|
|
Returns: TRUE if the string is a number, or contains a partial number
|
|
FALSE if the string is not a number
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC AnsiToIntA(
|
|
LPCSTR pszString,
|
|
int FAR * piRet)
|
|
{
|
|
#define IS_DIGIT(ch) InRange(ch, '0', '9')
|
|
|
|
BOOL bRet;
|
|
int n;
|
|
BOOL bNeg = FALSE;
|
|
LPCSTR psz;
|
|
LPCSTR pszAdj;
|
|
|
|
// Skip leading whitespace
|
|
//
|
|
for (psz = pszString; *psz == ' ' || *psz == '\n' || *psz == '\t'; psz = AnsiNext(psz))
|
|
;
|
|
|
|
// Determine possible explicit signage
|
|
//
|
|
if (*psz == '+' || *psz == '-')
|
|
{
|
|
bNeg = (*psz == '+') ? FALSE : TRUE;
|
|
psz++;
|
|
}
|
|
|
|
// Or is this hexadecimal?
|
|
//
|
|
pszAdj = AnsiNext(psz);
|
|
if (*psz == '0' && (*pszAdj == 'x' || *pszAdj == 'X'))
|
|
{
|
|
// Yes
|
|
|
|
// (Never allow negative sign with hexadecimal numbers)
|
|
bNeg = FALSE;
|
|
psz = AnsiNext(pszAdj);
|
|
|
|
pszAdj = psz;
|
|
|
|
// Do the conversion
|
|
//
|
|
for (n = 0; ; psz = AnsiNext(psz))
|
|
{
|
|
if (IS_DIGIT(*psz))
|
|
n = 0x10 * n + *psz - '0';
|
|
else
|
|
{
|
|
CHAR ch = *psz;
|
|
int n2;
|
|
|
|
if (ch >= 'a')
|
|
ch -= 'a' - 'A';
|
|
|
|
n2 = ch - 'A' + 0xA;
|
|
if (n2 >= 0xA && n2 <= 0xF)
|
|
n = 0x10 * n + n2;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return TRUE if there was at least one digit
|
|
bRet = (psz != pszAdj);
|
|
}
|
|
else
|
|
{
|
|
// No
|
|
pszAdj = psz;
|
|
|
|
// Do the conversion
|
|
for (n = 0; IS_DIGIT(*psz); psz = AnsiNext(psz))
|
|
n = 10 * n + *psz - '0';
|
|
|
|
// Return TRUE if there was at least one digit
|
|
bRet = (psz != pszAdj);
|
|
}
|
|
|
|
*piRet = bNeg ? -n : n;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Find first occurrence of character in string
|
|
|
|
Returns: Pointer to the first occurrence of ch in
|
|
Cond: --
|
|
*/
|
|
LPSTR PUBLIC AnsiChrA(
|
|
LPCSTR psz,
|
|
WORD wMatch)
|
|
{
|
|
for ( ; *psz; psz = AnsiNext(psz))
|
|
{
|
|
if (!ChrCmp(*(WORD FAR *)psz, wMatch))
|
|
return (LPSTR)psz;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#endif // NOSTRING
|
|
|
|
|
|
#ifndef NODIALOGHELPER
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Sets the rectangle with the bounding extent of the given string.
|
|
Returns: Rectangle
|
|
Cond: --
|
|
*/
|
|
void PUBLIC SetRectFromExtentW(
|
|
HDC hdc,
|
|
LPRECT lprect,
|
|
LPCWSTR lpcwsz)
|
|
{
|
|
SIZE size;
|
|
|
|
GetTextExtentPointW(hdc, lpcwsz, lstrlenW(lpcwsz), &size);
|
|
SetRect(lprect, 0, 0, size.cx, size.cy);
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Sets the rectangle with the bounding extent of the given string.
|
|
Returns: Rectangle
|
|
Cond: --
|
|
*/
|
|
void PUBLIC SetRectFromExtentA(
|
|
HDC hdc,
|
|
LPRECT lprect,
|
|
LPCSTR lpcsz)
|
|
{
|
|
SIZE size;
|
|
|
|
GetTextExtentPointA(hdc, lpcsz, lstrlenA(lpcsz), &size);
|
|
SetRect(lprect, 0, 0, size.cx, size.cy);
|
|
}
|
|
|
|
#endif // NODIALOGHELPER
|
|
|
|
|
|
#ifndef NODRAWTEXT
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
|
|
CHAR const FAR c_szEllipses[] = "...";
|
|
|
|
#pragma data_seg()
|
|
|
|
// Global variables
|
|
int g_cxLabelMargin = 0;
|
|
int g_cxBorder = 0;
|
|
int g_cyBorder = 0;
|
|
|
|
COLORREF g_clrHighlightText = 0;
|
|
COLORREF g_clrHighlight = 0;
|
|
COLORREF g_clrWindowText = 0;
|
|
COLORREF g_clrWindow = 0;
|
|
|
|
HBRUSH g_hbrHighlight = 0;
|
|
HBRUSH g_hbrWindow = 0;
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Get the system metrics we need
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC GetCommonMetrics(
|
|
WPARAM wParam) // wParam from WM_WININICHANGE
|
|
{
|
|
if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
|
|
{
|
|
g_cxBorder = GetSystemMetrics(SM_CXBORDER);
|
|
g_cyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
|
|
g_cxLabelMargin = (g_cxBorder * 2);
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Sees whether the entire string will fit in *prc.
|
|
If not, compute the numbder of chars that will fit
|
|
(including ellipses). Returns length of string in
|
|
*pcchDraw.
|
|
|
|
Taken from COMMCTRL.
|
|
|
|
Returns: TRUE if the string needed ellipses
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE NeedsEllipses(
|
|
HDC hdc,
|
|
LPCSTR pszText,
|
|
RECT * prc,
|
|
int * pcchDraw,
|
|
int cxEllipses)
|
|
{
|
|
int cchText;
|
|
int cxRect;
|
|
int ichMin, ichMax, ichMid;
|
|
SIZE siz;
|
|
|
|
cxRect = prc->right - prc->left;
|
|
|
|
cchText = lstrlenA(pszText);
|
|
|
|
if (cchText == 0)
|
|
{
|
|
*pcchDraw = cchText;
|
|
return FALSE;
|
|
}
|
|
|
|
GetTextExtentPointA(hdc, pszText, cchText, &siz);
|
|
|
|
if (siz.cx <= cxRect)
|
|
{
|
|
*pcchDraw = cchText;
|
|
return FALSE;
|
|
}
|
|
|
|
cxRect -= cxEllipses;
|
|
|
|
// If no room for ellipses, always show first character.
|
|
//
|
|
ichMax = 1;
|
|
if (cxRect > 0)
|
|
{
|
|
// Binary search to find character that will fit
|
|
ichMin = 0;
|
|
ichMax = cchText;
|
|
while (ichMin < ichMax)
|
|
{
|
|
// Be sure to round up, to make sure we make progress in
|
|
// the loop if ichMax == ichMin + 1.
|
|
//
|
|
ichMid = (ichMin + ichMax + 1) / 2;
|
|
|
|
GetTextExtentPointA(hdc, &pszText[ichMin], ichMid - ichMin, &siz);
|
|
|
|
if (siz.cx < cxRect)
|
|
{
|
|
ichMin = ichMid;
|
|
cxRect -= siz.cx;
|
|
}
|
|
else if (siz.cx > cxRect)
|
|
{
|
|
ichMax = ichMid - 1;
|
|
}
|
|
else
|
|
{
|
|
// Exact match up up to ichMid: just exit.
|
|
//
|
|
ichMax = ichMid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Make sure we always show at least the first character...
|
|
//
|
|
if (ichMax < 1)
|
|
ichMax = 1;
|
|
}
|
|
|
|
*pcchDraw = ichMax;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define CCHELLIPSES 3
|
|
#define DT_LVWRAP (DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_EDITCONTROL)
|
|
|
|
|
|
#ifdef WINNT
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char wrapper for MyDrawTextA.
|
|
|
|
Returns: see MyDrawTextA
|
|
Cond: --
|
|
*/
|
|
void PUBLIC MyDrawTextW(
|
|
HDC hdc,
|
|
LPCWSTR pwszText,
|
|
RECT FAR* prc,
|
|
UINT flags,
|
|
int cyChar,
|
|
int cxEllipses,
|
|
COLORREF clrText,
|
|
COLORREF clrTextBk)
|
|
{
|
|
CHAR szBuf[MAX_BUF];
|
|
LPSTR pszText;
|
|
BOOL bRet;
|
|
|
|
pszText = NULL;
|
|
bRet = AnsiFromUnicode(&pszText, pwszText, szBuf, ARRAYSIZE(szBuf));
|
|
|
|
if (bRet)
|
|
{
|
|
MyDrawTextA(hdc, pszText, prc, flags, cyChar, cxEllipses, clrText, clrTextBk);
|
|
AnsiFromUnicode(&pszText, NULL, szBuf, 0);
|
|
}
|
|
}
|
|
|
|
#endif // WINNT
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Draws text the shell's way.
|
|
|
|
Taken from COMMCTRL.
|
|
|
|
Returns: --
|
|
|
|
Cond: This function requires TRANSPARENT background mode
|
|
and a properly selected font.
|
|
*/
|
|
void PUBLIC MyDrawTextA(
|
|
HDC hdc,
|
|
LPCSTR pszText,
|
|
RECT FAR* prc,
|
|
UINT flags,
|
|
int cyChar,
|
|
int cxEllipses,
|
|
COLORREF clrText,
|
|
COLORREF clrTextBk)
|
|
{
|
|
int cchText;
|
|
COLORREF clrSave;
|
|
COLORREF clrSaveBk;
|
|
UINT uETOFlags = 0;
|
|
RECT rc;
|
|
CHAR ach[MAX_PATH + CCHELLIPSES];
|
|
|
|
// REVIEW: Performance idea:
|
|
// We could cache the currently selected text color
|
|
// so we don't have to set and restore it each time
|
|
// when the color is the same.
|
|
//
|
|
if (!pszText)
|
|
return;
|
|
|
|
rc = *prc;
|
|
|
|
// If needed, add in a little extra margin...
|
|
//
|
|
if (IsFlagSet(flags, MDT_EXTRAMARGIN))
|
|
{
|
|
rc.left += g_cxLabelMargin * 3;
|
|
rc.right -= g_cxLabelMargin * 3;
|
|
}
|
|
else
|
|
{
|
|
rc.left += g_cxLabelMargin;
|
|
rc.right -= g_cxLabelMargin;
|
|
}
|
|
|
|
if (IsFlagSet(flags, MDT_ELLIPSES) &&
|
|
NeedsEllipses(hdc, pszText, &rc, &cchText, cxEllipses))
|
|
{
|
|
hmemcpy(ach, pszText, cchText);
|
|
lstrcpyA(ach + cchText, c_szEllipses);
|
|
|
|
pszText = ach;
|
|
|
|
// Left-justify, in case there's no room for all of ellipses
|
|
//
|
|
ClearFlag(flags, (MDT_RIGHT | MDT_CENTER));
|
|
SetFlag(flags, MDT_LEFT);
|
|
|
|
cchText += CCHELLIPSES;
|
|
}
|
|
else
|
|
{
|
|
cchText = lstrlenA(pszText);
|
|
}
|
|
|
|
if (IsFlagSet(flags, MDT_TRANSPARENT))
|
|
{
|
|
clrSave = SetTextColor(hdc, 0x000000);
|
|
}
|
|
else
|
|
{
|
|
uETOFlags |= ETO_OPAQUE;
|
|
|
|
if (IsFlagSet(flags, MDT_SELECTED))
|
|
{
|
|
clrSave = SetTextColor(hdc, g_clrHighlightText);
|
|
clrSaveBk = SetBkColor(hdc, g_clrHighlight);
|
|
|
|
if (IsFlagSet(flags, MDT_DRAWTEXT))
|
|
{
|
|
FillRect(hdc, prc, g_hbrHighlight);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (clrText == CLR_DEFAULT && clrTextBk == CLR_DEFAULT)
|
|
{
|
|
clrSave = SetTextColor(hdc, g_clrWindowText);
|
|
clrSaveBk = SetBkColor(hdc, g_clrWindow);
|
|
|
|
if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
|
|
{
|
|
FillRect(hdc, prc, g_hbrWindow);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HBRUSH hbr;
|
|
|
|
if (clrText == CLR_DEFAULT)
|
|
clrText = g_clrWindowText;
|
|
|
|
if (clrTextBk == CLR_DEFAULT)
|
|
clrTextBk = g_clrWindow;
|
|
|
|
clrSave = SetTextColor(hdc, clrText);
|
|
clrSaveBk = SetBkColor(hdc, clrTextBk);
|
|
|
|
if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
|
|
{
|
|
hbr = CreateSolidBrush(GetNearestColor(hdc, clrTextBk));
|
|
if (hbr)
|
|
{
|
|
FillRect(hdc, prc, hbr);
|
|
DeleteObject(hbr);
|
|
}
|
|
else
|
|
FillRect(hdc, prc, GetStockObject(WHITE_BRUSH));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we want the item to display as if it was depressed, we will
|
|
// offset the text rectangle down and to the left
|
|
if (IsFlagSet(flags, MDT_DEPRESSED))
|
|
OffsetRect(&rc, g_cxBorder, g_cyBorder);
|
|
|
|
if (IsFlagSet(flags, MDT_DRAWTEXT))
|
|
{
|
|
UINT uDTFlags = DT_LVWRAP;
|
|
|
|
if (IsFlagClear(flags, MDT_CLIPPED))
|
|
uDTFlags |= DT_NOCLIP;
|
|
|
|
DrawTextA(hdc, pszText, cchText, &rc, uDTFlags);
|
|
}
|
|
else
|
|
{
|
|
if (IsFlagClear(flags, MDT_LEFT))
|
|
{
|
|
SIZE siz;
|
|
|
|
GetTextExtentPointA(hdc, pszText, cchText, &siz);
|
|
|
|
if (IsFlagSet(flags, MDT_CENTER))
|
|
rc.left = (rc.left + rc.right - siz.cx) / 2;
|
|
else
|
|
{
|
|
ASSERT(IsFlagSet(flags, MDT_RIGHT));
|
|
rc.left = rc.right - siz.cx;
|
|
}
|
|
}
|
|
|
|
if (IsFlagSet(flags, MDT_VCENTER))
|
|
{
|
|
// Center vertically
|
|
rc.top += (rc.bottom - rc.top - cyChar) / 2;
|
|
}
|
|
|
|
if (IsFlagSet(flags, MDT_CLIPPED))
|
|
uETOFlags |= ETO_CLIPPED;
|
|
|
|
ExtTextOutA(hdc, rc.left, rc.top, uETOFlags, prc, pszText, cchText, NULL);
|
|
}
|
|
|
|
if (flags & (MDT_SELECTED | MDT_DESELECTED | MDT_TRANSPARENT))
|
|
{
|
|
SetTextColor(hdc, clrSave);
|
|
if (IsFlagClear(flags, MDT_TRANSPARENT))
|
|
SetBkColor(hdc, clrSaveBk);
|
|
}
|
|
}
|
|
#endif // NODRAWTEXT
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef NOMESSAGESTRING
|
|
|
|
typedef va_list * LPVA_LIST;
|
|
|
|
|
|
|
|
#ifdef WINNT
|
|
|
|
#define IsPointerResouceId(_p) (((ULONG_PTR)_p) <= 0xffff)
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char version of ConstructVMessageStringA
|
|
|
|
Returns: see ConstructVMessageStringA
|
|
Cond: --
|
|
*/
|
|
LPWSTR PUBLIC ConstructVMessageStringW(
|
|
HINSTANCE hinst,
|
|
LPCWSTR pwszMsg,
|
|
va_list FAR * ArgList)
|
|
{
|
|
WCHAR wszTemp[MAX_BUF];
|
|
LPWSTR pwszRet;
|
|
LPWSTR pwszRes;
|
|
|
|
if (!IsPointerResouceId(pwszMsg)) {
|
|
|
|
pwszRes = (LPWSTR)pwszMsg;
|
|
|
|
} else {
|
|
|
|
if ((((ULONG_PTR)pwszMsg) != 0) && LoadStringW(hinst, (DWORD)(ULONG_PTR)pwszMsg, wszTemp, ARRAYSIZE(wszTemp))) {
|
|
|
|
pwszRes = wszTemp;
|
|
|
|
} else {
|
|
|
|
pwszRes = NULL;
|
|
}
|
|
}
|
|
|
|
if (pwszRes) {
|
|
|
|
if (!FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
|
pwszRes, 0, 0, (LPWSTR)&pwszRet, 0, (LPVA_LIST)ArgList))
|
|
{
|
|
pwszRet = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bad parameter
|
|
pwszRet = NULL;
|
|
}
|
|
|
|
return pwszRet; // free with LocalFree()
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char version of ConstructMessageA.
|
|
|
|
Returns: see ConstructMessageA
|
|
Cond: --
|
|
*/
|
|
BOOL CPUBLIC ConstructMessageW(
|
|
LPWSTR FAR * ppwsz,
|
|
HINSTANCE hinst,
|
|
LPCWSTR pwszMsg, ...)
|
|
{
|
|
BOOL bRet;
|
|
LPWSTR pwszRet;
|
|
va_list ArgList;
|
|
|
|
va_start(ArgList, pwszMsg);
|
|
|
|
pwszRet = ConstructVMessageStringW(hinst, pwszMsg, &ArgList);
|
|
|
|
va_end(ArgList);
|
|
|
|
*ppwsz = NULL;
|
|
|
|
if (pwszRet)
|
|
{
|
|
bRet = SetStringW(ppwsz, pwszRet);
|
|
LocalFree(pwszRet);
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char version of MsgBoxA
|
|
|
|
Returns: See MsgBoxA
|
|
Cond: --
|
|
*/
|
|
int CPUBLIC MsgBoxW(
|
|
HINSTANCE hinst,
|
|
HWND hwndOwner,
|
|
LPCWSTR pwszText,
|
|
LPCWSTR pwszCaption,
|
|
HICON hicon, // May be NULL
|
|
DWORD dwStyle, ...)
|
|
{
|
|
int iRet = -1;
|
|
int ids;
|
|
WCHAR wszCaption[MAX_BUF];
|
|
LPWSTR pwszRet;
|
|
va_list ArgList;
|
|
|
|
va_start(ArgList, dwStyle);
|
|
|
|
pwszRet = ConstructVMessageStringW(hinst, pwszText, &ArgList);
|
|
|
|
va_end(ArgList);
|
|
|
|
if (pwszRet)
|
|
{
|
|
// Is pszCaption a resource ID?
|
|
if (IsPointerResouceId(pwszCaption))
|
|
{
|
|
// Yes; load it
|
|
ids = LOWORD(pwszCaption);
|
|
SzFromIDSW(hinst, ids, wszCaption, ARRAYSIZE(wszCaption));
|
|
pwszCaption = wszCaption;
|
|
}
|
|
|
|
// Invoke dialog
|
|
if (pwszCaption)
|
|
{
|
|
MSGBOXPARAMSW mbp;
|
|
|
|
mbp.cbSize = sizeof(mbp);
|
|
mbp.hwndOwner = hwndOwner;
|
|
mbp.hInstance = hinst;
|
|
mbp.lpszText = pwszRet;
|
|
mbp.lpszCaption = pwszCaption;
|
|
mbp.dwStyle = dwStyle | MB_SETFOREGROUND;
|
|
mbp.lpszIcon = MAKEINTRESOURCEW(hicon);
|
|
mbp.lpfnMsgBoxCallback = NULL;
|
|
mbp.dwLanguageId = LANG_NEUTRAL;
|
|
|
|
iRet = MessageBoxIndirectW(&mbp);
|
|
}
|
|
LocalFree(pwszRet);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
#endif // WINNT
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Load the string (if necessary) and format the string
|
|
properly.
|
|
|
|
Returns: A pointer to the allocated string containing the formatted
|
|
message or
|
|
NULL if out of memory
|
|
|
|
Cond: free pointer with FREE_MEMORY()
|
|
*/
|
|
LPSTR PUBLIC ConstructVMessageStringA(
|
|
HINSTANCE hinst,
|
|
LPCSTR pszMsg,
|
|
va_list FAR * ArgList)
|
|
{
|
|
CHAR szTemp[MAX_BUF];
|
|
LPSTR pszRet;
|
|
LPSTR pszRes;
|
|
|
|
if (!IsPointerResouceId(pszMsg)) {
|
|
|
|
pszRes = (LPSTR)pszMsg;
|
|
|
|
} else {
|
|
|
|
if ((((ULONG_PTR)pszMsg) != 0) && LoadStringA(hinst, (DWORD)(ULONG_PTR)pszMsg, szTemp, ARRAYSIZE(szTemp))) {
|
|
|
|
pszRes = szTemp;
|
|
|
|
} else {
|
|
|
|
pszRes = NULL;
|
|
}
|
|
}
|
|
|
|
if (pszRes)
|
|
{
|
|
if (!FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
|
pszRes, 0, 0, (LPSTR)&pszRet, 0, (LPVA_LIST)ArgList))
|
|
{
|
|
pszRet = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bad parameter
|
|
pszRet = NULL;
|
|
}
|
|
|
|
return pszRet; // free with FREE_MEMORY()
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Constructs a formatted string. The returned string
|
|
must be freed using GFree().
|
|
|
|
Returns: TRUE on success
|
|
|
|
Cond: Free pointer with GFree()
|
|
*/
|
|
BOOL CPUBLIC ConstructMessageA(
|
|
LPSTR FAR * ppsz,
|
|
HINSTANCE hinst,
|
|
LPCSTR pszMsg, ...)
|
|
{
|
|
BOOL bRet;
|
|
LPSTR pszRet;
|
|
va_list ArgList;
|
|
|
|
va_start(ArgList, pszMsg);
|
|
|
|
pszRet = ConstructVMessageStringA(hinst, pszMsg, &ArgList);
|
|
|
|
va_end(ArgList);
|
|
|
|
*ppsz = NULL;
|
|
|
|
if (pszRet)
|
|
{
|
|
bRet = SetStringA(ppsz, pszRet);
|
|
LocalFree(pszRet);
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Invoke a message box.
|
|
|
|
Returns: ID of button that terminated the dialog
|
|
Cond: --
|
|
*/
|
|
int CPUBLIC MsgBoxA(
|
|
HINSTANCE hinst,
|
|
HWND hwndOwner,
|
|
LPCSTR pszText,
|
|
LPCSTR pszCaption,
|
|
HICON hicon, // May be NULL
|
|
DWORD dwStyle, ...)
|
|
{
|
|
int iRet = -1;
|
|
int ids;
|
|
CHAR szCaption[MAX_BUF];
|
|
LPSTR pszRet;
|
|
va_list ArgList;
|
|
|
|
va_start(ArgList, dwStyle);
|
|
|
|
pszRet = ConstructVMessageStringA(hinst, pszText, &ArgList);
|
|
|
|
va_end(ArgList);
|
|
|
|
if (pszRet)
|
|
{
|
|
// Is pszCaption a resource ID?
|
|
if (IsPointerResouceId(pszCaption))
|
|
{
|
|
// Yes; load it
|
|
ids = LOWORD(pszCaption);
|
|
SzFromIDSA(hinst, ids, szCaption, SIZECHARS(szCaption));
|
|
pszCaption = szCaption;
|
|
}
|
|
|
|
// Invoke dialog
|
|
if (pszCaption)
|
|
{
|
|
#ifdef WIN32
|
|
|
|
MSGBOXPARAMSA mbp;
|
|
|
|
mbp.cbSize = sizeof(mbp);
|
|
mbp.hwndOwner = hwndOwner;
|
|
mbp.hInstance = hinst;
|
|
mbp.lpszText = pszRet;
|
|
mbp.lpszCaption = pszCaption;
|
|
mbp.dwStyle = dwStyle | MB_SETFOREGROUND;
|
|
mbp.lpszIcon = MAKEINTRESOURCEA(hicon);
|
|
mbp.lpfnMsgBoxCallback = NULL;
|
|
mbp.dwLanguageId = LANG_NEUTRAL;
|
|
|
|
iRet = MessageBoxIndirectA(&mbp);
|
|
|
|
#else // WIN32
|
|
|
|
iRet = MessageBox(hwndOwner, pszRet, pszCaption, LOWORD(dwStyle));
|
|
#endif
|
|
}
|
|
LocalFree(pszRet);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
#endif // NOMESSAGESTRING
|
|
|
|
|
|
#if !defined(NODEBUGHELP) && defined(DEBUG)
|
|
|
|
// Globals
|
|
DWORD g_dwBreakFlags = 0;
|
|
DWORD g_dwDumpFlags = 0;
|
|
DWORD g_dwTraceFlags = 0;
|
|
LONG g_dwIndent = 0;
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
|
|
#ifdef WINNT
|
|
extern WCHAR const FAR c_wszNewline[];
|
|
extern WCHAR const FAR c_wszTrace[];
|
|
extern WCHAR const FAR c_wszAssertFailed[];
|
|
#endif // WINNT
|
|
|
|
extern CHAR const FAR c_szNewline[];
|
|
extern CHAR const FAR c_szTrace[];
|
|
extern CHAR const FAR c_szAssertFailed[];
|
|
|
|
|
|
#pragma data_seg()
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Return English reason for the debug break
|
|
Returns: String
|
|
Cond: --
|
|
*/
|
|
LPCSTR PRIVATE GetReasonString(
|
|
DWORD flag) // One of BF_ flags
|
|
{
|
|
LPCSTR psz;
|
|
|
|
if (IsFlagSet(flag, BF_ONOPEN))
|
|
psz = "BREAK ON OPEN\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONCLOSE))
|
|
psz = "BREAK ON CLOSE\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONRUNONCE))
|
|
psz = "BREAK ON RUNONCE\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONVALIDATE))
|
|
psz = "BREAK ON VALIDATION FAILURE\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONTHREADATT))
|
|
psz = "BREAK ON THREAD ATTACH\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONTHREADDET))
|
|
psz = "BREAK ON THREAD DETACH\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONPROCESSATT))
|
|
psz = "BREAK ON PROCESS ATTACH\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONPROCESSDET))
|
|
psz = "BREAK ON PROCESS DETACH\r\n";
|
|
|
|
else if (IsFlagSet(flag, BF_ONAPIENTER))
|
|
psz = "BREAK ON API ENTER\r\n";
|
|
|
|
else
|
|
psz = c_szNewline;
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Perform a debug break based on the flag
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC CommonDebugBreak(
|
|
DWORD flag) // One of BF_ flags
|
|
{
|
|
if (IsFlagSet(g_dwBreakFlags, flag))
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, GetReasonString(flag));
|
|
DebugBreak();
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Assert failed
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC CommonAssertFailed(
|
|
LPCSTR pszFile,
|
|
int line)
|
|
{
|
|
LPCSTR psz;
|
|
CHAR ach[256];
|
|
|
|
// Strip off path info from filename string, if present.
|
|
//
|
|
for (psz = pszFile + lstrlenA(pszFile); psz != pszFile; psz=AnsiPrev(pszFile, psz))
|
|
{
|
|
if ((AnsiPrev(pszFile, psz) != (psz-2)) && *(psz - 1) == '\\')
|
|
break;
|
|
}
|
|
wsprintfA(ach, c_szAssertFailed, psz, line);
|
|
OutputDebugStringA(ach);
|
|
|
|
if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
|
|
DebugBreak();
|
|
}
|
|
|
|
|
|
#ifdef WINNT
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Determine id debug should be displayed
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
BOOL WINAPI
|
|
DisplayDebug(
|
|
DWORD flag
|
|
)
|
|
|
|
{
|
|
return (IsFlagSet(g_dwTraceFlags, flag));
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char version of CommonAssertMsgA
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void CPUBLIC CommonAssertMsgW(
|
|
BOOL f,
|
|
LPCWSTR pwszMsg, ...)
|
|
{
|
|
WCHAR ach[DEBUG_PRINT_BUFFER_LEN]; // Largest path plus extra
|
|
va_list vArgs;
|
|
|
|
if (!f)
|
|
{
|
|
int cch;
|
|
|
|
lstrcpyW(ach, c_wszTrace);
|
|
cch = lstrlenW(ach);
|
|
va_start(vArgs, pwszMsg);
|
|
wvsprintfW(&ach[cch], pwszMsg, vArgs);
|
|
va_end(vArgs);
|
|
OutputDebugStringW(ach);
|
|
OutputDebugStringW(c_wszNewline);
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char version of CommonDebugMsgA
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void CPUBLIC CommonDebugMsgW(
|
|
DWORD flag,
|
|
LPCSTR pszMsg, ...)
|
|
{
|
|
WCHAR ach[DEBUG_PRINT_BUFFER_LEN]; // Largest path plus extra
|
|
va_list vArgs;
|
|
DWORD dwLastError = GetLastError (); // Save the last error
|
|
|
|
if (IsFlagSet(g_dwTraceFlags, flag))
|
|
{
|
|
int cch;
|
|
WCHAR wszBuf[MAX_BUF];
|
|
LPWSTR pwsz;
|
|
|
|
WCHAR wszBlank[] = L" ";
|
|
wszBlank[g_dwIndent < 0 ? 0 : g_dwIndent] = L'\0';
|
|
|
|
#ifdef PROFILE_TRACES
|
|
const static WCHAR szTemplate[]=TEXT("[%lu] ");
|
|
static DWORD dwTickLast;
|
|
static DWORD dwTickNow = 0;
|
|
|
|
if (!dwTickNow)
|
|
{
|
|
lstrcpy(szTemplate, TEXT("[%lu] "));
|
|
dwTickLast = GetTickCount();
|
|
}
|
|
dwTickNow = GetTickCount();
|
|
wsprintf(ach, szTemplate, dwTickNow - dwTickLast);
|
|
dwTickLast = dwTickNow;
|
|
|
|
lstrcatW(ach, c_wszTrace);
|
|
#else
|
|
lstrcpyW(ach, c_wszTrace);
|
|
#endif
|
|
lstrcat(ach,wszBlank);
|
|
|
|
cch = lstrlenW(ach);
|
|
va_start(vArgs, pszMsg);
|
|
|
|
// (We convert the string, rather than simply input an
|
|
// LPCWSTR parameter, so the caller doesn't have to wrap
|
|
// all the string constants with the TEXT() macro.)
|
|
|
|
if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, ARRAYSIZE(wszBuf)))
|
|
{
|
|
wvsprintfW(&ach[cch], pwsz, vArgs);
|
|
UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
|
|
}
|
|
|
|
va_end(vArgs);
|
|
OutputDebugStringW(ach);
|
|
OutputDebugStringW(c_wszNewline);
|
|
}
|
|
|
|
SetLastError (dwLastError); // Restore the last error
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Wide-char version of Dbg_SafeStrA
|
|
|
|
Returns: String ptr
|
|
Cond: --
|
|
*/
|
|
LPCWSTR PUBLIC Dbg_SafeStrW(
|
|
LPCWSTR pwsz)
|
|
{
|
|
if (pwsz)
|
|
return pwsz;
|
|
else
|
|
return L"NULL";
|
|
}
|
|
|
|
#endif // WINNT
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Assert failed message only
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void CPUBLIC CommonAssertMsgA(
|
|
BOOL f,
|
|
LPCSTR pszMsg, ...)
|
|
{
|
|
CHAR ach[DEBUG_PRINT_BUFFER_LEN]; // Largest path plus extra
|
|
va_list vArgs;
|
|
|
|
if (!f)
|
|
{
|
|
int cch;
|
|
|
|
lstrcpyA(ach, c_szTrace);
|
|
cch = lstrlenA(ach);
|
|
va_start(vArgs, pszMsg);
|
|
wvsprintfA(&ach[cch], pszMsg, vArgs);
|
|
va_end(vArgs);
|
|
OutputDebugStringA(ach);
|
|
OutputDebugStringA(c_szNewline);
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Debug spew
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void CPUBLIC CommonDebugMsgA(
|
|
DWORD flag,
|
|
LPCSTR pszMsg, ...)
|
|
{
|
|
CHAR ach[DEBUG_PRINT_BUFFER_LEN]; // Largest path plus extra
|
|
va_list vArgs;
|
|
DWORD dwLastError = GetLastError ();
|
|
|
|
if (IsFlagSet(g_dwTraceFlags, flag))
|
|
{
|
|
int cch;
|
|
char szBlank[] = " ";
|
|
|
|
ASSERT( g_dwIndent >= 0);
|
|
szBlank[g_dwIndent < 0 ? 0 : g_dwIndent] = 0;
|
|
|
|
lstrcpyA(ach, c_szTrace);
|
|
|
|
lstrcatA(ach, szBlank);
|
|
|
|
cch = lstrlenA(ach);
|
|
va_start(vArgs, pszMsg);
|
|
wvsprintfA(&ach[cch], pszMsg, vArgs);
|
|
va_end(vArgs);
|
|
OutputDebugStringA(ach);
|
|
OutputDebugStringA(c_szNewline);
|
|
}
|
|
|
|
SetLastError (dwLastError);
|
|
}
|
|
|
|
|
|
#ifdef WANT_OLE_SUPPORT
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns the string form of an known interface ID.
|
|
|
|
Returns: String ptr
|
|
Cond: --
|
|
*/
|
|
LPCSTR PUBLIC Dbg_GetRiidName(
|
|
REFIID riid)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(c_rgriidmap); i++)
|
|
{
|
|
if (IsEqualIID(riid, c_rgriidmap[i].riid))
|
|
return c_rgriidmap[i].psz;
|
|
}
|
|
return "Unknown riid";
|
|
}
|
|
#endif
|
|
|
|
#ifdef __SCODE_H__
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns the string form of an scode given an hresult.
|
|
|
|
Returns: String ptr
|
|
Cond: --
|
|
*/
|
|
LPCSTR PUBLIC Dbg_GetScode(
|
|
HRESULT hres)
|
|
{
|
|
int i;
|
|
SCODE sc;
|
|
|
|
sc = GetScode(hres);
|
|
for (i = 0; i < ARRAYSIZE(c_rgscodemap); i++)
|
|
{
|
|
if (sc == c_rgscodemap[i].sc)
|
|
return c_rgscodemap[i].psz;
|
|
}
|
|
return "Unknown scode";
|
|
}
|
|
|
|
#endif // __SCODE_H__
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns a string safe enough to print...and I don't
|
|
mean swear words.
|
|
|
|
Returns: String ptr
|
|
Cond: --
|
|
*/
|
|
LPCSTR PUBLIC Dbg_SafeStrA(
|
|
LPCSTR psz)
|
|
{
|
|
if (psz)
|
|
return psz;
|
|
else
|
|
return "NULL";
|
|
}
|
|
|
|
#endif // !defined(NODEBUGHELP) && defined(DEBUG)
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Entry-point to handle any necessary initialization
|
|
of the common data structures and functions.
|
|
|
|
Returns: TRUE on success
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC RovComm_Init(
|
|
HINSTANCE hinst)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
#ifndef NODRAWTEXT
|
|
GetCommonMetrics(0);
|
|
#endif
|
|
|
|
|
|
bRet = RovComm_ProcessIniFile();
|
|
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Entry-point to handle termination.
|
|
|
|
Returns: TRUE on success
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC RovComm_Terminate(
|
|
HINSTANCE hinst)
|
|
{
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns TRUE iff user has admin priveleges
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC IsAdminUser(void)
|
|
{
|
|
HKEY hkey;
|
|
|
|
if(RegOpenKeyEx(HKEY_USERS, TEXT(".DEFAULT"), 0, KEY_WRITE, &hkey) == 0)
|
|
{
|
|
RegCloseKey(hkey);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|