/**************************************************************************** * * 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 #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 #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 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 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; }