Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2255 lines
51 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"
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)LocalAlloc(LPTR, 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
LocalFree((HLOCAL)*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)LocalAlloc(LPTR, 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
LocalFree((HLOCAL)*ppwszWide);
*ppwszWide = NULL;
}
bRet = TRUE;
}
return bRet;
}
#endif // WINNT
#ifdef NORTL
// Some of these are replacements for the C runtime routines.
// This is so we don't have to link to the CRT libs.
//
#ifdef WINNT
/*----------------------------------------------------------
Purpose: Wide-char version. memset
Returns:
Cond: --
*/
LPWSTR PUBLIC lmemsetW(
LPWSTR dst,
WCHAR wcVal,
DWORD count)
{
LPWSTR start = dst;
while (count--)
*dst++ = wcVal;
return(start);
}
/*----------------------------------------------------------
Purpose: memmove
Swiped from the C 7.0 runtime sources.
Returns:
Cond:
*/
LPWSTR PUBLIC lmemmoveW(
LPWSTR dst,
LPCWSTR src,
DWORD count)
{
LPWSTR ret = dst;
if (dst <= src || dst >= (src + count)) {
/*
* Non-Overlapping Buffers
* copy from lower addresses to higher addresses
*/
while (count--)
*dst++ = *src++;
}
else {
/*
* Overlapping Buffers
* copy from higher addresses to lower addresses
*/
dst += count - 1;
src += count - 1;
while (count--)
*dst-- = *src--;
}
return(ret);
}
#endif // WINNT
/*----------------------------------------------------------
Purpose: memset
Swiped from the C 7.0 runtime sources.
Returns:
Cond:
*/
LPSTR PUBLIC lmemsetA(
LPSTR dst,
char val,
DWORD count)
{
LPSTR start = dst;
while (count--)
*dst++ = val;
return(start);
}
/*----------------------------------------------------------
Purpose: memmove
Swiped from the C 7.0 runtime sources.
Returns:
Cond:
*/
LPSTR PUBLIC lmemmoveA(
LPSTR dst,
LPCSTR src,
DWORD count)
{
LPSTR ret = dst;
if (dst <= src || dst >= (src + count)) {
/*
* Non-Overlapping Buffers
* copy from lower addresses to higher addresses
*/
while (count--)
*dst++ = *src++;
}
else {
/*
* Overlapping Buffers
* copy from higher addresses to lower addresses
*/
dst += count - 1;
src += count - 1;
while (count--)
*dst-- = *src--;
}
return(ret);
}
#endif // NORTL
#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
#if defined(DBCS) || defined(WINNT)
#define FASTCALL PASCAL
#else
#define FASTCALL _fastcall
#endif
/*----------------------------------------------------------
Purpose: Case sensitive character comparison for DBCS
Returns: FALSE if they match, TRUE if no match
Cond: --
*/
BOOL NEAR FASTCALL 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 FASTCALL 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 = AnsiFromUnicode(&pszString, pwszString, szBuf, ARRAYSIZE(szBuf));
if (bRet)
{
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 = 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
#if !defined(NOFILEINFO) && defined(WIN95)
/*----------------------------------------------------------
Purpose: Takes a DWORD value and converts it to a string, adding
commas on the way.
This was taken from the shell.
Returns: Pointer to buffer
Cond: --
*/
LPSTR PRIVATE AddCommas(
DWORD dw,
LPSTR pszBuffer,
UINT cchBuffer)
{
CHAR szTemp[30];
CHAR szSep[5];
NUMBERFMT nfmt;
nfmt.NumDigits=0;
nfmt.LeadingZero=0;
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
AnsiToInt(szSep, &nfmt.Grouping);
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
nfmt.NegativeOrder= 0;
wsprintf(szTemp, "%lu", dw);
GetNumberFormatA(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszBuffer, cchBuffer);
return pszBuffer;
}
const short s_rgidsOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB, IDS_ORDERGB, IDS_ORDERTB};
/*----------------------------------------------------------
Purpose: Converts a number into a short, string format.
This code was taken from the shell.
532 -> 523 bytes
1340 -> 1.3KB
23506 -> 23.5KB
-> 2.4MB
-> 5.2GB
Returns: pointer to buffer
Cond: --
*/
LPSTR PRIVATE ShortSizeFormat64(
__int64 dw64,
LPSTR szBuf)
{
int i;
UINT wInt, wLen, wDec;
CHAR szTemp[10], szOrder[20], szFormat[5];
if (dw64 < 1000)
{
wsprintf(szTemp, "%d", LODWORD(dw64));
i = 0;
goto AddOrder;
}
for (i = 1; i < ARRAYSIZE(s_rgidsOrders)-1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
/* do nothing */
wInt = LODWORD(dw64 >> 10);
AddCommas(wInt, szTemp, ARRAYSIZE(szTemp));
wLen = lstrlen(szTemp);
if (wLen < 3)
{
wDec = LODWORD(dw64 - (__int64)wInt * 1024L) * 1000 / 1024;
// At this point, wDec should be between 0 and 1000
// we want get the top one (or two) digits.
wDec /= 10;
if (wLen == 2)
wDec /= 10;
// Note that we need to set the format before getting the
// intl char.
lstrcpy(szFormat, "%02d");
szFormat[2] = '0' + 3 - wLen;
GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
szTemp+wLen, ARRAYSIZE(szTemp)-wLen);
wLen = lstrlen(szTemp);
wLen += wsprintf(szTemp+wLen, szFormat, wDec);
}
AddOrder:
LoadString(g_hinst, s_rgidsOrders[i], szOrder, ARRAYSIZE(szOrder));
wsprintf(szBuf, szOrder, (LPSTR)szTemp);
return szBuf;
}
/*----------------------------------------------------------
Purpose: Converts a number into a short, string format.
This code was taken from the shell.
532 -> 523 bytes
1340 -> 1.3KB
23506 -> 23.5KB
-> 2.4MB
-> 5.2GB
Returns: pointer to buffer
Cond: --
*/
LPSTR PRIVATE ShortSizeFormat(DWORD dw, LPSTR szBuf)
{
return(ShortSizeFormat64((__int64)dw, szBuf));
}
/*----------------------------------------------------------
Purpose: Gets the file info given a path. If the path refers
to a directory, then simply the path field is filled.
If himl != NULL, then the function will add the file's
image to the provided image list and set the image index
field in the *ppfi.
Returns: standard hresult
Cond: --
*/
HRESULT PUBLIC FICreate(
LPCSTR pszPath,
FileInfo ** ppfi,
UINT uFlags)
{
HRESULT hres = ResultFromScode(E_OUTOFMEMORY);
int cchPath;
SHFILEINFO sfi;
UINT uInfoFlags = SHGFI_DISPLAYNAME | SHGFI_ATTRIBUTES;
DWORD dwAttr;
ASSERT(pszPath);
ASSERT(ppfi);
// Get shell file info
if (IsFlagSet(uFlags, FIF_ICON))
uInfoFlags |= SHGFI_ICON;
if (IsFlagSet(uFlags, FIF_DONTTOUCH))
{
uInfoFlags |= SHGFI_USEFILEATTRIBUTES;
// Today, FICreate is not called for folders, so this is ifdef'd out
#ifdef SUPPORT_FOLDERS
dwAttr = IsFlagSet(uFlags, FIF_FOLDER) ? FILE_ATTRIBUTE_DIRECTORY : 0;
#else
dwAttr = 0;
#endif
}
else
dwAttr = 0;
if (SHGetFileInfo(pszPath, dwAttr, &sfi, sizeof(sfi), uInfoFlags))
{
// Allocate enough for the structure, plus buffer for the fully qualified
// path and buffer for the display name (and extra null terminator).
cchPath = lstrlen(pszPath);
*ppfi = GAlloc(sizeof(FileInfo) + CbFromCch(cchPath+1) - ARRAYSIZE((*ppfi)->szPath) + CbFromCch(lstrlen(sfi.szDisplayName)+1));
if (*ppfi)
{
FileInfo * pfi = *ppfi;
pfi->pszDisplayName = pfi->szPath + CbFromCch(cchPath+1);
lstrcpy(pfi->pszDisplayName, sfi.szDisplayName);
if (IsFlagSet(uFlags, FIF_ICON))
pfi->hicon = sfi.hIcon;
pfi->dwAttributes = sfi.dwAttributes;
// Does the path refer to a directory?
if (FIIsFolder(pfi))
{
// Yes; just fill in the path field
lstrcpy(pfi->szPath, pszPath);
hres = NOERROR;
}
else
{
// No; assume the file exists?
if (IsFlagClear(uFlags, FIF_DONTTOUCH))
{
// Yes; get the time, date and size of the file
HANDLE hfile = CreateFile(pszPath, GENERIC_READ,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL);
if (hfile == INVALID_HANDLE_VALUE)
{
GFree(*ppfi);
hres = ResultFromScode(E_HANDLE);
}
else
{
hres = NOERROR;
lstrcpy(pfi->szPath, pszPath);
pfi->dwSize = GetFileSize(hfile, NULL);
GetFileTime(hfile, NULL, NULL, &pfi->ftMod);
CloseHandle(hfile);
}
}
else
{
// No; use what we have
hres = NOERROR;
lstrcpy(pfi->szPath, pszPath);
}
}
}
}
else if (!WPPathExists(pszPath))
{
// Differentiate between out of memory and file not found
hres = E_FAIL;
}
return hres;
}
/*----------------------------------------------------------
Purpose: Get some file info of the given path.
The returned string is of the format "# bytes <date>"
If the path is a folder, the string is empty.
Returns: FALSE if path is not found
Cond: --
*/
BOOL PUBLIC FIGetInfoString(
FileInfo * pfi,
LPSTR pszBuf,
int cchBuf)
{
BOOL bRet;
ASSERT(pfi);
ASSERT(pszBuf);
*pszBuf = NULL_CHAR;
if (pfi)
{
// Is this a file?
if ( !FIIsFolder(pfi) )
{
// Yes
CHAR szSize[MAX_BUF_MED];
CHAR szDate[MAX_BUF_MED];
CHAR szTime[MAX_BUF_MED];
LPSTR pszMsg;
SYSTEMTIME st;
FILETIME ftLocal;
// Construct the string
FileTimeToLocalFileTime(&pfi->ftMod, &ftLocal);
FileTimeToSystemTime(&ftLocal, &st);
GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, ARRAYSIZE(szDate));
GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, szTime, ARRAYSIZE(szTime));
if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(IDS_DATESIZELINE),
ShortSizeFormat(FIGetSize(pfi), szSize), szDate, szTime))
{
lstrcpy(pszBuf, pszMsg);
GSetString(&pszMsg, NULL);
}
else
*pszBuf = 0;
bRet = TRUE;
}
else
bRet = FALSE;
}
else
bRet = FALSE;
return bRet;
}
/*----------------------------------------------------------
Purpose: Set the path entry. This can move the pfi.
Returns: FALSE on out of memory
Cond: --
*/
BOOL PUBLIC FISetPath(
FileInfo ** ppfi,
LPCSTR pszPathNew,
UINT uFlags)
{
ASSERT(ppfi);
ASSERT(pszPathNew);
FIFree(*ppfi);
return SUCCEEDED(FICreate(pszPathNew, ppfi, uFlags));
}
/*----------------------------------------------------------
Purpose: Free our file info struct
Returns: --
Cond: --
*/
void PUBLIC FIFree(
FileInfo * pfi)
{
if (pfi)
{
if (pfi->hicon)
DestroyIcon(pfi->hicon);
GFree(pfi); // This macro already checks for NULL pfi condition
}
}
/*----------------------------------------------------------
Purpose: Convert FILETIME struct to a readable string
Returns: String
Cond: --
*/
void PUBLIC FileTimeToDateTimeString(
LPFILETIME pft,
LPSTR pszBuf,
int cchBuf)
{
SYSTEMTIME st;
FILETIME ftLocal;
FileTimeToLocalFileTime(pft, &ftLocal);
FileTimeToSystemTime(&ftLocal, &st);
GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuf, cchBuf/2);
pszBuf += lstrlen(pszBuf);
*pszBuf++ = ' ';
GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszBuf, cchBuf/2);
}
#endif // NOFILEINFO
#ifndef NOSYNC
#if defined(WIN95)
CRITICAL_SECTION g_csCommon = { 0 };
DEBUG_CODE( UINT g_cRefCommonCS = 0; )
#endif
/*----------------------------------------------------------
Purpose: Waits for on object to signal. This function "does
the right thing" to prevent deadlocks which can occur
because the calculation thread calls SendMessage.
Returns: value of MsgWaitForMultipleObjects
Cond: --
*/
DWORD PUBLIC MsgWaitObjectsSendMessage(
DWORD cObjects,
LPHANDLE phObjects,
DWORD dwTimeout)
{
DWORD dwRet;
while (TRUE)
{
dwRet = MsgWaitForMultipleObjects(cObjects, phObjects, FALSE,
dwTimeout, QS_SENDMESSAGE);
// If it is not a message, return
if ((WAIT_OBJECT_0 + cObjects) != dwRet)
{
return dwRet;
}
else
{
// Process all the sent messages
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
}
}
}
#if defined(WIN95)
/*----------------------------------------------------------
Purpose: Initialize the critical section.
Returns: --
Cond: Note that critical sections differ between Win95
and NT. On Win95, critical sections synchronize
across processes. On NT, they are per-process.
*/
void PUBLIC Common_InitExclusive(void)
{
#ifdef WIN95
ReinitializeCriticalSection(&g_csCommon);
#else
InitializeCriticalSection(&g_csCommon);
#endif
ASSERT(0 != *((LPDWORD)&g_csCommon));
#ifdef DEBUG
g_cRefCommonCS = 0;
#endif
}
/*----------------------------------------------------------
Purpose: Enter a critical section
Returns: --
Cond: Note that critical sections differ between Win95
and NT. On Win95, critical sections synchronize
across processes. On NT, they are per-process.
*/
void PUBLIC Common_EnterExclusive(void)
{
EnterCriticalSection(&g_csCommon);
#ifdef DEBUG
g_cRefCommonCS++;
#endif
}
/*----------------------------------------------------------
Purpose: Leave a critical section
Returns: --
Cond: Note that critical sections differ between Win95
and NT. On Win95, critical sections synchronize
across processes. On NT, they are per-process.
*/
void PUBLIC Common_LeaveExclusive(void)
{
#ifdef DEBUG
g_cRefCommonCS--;
#endif
LeaveCriticalSection(&g_csCommon);
}
#endif // WIN95
#endif // NOSYNC
#ifndef NOMESSAGESTRING
#ifdef WIN32
typedef va_list * LPVA_LIST;
#else // WIN32
typedef LPDWORD LPVA_LIST;
#endif // WIN32
#ifdef WINNT
/*----------------------------------------------------------
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 (HIWORD(pwszMsg))
pwszRes = (LPWSTR)pwszMsg;
else if (LOWORD(pwszMsg) && LoadStringW(hinst, LOWORD(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((HLOCAL)OFFSETOF(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 (0 == HIWORD(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((HLOCAL)OFFSETOF(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 LocalFree()
*/
LPSTR PUBLIC ConstructVMessageStringA(
HINSTANCE hinst,
LPCSTR pszMsg,
va_list FAR * ArgList)
{
CHAR szTemp[MAX_BUF];
LPSTR pszRet;
LPSTR pszRes;
if (HIWORD(pszMsg))
pszRes = (LPSTR)pszMsg;
else if (LOWORD(pszMsg) && LoadStringA(hinst, LOWORD(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 LocalFree()
}
/*----------------------------------------------------------
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((HLOCAL)OFFSETOF(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 (0 == HIWORD(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((HLOCAL)OFFSETOF(pszRet));
}
return iRet;
}
#endif // NOMESSAGESTRING
#if !defined(NODEBUGHELP) && defined(DEBUG)
// Globals
DWORD g_dwBreakFlags = 0;
DWORD g_dwDumpFlags = 0;
DWORD g_dwTraceFlags = 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[];
#if defined(WANT_OLE_SUPPORT) && defined(WIN95)
struct _RIIDMAP
{
REFIID riid;
LPCSTR psz;
} const c_rgriidmap[] = {
{ &IID_IUnknown, "IID_IUnknown" },
{ &IID_IBriefcaseStg, "IID_IBriefcaseStg" },
{ &IID_IEnumUnknown, "IID_IEnumUnknown" },
{ &IID_IShellBrowser, "IID_IShellBrowser" },
{ &IID_IShellView, "IID_IShellView" },
{ &IID_IContextMenu, "IID_IContextMenu" },
{ &IID_IShellFolder, "IID_IShellFolder" },
{ &IID_IShellExtInit, "IID_IShellExtInit" },
{ &IID_IShellPropSheetExt, "IID_IShellPropSheetExt" },
{ &IID_IPersistFolder, "IID_IPersistFolder" },
{ &IID_IExtractIcon, "IID_IExtractIcon" },
{ &IID_IShellDetails, "IID_IShellDetails" },
{ &IID_IDelayedRelease, "IID_IDelayedRelease" },
{ &IID_IShellLink, "IID_IShellLink" },
};
#endif // defined(WANT_OLE_SUPPORT) && defined(WIN95)
#if defined(__SCODE_H__) && defined(WIN95)
struct _SCODEMAP
{
SCODE sc;
LPCSTR psz;
} const c_rgscodemap[] = {
{ S_OK, "S_OK" },
{ S_FALSE, "S_FALSE" },
{ E_UNEXPECTED, "E_UNEXPECTED" },
{ E_NOTIMPL, "E_NOTIMPL" },
{ E_OUTOFMEMORY, "E_OUTOFMEMORY" },
{ E_INVALIDARG, "E_INVALIDARG" },
{ E_NOINTERFACE, "E_NOINTERFACE" },
{ E_POINTER, "E_POINTER" },
{ E_HANDLE, "E_HANDLE" },
{ E_ABORT, "E_ABORT" },
{ E_FAIL, "E_FAIL" },
{ E_ACCESSDENIED, "E_ACCESSDENIED" },
};
#endif // defined(__SCODE_H__) && defined(WIN95)
#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))
{
#ifdef DBCS
if ((AnsiPrev(pszFile, psz) != (psz-2)) && *(psz - 1) == '\\')
#else
if (*(psz - 1) == '\\')
#endif
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 (TF_ALWAYS == flag || 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;
if (TF_ALWAYS == flag || IsFlagSet(g_dwTraceFlags, flag))
{
int cch;
WCHAR wszBuf[MAX_BUF];
LPWSTR pwsz;
#ifdef PROFILE_TRACES
static WCHAR szTemplate[7];
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
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);
}
}
/*----------------------------------------------------------
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;
if (TF_ALWAYS == flag || IsFlagSet(g_dwTraceFlags, flag))
{
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);
}
}
#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
#ifdef WIN95
INIT_EXCLUSIVE();
#endif
bRet = RovComm_ProcessIniFile();
return bRet;
}
/*----------------------------------------------------------
Purpose: Entry-point to handle termination.
Returns: TRUE on success
Cond: --
*/
BOOL PUBLIC RovComm_Terminate(
HINSTANCE hinst)
{
#if !defined(NOSHAREDHEAP) && defined(WIN95)
SharedTerminate();
#endif
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;
}