2020-09-30 17:12:29 +02:00

901 lines
19 KiB
C++

/****************************************************************************
*
* COMMON.CPP
*
* Copyright (C) Microsoft Corporation 1993-1994
* All Rights reserved.
*
*****************************************************************************/
#include "stdafx.h"
#ifndef _CSTR_INCLUDED
#include "cstr.h"
#endif
#ifndef _INC_CTYPE
#include <ctype.h>
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
void STDCALL InitializeHwDll(HWDLL_INIT* pinit)
{
hinstApp = pinit->hinstApp;
pszErrorFile = pinit->pszErrorFile;
hwndApp = pinit->hwndWindow;
CopyAssertInfo = pinit->CopyAssertInfo;
pszMsgBoxTitle = pinit->pszMsgBoxTitle;
if (pinit->version > DLL_VERSION)
DllMsgBox(IDS_DLL_OUT_OF_DATE);
pinit->fDBCSSystem = _fDBCSSystem;
pinit->lcidSystem = _lcidSystem;
pinit->fDualCPU = _fDualCPU;
}
/***************************************************************************
FUNCTION: stristr
PURPOSE: Case-insensitive search for a sub string in a main string
PARAMETERS:
pszMain
pszSub
RETURNS:
COMMENTS:
Not tested
MODIFICATION DATES:
28-Mar-1994 [ralphw]
***************************************************************************/
PSTR STDCALL stristr(PCSTR pszMain, PCSTR pszSub)
{
PSTR pszCur = (PSTR) pszMain;
char ch = tolower(*pszSub);
int cb = strlen(pszSub) - 1; // -1 to ignore leading character
for (;;) {
while (tolower(*pszCur) != ch && *pszCur)
pszCur++;
if (!*pszCur)
return NULL;
if (_strnicmp(pszCur + 1, pszSub + 1, cb) == 0)
return pszCur;
pszCur++;
}
}
/***************************************************************************
FUNCTION: IsThereMore
PURPOSE: Given a pointer to an argument, or the space after an argument,
return a pointer to the next argument if there is one, or
NULL if there is no additional argument
RETURNS: Pointer to second item, NULL if none found.
COMMENTS:
Normally a dot command such as .list is passed to this to determine
if there is additional text on the same line. If there is, a pointer
to the second item is returned.
MODIFICATION DATES:
03-Apr-1989 [ralphw]
05-Jul-1989 [ralphw]
If the current pointer is to a quote, then skip everything until
the next quote.
***************************************************************************/
PSTR STDCALL IsThereMore(PCSTR psz)
{
if (!psz)
return NULL;
// If the current argument is quoted, skip to next quote
if (*psz == CH_QUOTE || *psz == CH_START_QUOTE) {
char chEnd = (*psz == CH_QUOTE) ? CH_QUOTE : CH_END_QUOTE;
KeepTrying:
for (psz++; *psz != chEnd && *psz; psz++);
if (psz[-1] == CH_BACKSLASH) {
psz++;
goto KeepTrying;
}
if (*psz == chEnd)
psz++;
}
// find the first space or EOL
while (*psz > CH_SPACE && *psz)
psz++;
// find the first non-space
while (isspace(*psz))
psz++;
return (*psz) ? (PSTR) psz : NULL;
}
/***************************************************************************
FUNCTION: FirstNonSpace
PURPOSE: Return a pointer to the first non-space character
RETURNS:
COMMENTS:
MODIFICATION DATES:
30-May-1989 [ralphw]
***************************************************************************/
#ifndef _INC_CTYPE
#include <ctype.h>
#endif
PSTR STDCALL FirstNonSpace(PCSTR psz, BOOL fDBCS)
{
if (fDBCS) {
while (!IsDBCSLeadByte(*psz) && IsDbcsSpace(*psz, TRUE))
psz++;
return (PSTR) psz;
}
while(IsDbcsSpace(*psz, FALSE))
psz++;
return (PSTR) psz;
}
/***************************************************************************
FUNCTION: IsDbcsSpace
PURPOSE: DBCS-aware version of isspace
PARAMETERS:
ch
fDBCS
RETURNS:
COMMENTS:
MODIFICATION DATES:
14-Jan-1995 [ralphw]
***************************************************************************/
BOOL STDCALL IsDbcsSpace(char ch, BOOL fDBCS)
{
if (fDBCS)
return (!IsDBCSLeadByte(ch) && (ch == CH_SPACE || ch == CH_TAB));
else
return ((ch == CH_SPACE || ch == CH_TAB));
}
/***************************************************************************
FUNCTION: ChangeExtension
PURPOSE: Changes the extension of a filename
RETURNS:
COMMENTS:
The extension can be specified with or without the leading period.
MODIFICATION DATES:
25-May-1990 [ralphw]
04-Aug-1990 [ralphw]
NULL for an extension means remove any existing extension
***************************************************************************/
void STDCALL ChangeExtension(PSTR pszDest, PCSTR pszExt)
{
PSTR psz;
BOOL fDBCSSystem = IsDbcsSystem();
ASSERT(pszDest);
// If NULL is specified, simply remove any existing extension
if (pszExt == NULL || !*pszExt) {
if ((psz = StrRChr(pszDest, '.', fDBCSSystem)) != NULL)
*psz = '\0';
return;
}
if ((psz = StrRChr(pszDest, '.', fDBCSSystem)) == NULL)
psz = pszDest + strlen(pszDest); // filename didn't have an extension
if (*pszExt != '.')
*psz++ = '.';
strcpy(psz, pszExt);
}
/***************************************************************************
FUNCTION: StrChr
PURPOSE: DBCS-capable version of strchr
PARAMETERS:
pszString
ch
fDBCS
RETURNS: pointer to the character
COMMENTS: This can NOT find a DBCS character. It can only be used to
find a SBCS character imbedded in a DBCS character string.
MODIFICATION DATES:
29-Jul-1994 [ralphw]
***************************************************************************/
PSTR STDCALL StrChr(PCSTR pszString, char ch, BOOL fDBCS)
{
if (!fDBCS)
return strchr(pszString, ch);
while (*pszString) {
while (IsDBCSLeadByte(*pszString))
pszString += 2;
if (*pszString == ch)
return (PSTR) pszString;
else if (!*pszString)
return NULL;
pszString++;
}
return NULL;
}
/***************************************************************************
FUNCTION: StrRChr
PURPOSE: DBCS-enabled version of strrchr
PARAMETERS:
pszString
ch
fDBCS
RETURNS:
COMMENTS:
MODIFICATION DATES:
14-Jan-1995 [ralphw]
***************************************************************************/
PSTR STDCALL StrRChr(PCSTR pszString, char ch, BOOL fDBCS)
{
if (!fDBCS)
return strrchr(pszString, ch);
PSTR pszLast = StrChr(pszString, ch, fDBCS);
if (!pszLast)
return NULL;
PSTR pszNext;
while ((pszNext = StrChr(pszLast + 1, ch, fDBCS)))
pszLast = pszNext;
return pszLast;
}
/***************************************************************************
FUNCTION: RemoveObject
PURPOSE: Unlike DeleteObject (which this function calls), this
function not only deletes the object, but zeros-out the
handle of the object.
PARAMETERS:
phobj
RETURNS:
COMMENTS:
It's perfectly fine to call this with a NULL handle -- the function
will return immediately without attempting to delete the object.
When compiling the debugging version, this function will confirm
that the object was deleted.
MODIFICATION DATES:
05-Feb-1992 [ralphw]
***************************************************************************/
void STDCALL RemoveObject(HGDIOBJ *phobj)
{
if (*phobj == NULL)
return; // object has already been deleted
VERIFY(DeleteObject(*phobj));
*phobj = NULL;
}
BOOL STDCALL IsThisChicago(void)
{
// handles both version 4.00 and 3.99.
if (HIBYTE(LOWORD(GetVersion())) >= 90 ||
LOBYTE(LOWORD(GetVersion())) >= 4)
return TRUE;
else
return FALSE;
}
BOOL STDCALL nstrisubcmp(PCSTR mainstring, PCSTR substring)
{
int cb = lstrlen(substring);
int cbMain = lstrlen(mainstring);
if (cb > cbMain)
return FALSE;
return (CompareString(GetUserDefaultLCID(), NORM_IGNORECASE,
mainstring, cb, substring, cb) == 2);
}
const int MAX_STRING_RESOURCE_LEN = 255;
int STDCALL MsgBox(UINT idString, UINT nType)
{
char szMsg[MAX_STRING_RESOURCE_LEN + 1];
if (LoadString(hinstApp, idString, szMsg,
sizeof(szMsg)) == 0) {
#ifdef _DEBUG
wsprintf(szMsg, "invalid string id #%u", idString);
DBWIN(szMsg);
#endif
return 0;
}
return MessageBox(hwndApp, szMsg, pszMsgBoxTitle, nType);
}
/***************************************************************************
FUNCTION: DllMsgBox
PURPOSE: Same as MsgBox, but uses a string resource id from the dll
PARAMETERS:
idString
nType
RETURNS:
COMMENTS:
MODIFICATION DATES:
29-Jun-1995 [ralphw]
***************************************************************************/
int STDCALL DllMsgBox(UINT idString, UINT nType)
{
char szMsg[MAX_STRING_RESOURCE_LEN + 1];
if (LoadString(hinstDll, idString, szMsg,
sizeof(szMsg)) == 0) {
#ifdef _DEBUG
wsprintf(szMsg, "invalid string id #%u", idString);
DBWIN(szMsg);
#endif
return 0;
}
return MessageBox(hwndApp, szMsg, pszMsgBoxTitle, nType);
}
int STDCALL MsgBox(PCSTR pszMsg, UINT nType)
{
return MessageBox(hwndApp, pszMsg, pszMsgBoxTitle, nType);
}
static char szStringBuf[MAX_STRING_RESOURCE_LEN + MAX_PATH];
PCSTR STDCALL GetStringResource(int idString)
{
if (LoadString(hinstApp, idString, szStringBuf,
sizeof(szStringBuf)) == 0) {
#ifdef _DEBUG
wsprintf(szStringBuf, "invalid string id #%u", idString);
DBWIN(szStringBuf);
#endif
szStringBuf[0] = '\0';
}
return (PCSTR) szStringBuf;
}
PCSTR STDCALL GetStringResource(int idString, PCSTR pszAppend)
{
if (LoadString(hinstApp, idString, szStringBuf,
sizeof(szStringBuf)) == 0) {
#ifdef _DEBUG
wsprintf(szStringBuf, "invalid string id #%u", idString);
DBWIN(szStringBuf);
#endif
szStringBuf[0] = '\0';
}
strcat(szStringBuf, pszAppend);
return (PCSTR) szStringBuf;
}
PCSTR STDCALL GetDllStringResource(int idString)
{
if (LoadString(hinstDll, idString, szStringBuf,
sizeof(szStringBuf)) == 0) {
#ifdef _DEBUG
wsprintf(szStringBuf, "invalid string id #%u", idString);
DBWIN(szStringBuf);
#endif
szStringBuf[0] = '\0';
}
return (PCSTR) szStringBuf;
}
static HCURSOR hcurRestore, hcurWait;
void STDCALL WaitCursor(void)
{
if (!hcurWait)
hcurWait = LoadCursor(NULL, (LPSTR) IDC_WAIT);
hcurRestore = SetCursor(hcurWait);
}
void STDCALL RemoveWaitCursor(void) {
SetCursor(hcurRestore);
}
/***************************************************************************
FUNCTION: FormatNumber
PURPOSE: Convert a number into a string, and insert commas every
3 digits
PARAMETERS:
num
RETURNS: Pointer to the string containing the number
COMMENTS:
Cycles through an array of strings, allowing up to MAX_STRING
requests before a duplicate would occur. This is important for
calls to sprintf() where all the pointers are retrieved before
the strings are actually used.
MODIFICATION DATES:
03-Jul-1994 [ralphw]
***************************************************************************/
#define MAX_NUM 15
#define MAX_STRING 10
#include <stdlib.h>
PCSTR STDCALL FormatNumber(int num)
{
static int pos = 0;
static char szNum[MAX_NUM * MAX_STRING];
PSTR pszNum = szNum + (pos * MAX_STRING);
if (++pos >= MAX_STRING)
pos = 0;
_itoa(num, pszNum, 10);
int cb = strlen(pszNum) - 3;
while (cb > 0) {
memmove(pszNum + cb + 1, pszNum + cb, strlen(pszNum + cb) + 1);
pszNum[cb] = ',';
cb -= 3;
}
return pszNum;
}
void STDCALL OOM(void)
{
/*
* If our heap initializatin fails, we won't have an instance handle
* yet, so we can't load a string resource. In this case, we have no
* choice but to use the English message.
*/
if (!hinstDll)
FatalAppExit(0,
"There is not enough memory available for this task.\nQuit one or more applications to increase available memory, and then try again.");
else
FatalAppExit(0, GetDllStringResource(IDS_OOM));
}
void AssertErrorReport(PCSTR pszExpression, UINT Line, LPCSTR pszFile)
{
char szBuf[512], szErrorFile[30];
HFILE hf;
OFSTRUCT of;
static BOOL fAsserted = FALSE;
char szExpression[256];
char szName[_MAX_FNAME];
BOOL fCopiedToPike = FALSE;
if (fAsserted)
return; // we already asserted
else
fAsserted = TRUE;
/*
* Often the expression will have been obtained via GetStringResource,
* so we make a copy of it here to save the information.
*/
strncpy(szExpression, pszExpression, sizeof(szExpression));
#ifdef INTERNAL
if (!GetVolumeInformation("c:\\", szName, sizeof(szName),
NULL, NULL, NULL, NULL, 0)) {
strcpy(szName, pszErrorFile);
}
else {
szName[8] = '\0';
CharLower(szName);
strcat(szName, ".err");
strcpy(szErrorFile, "\\\\pike\\bugs\\flash\\");
strcat(szErrorFile, szName);
}
of.cBytes = sizeof(OFSTRUCT);
hf = OpenFile(szErrorFile, &of, OF_CREATE | OF_WRITE);
if (hf == HFILE_ERROR) {
// couldn't find \\pike, so copy it to their C drive.
strcpy(szErrorFile, "c:\\");
strcat(szErrorFile, szName);
hf = OpenFile(szErrorFile, &of, OF_CREATE | OF_WRITE);
}
else
fCopiedToPike = TRUE;
#else
if (!GetVolumeInformation("c:\\", szName, sizeof(szName),
NULL, NULL, NULL, NULL, 0)) {
strcpy(szErrorFile, pszErrorFile);
}
else {
strcpy(szErrorFile, "c:\\");
CharLower(szName);
strcat(szErrorFile, szName);
szErrorFile[10] = '\0';
strcat(szErrorFile, ".err");
}
of.cBytes = sizeof(OFSTRUCT);
hf = OpenFile(szErrorFile, &of, OF_CREATE | OF_WRITE);
#endif // INTERNAL
if (hf >= 0) {
strcpy(szBuf, GetStringResource(IDS_VERSION));
wsprintf(szBuf + strlen(szBuf),
GetDllStringResource(IDS_ASSERTION_FAILURE),
(LPSTR) pszFile, Line, (LPSTR) szExpression);
_lwrite(hf, szBuf, strlen(szBuf));
if (CopyAssertInfo) {
char szSysInfo[512];
CopyAssertInfo(szSysInfo);
_lwrite(hf, szSysInfo, strlen(szSysInfo));
}
wsprintf(szBuf,
GetDllStringResource((fCopiedToPike ?
IDS_ASSRT_COPIED_MSG : IDS_ASSRT_COPY_MSG)),
szErrorFile);
MsgBox(szBuf);
_lclose(hf);
}
else {
DllMsgBox(IDS_INTERNAL_ERROR);
}
#ifdef _DEBUG
int answer = ::MessageBox(NULL, pszExpression, "Retry to call DebugBreak()",
MB_ABORTRETRYIGNORE);
if (answer == IDRETRY) {
DebugBreak();
return;
}
else if (answer == IDIGNORE)
return;
#endif
/*
* Send a WM_CLOSE message to give the application the opportunity to
* clean up resources before being terminated.
*/
if (IsValidWindow(hwndApp))
SendMessage(hwndApp, WM_CLOSE, 0, 0);
// What does AfxWinTerm() do with a non-MFC app?
AfxWinTerm();
_exit(1);
return;
}
/***************************************************************************
FUNCTION: MoveClientWindow
PURPOSE: Moves a child window using screen coordinates
PARAMETERS:
hwndParent
hwndChild
prc - rectangle containing coordinates
fRedraw
RETURNS:
COMMENTS:
This function is similar to MoveWindow, only it expects the
coordinates to be in screen coordinates rather then client
coordinates. This makes it possible to use functions like
GetWindowRect() and use the values directly.
MODIFICATION DATES:
25-Feb-1992 [ralphw]
***************************************************************************/
BOOL STDCALL MoveClientWindow(HWND hwndParent, HWND hwndChild,
const RECT *prc, BOOL fRedraw)
{
CPoint pt(0, 0);
ScreenToClient(hwndParent, &pt);
return SetWindowPos(hwndChild, NULL, prc->left + pt.x, prc->top + pt.y,
RECT_WIDTH(prc), RECT_HEIGHT(prc),
(fRedraw ? (SWP_NOZORDER | SWP_NOACTIVATE) :
(SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW)));
}
/***************************************************************************
FUNCTION: AddTrailingBackslash
PURPOSE:
PARAMETERS:
npszStr
RETURNS:
COMMENTS:
MODIFICATION DATES:
03-Nov-1992 [ralphw]
***************************************************************************/
void STDCALL AddTrailingBackslash(PSTR psz)
{
int sPos;
if (psz != NULL && *psz != '\0') {
if (_fDBCSSystem) {
PSTR pszEnd = psz + strlen(psz);
if (*(CharPrev(psz, pszEnd)) != '\\' &&
*(CharPrev(psz, pszEnd)) != '/' &&
*(CharPrev(psz, pszEnd)) != ':') {
*pszEnd++ = '\\';
*pszEnd++ = '\0';
}
}
else {
sPos = strlen(psz) - 1;
if (psz[sPos] != '\\' && psz[sPos] != '/' && psz[sPos] != ':') {
psz[sPos + 1] = '\\';
psz[sPos + 2] = '\0';
}
}
}
}
/***************************************************************************
FUNCTION: StrToken
PURPOSE: DBCS-enabed variant of strtok
PARAMETERS:
pszList
chDelimiter
RETURNS:
COMMENTS:
You can NOT specify a DBCS character to look for
MODIFICATION DATES:
06-Jan-1995 [ralphw]
***************************************************************************/
PSTR STDCALL StrToken(PSTR pszList, PCSTR pszDelimeters)
{
static PSTR pszSavedList = NULL;
PSTR psz, pszTokens;
if (pszList) {
pszSavedList = pszList;
// On the first call, remove any leading token matches
for (psz = (PSTR) pszDelimeters; *psz; psz++) {
if (*psz == *pszSavedList) {
pszSavedList++;
psz = (PSTR) pszDelimeters - 1;
}
}
}
if (_fDBCSSystem) {
psz = pszSavedList;
while (*psz) {
for (pszTokens = (PSTR) pszDelimeters; *pszTokens; pszTokens++) {
if (*pszTokens == *psz)
break;
}
if (*pszTokens == *psz)
break;
psz = CharNext(psz);
}
if (!*psz)
psz = NULL;
}
else {
psz = strpbrk(pszSavedList, pszDelimeters);
}
if (!psz) {
if (!*pszSavedList)
return NULL;
else {
PSTR pszReturn = pszSavedList;
pszSavedList = pszSavedList + strlen(pszSavedList);
return pszReturn;
}
}
*psz++ = '\0';
PSTR pszReturn = pszSavedList;
pszSavedList = psz;
return pszReturn;
}
// Same as above, but allows two active strtokens at once
PSTR STDCALL StrToken2(PSTR pszList, PCSTR pszDelimeters)
{
static PSTR pszSavedList = NULL;
PSTR psz, pszTokens;
if (pszList) {
pszSavedList = pszList;
// On the first call, remove any leading token matches
for (psz = (PSTR) pszDelimeters; *psz; psz++) {
if (*psz == *pszSavedList) {
pszSavedList++;
psz = (PSTR) pszDelimeters - 1;
}
}
}
if (_fDBCSSystem) {
psz = pszSavedList;
while (*psz) {
for (pszTokens = (PSTR) pszDelimeters; *pszTokens; pszTokens++) {
if (*pszTokens == *psz)
break;
}
if (*pszTokens == *psz)
break;
psz = CharNext(psz);
}
if (!*psz)
psz = NULL;
}
else {
psz = strpbrk(pszSavedList, pszDelimeters);
}
if (!psz) {
if (!*pszSavedList)
return NULL;
else {
PSTR pszReturn = pszSavedList;
pszSavedList = pszSavedList + strlen(pszSavedList);
return pszReturn;
}
}
*psz++ = '\0';
PSTR pszReturn = pszSavedList;
pszSavedList = psz;
return pszReturn;
}
void STDCALL MsgCantOpen(PCSTR pszFile)
{
CStr csz(GetDllStringResource(IDS_CANNOT_OPEN));
csz += pszFile;
MsgBox(csz);
}
#include <cderr.h>
static PSTR apszCDErr[] = {
"CDERR_GENERALCODES",
"CDERR_STRUCTSIZE",
"CDERR_INITIALIZATION",
"CDERR_NOTEMPLATE",
"CDERR_NOHINSTANCE",
"CDERR_LOADSTRFAILURE",
"CDERR_FINDRESFAILURE",
"CDERR_LOADRESFAILURE",
"CDERR_LOCKRESFAILURE",
"CDERR_MEMALLOCFAILURE",
"CDERR_MEMLOCKFAILURE",
"CDERR_NOHOOK"
};
static PSTR apszFNErr[] = {
"FNERR_FILENAMECODES",
"FNERR_SUBCLASSFAILURE",
"FNERR_INVALIDFILENAME",
"FNERR_BUFFERTOOSMALL"
};
void STDCALL ReportComDlgError(DWORD Error)
{
char szMsg[100];
strcpy(szMsg, GetDllStringResource(IDS_COMMDLG_ERROR));
if (Error >= CDERR_GENERALCODES && Error <= PDERR_PRINTERCODES)
strcat(szMsg, apszCDErr[Error]);
else if (Error >= FNERR_FILENAMECODES && Error <= FRERR_FINDREPLACECODES)
strcat(szMsg, apszFNErr[Error - FNERR_FILENAMECODES]);
else
wsprintf(szMsg + strlen(szMsg), "%lu", Error);
MsgBox(szMsg);
return;
}