|
|
//+--------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: util.cxx
//
// Contents: DRT support routines
//
// History: 22-Sep-92 DrewB Created
//
//---------------------------------------------------------------
#include "headers.cxx"
#pragma hdrstop
#include <stdarg.h>
#include <direct.h>
#include <io.h>
#if DBG == 1
#include <dfdeb.hxx>
#endif
#define DEFAULT_DATA_DIR "."
BOOL fExitOnFail = TRUE;
char szOrigDir[_MAX_PATH] = ".";
// Preserve the current directory and change
// directory into the data directory
void SetData(void) { char *pszDataDir;
_getcwd(szOrigDir, _MAX_PATH); pszDataDir = getenv("DRTDATA"); if (pszDataDir == NULL) pszDataDir = DEFAULT_DATA_DIR; _chdir(pszDataDir); }
// Clean up the data directory
void CleanData(void) { _unlink(OlecsOut(DRTDF)); _unlink(OlecsOut(MARSHALDF)); }
// Restore the original directory
void UnsetData(void) { _chdir(szOrigDir); }
// Output a message if fVerbose is true
void out(char *fmt, ...) { va_list args;
if (fVerbose) { va_start(args, fmt); vprintf(fmt, args); va_end(args); } }
// internal error print
void _errorprint (char *fmt, va_list args) { #if !defined(FLAT) || defined(FPRINTF_WORKS)
fprintf(stderr, "** Fatal error **: "); vfprintf(stderr, fmt, args); #else
printf("** Fatal error **: "); vprintf(fmt, args); #endif
}
// error print
void errorprint (char *fmt, ...) { va_list args;
va_start (args, fmt);
_errorprint (fmt, args);
va_end (args); }
// Print out an error message and terminate the DRT
void error(int code, char *fmt, ...) { va_list args;
va_start(args, fmt);
_errorprint (fmt, args);
va_end(args); CleanData(); UnsetData(); exit(code); }
// Converts a TCHAR string to a char pointer in a temporary buffer
// This implementation treats the conversion buffer as a circular
// buffer so more than one string can be held (depending on the size
// of the strings)
#define BUFSIZE 1024
char *OlecsOut(OLECHAR const *ptcs) { #ifdef OLEWIDECHAR
static char szBuffer[BUFSIZE]; static char *pszBuf = szBuffer; char *pszTmp;
if (ptcs == NULL) return NULL; if (wcslen(ptcs) >= (size_t)(BUFSIZE-(pszBuf-szBuffer))) pszBuf = szBuffer; wcstombs(pszBuf, ptcs, BUFSIZE); szBuffer[BUFSIZE-1] = 0; pszTmp = pszBuf; pszBuf += strlen(pszBuf)+1; return pszTmp; #else
return (char *)ptcs; #endif
}
typedef struct { SCODE sc; char *text; } StatusCodeText;
static StatusCodeText scodes[] = { S_OK, "S_OK", S_FALSE, "S_FALSE", STG_E_INVALIDFUNCTION, "STG_E_INVALIDFUNCTION", STG_E_FILENOTFOUND, "STG_E_FILENOTFOUND", STG_E_PATHNOTFOUND, "STG_E_PATHNOTFOUND", STG_E_TOOMANYOPENFILES, "STG_E_TOOMANYOPENFILES", STG_E_ACCESSDENIED, "STG_E_ACCESSDENIED", STG_E_INVALIDHANDLE, "STG_E_INVALIDHANDLE", STG_E_INSUFFICIENTMEMORY, "STG_E_INSUFFICIENTMEMORY", STG_E_INVALIDPOINTER, "STG_E_INVALIDPOINTER", STG_E_NOMOREFILES, "STG_E_NOMOREFILES", STG_E_DISKISWRITEPROTECTED, "STG_E_DISKISWRITEPROTECTED", STG_E_SEEKERROR, "STG_E_SEEKERROR", STG_E_WRITEFAULT, "STG_E_WRITEFAULT", STG_E_READFAULT, "STG_E_READFAULT", STG_E_SHAREVIOLATION, "STG_E_SHAREVIOLATION", STG_E_LOCKVIOLATION, "STG_E_LOCKVIOLATION", STG_E_FILEALREADYEXISTS, "STG_E_FILEALREADYEXISTS", STG_E_INVALIDPARAMETER, "STG_E_INVALIDPARAMETER", STG_E_MEDIUMFULL, "STG_E_MEDIUMFULL", STG_E_ABNORMALAPIEXIT, "STG_E_ABNORMALAPIEXIT", STG_E_INVALIDHEADER, "STG_E_INVALIDHEADER", STG_E_INVALIDNAME, "STG_E_INVALIDNAME", STG_E_UNKNOWN, "STG_E_UNKNOWN", STG_E_UNIMPLEMENTEDFUNCTION, "STG_E_UNIMPLEMENTEDFUNCTION", STG_E_INVALIDFLAG, "STG_E_INVALIDFLAG", STG_E_INUSE, "STG_E_INUSE", STG_E_NOTCURRENT, "STG_E_NOTCURRENT", STG_E_REVERTED, "STG_E_REVERTED", STG_E_CANTSAVE, "STG_E_CANTSAVE", STG_E_OLDFORMAT, "STG_E_OLDFORMAT", STG_E_OLDDLL, "STG_E_OLDDLL", STG_E_SHAREREQUIRED, "STG_E_SHAREREQUIRED", STG_E_NOTFILEBASEDSTORAGE, "STG_E_NOTFILEBASEDSTORAGE", STG_E_EXTANTMARSHALLINGS, "STG_E_EXTANTMARSHALLINGS", STG_S_CONVERTED, "STG_S_CONVERTED" }; #define NSCODETEXT (sizeof(scodes)/sizeof(scodes[0]))
// Convert a status code to text
char *ScText(SCODE sc) { int i;
for (i = 0; i<NSCODETEXT; i++) if (scodes[i].sc == sc) return scodes[i].text; return "?"; }
// Output a call result and check for failure
HRESULT Result(HRESULT hr) { SCODE sc;
sc = DfGetScode(hr); out(" - %s (0x%lX)\n", ScText(sc), sc); if (FAILED(sc) && fExitOnFail) error(EXIT_BADSC, "Unexpected call failure\n"); return hr; }
// Perform Result() when the expectation is failure
HRESULT IllResult(char *pszText, HRESULT hr) { SCODE sc;
sc = DfGetScode(hr); out("%s - %s (0x%lX)\n", pszText, ScText(sc), sc); if (SUCCEEDED(sc) && fExitOnFail) error(EXIT_BADSC, "Unexpected call success\n"); return hr; }
// DEBUG - Check for memory leaks
void CheckMemory(void) { #if DBG == 1
if (fVerbose || DfGetMemAlloced() != 0) { out("Memory held: %lu bytes\n", DfGetMemAlloced()); if (DfGetMemAlloced() != 0) { DfPrintAllocs(); error(EXIT_BADSC, "Memory leak\n"); } } #endif
}
// DEBUG - Set the debugging level
void SetDebug(ULONG ulDf, ULONG ulMsf) { #if DBG == 1
DfDebug(ulDf, ulMsf); #endif
}
// Check whether a given storage has a certain
// structure or not
// Structure is given as a string with elements:
// <Type><Name><Options>[,...]
// Type - d for docfile and s for stream
// Name - Characters up to a '(' or ','
// Options - For a docfile, you can specify a recursive check
// in parentheses
//
// Example: dDocfile(sStream,dDocfile)
char *VerifyStructure(IStorage *pstg, char *pszStructure) { char szName[CWCSTORAGENAME], *psz; IStorage *pstgChild; char chType; SCODE sc; CStrList sl; SStrEntry *pse; IEnumSTATSTG *penm; STATSTG stat; OLECHAR atcName[CWCSTORAGENAME];
if (FAILED(sc = DfGetScode(pstg->EnumElements(0, NULL, 0, &penm)))) error(EXIT_BADSC, "VerifyStructure: Unable to create enumerator - " "%s (0x%lX)\n", ScText(sc), sc); for (;;) { sc = DfGetScode(penm->Next(1, &stat, NULL)); if (sc == S_FALSE) break; else if (FAILED(sc)) error(EXIT_BADSC, "VerifyStructure: Unable to enumerate - " "%s (0x%lX)\n", ScText(sc), sc); pse = sl.Add(stat.pwcsName); if (pse == NULL) error(EXIT_OOM, "VerifyStructure: Unable to allocate string\n"); pse->user.dw = stat.type; drtMemFree(stat.pwcsName); } penm->Release(); while (*pszStructure && *pszStructure != ')') { chType = *pszStructure++; psz = szName; while (*pszStructure && *pszStructure != '(' && *pszStructure != ')' && *pszStructure != ',') *psz++ = *pszStructure++; *psz = 0; ATOOLE(szName, atcName, CWCSTORAGENAME); pse = sl.Find(atcName); if (pse == NULL) error(EXIT_BADSC, "VerifyStructure: '%s' not found\n", szName); switch(chType) { case 'd': if (pse->user.dw != STGTY_STORAGE) error(EXIT_BADSC, "VerifyStructure: '%s' is not a storage\n", szName); sc = DfGetScode(pstg->OpenStorage(atcName, NULL, STGP(STGM_READWRITE), NULL, 0, &pstgChild)); if (FAILED(sc)) error(EXIT_BADSC, "VerifyStructure: can't open storage " "'%s' - %s\n", szName, ScText(sc)); if (*pszStructure == '(') pszStructure = VerifyStructure(pstgChild, pszStructure+1)+1; pstgChild->Release(); break; case 's': if (pse->user.dw != STGTY_STREAM) error(EXIT_BADSC, "VerifyStructure: '%s' is not a stream\n", szName); break; } sl.Remove(pse); if (*pszStructure == ',') pszStructure++; } for (pse = sl.GetHead(); pse; pse = pse->pseNext) error(EXIT_BADSC, "VerifyStructure: additional member '%s'\n", OlecsOut(pse->atc)); return pszStructure; }
// Creates a structure using the same syntax
// as VerifyStructure
char *CreateStructure(IStorage *pstg, char *pszStructure) { char szName[CWCSTORAGENAME], *psz; IStorage *pstgChild; IStream *pstmChild; char chType; SCODE sc; OLECHAR atcName[CWCSTORAGENAME];
while (*pszStructure && *pszStructure != ')') { chType = *pszStructure++; psz = szName; while (*pszStructure && *pszStructure != '(' && *pszStructure != ')' && *pszStructure != ',') *psz++ = *pszStructure++; *psz = 0; ATOOLE(szName, atcName, CWCSTORAGENAME); switch(chType) { case 'd': sc = DfGetScode(pstg->CreateStorage(atcName, STGP(STGM_READWRITE), 0, 0, &pstgChild)); if (FAILED(sc)) error(EXIT_BADSC, "CreateStructure: can't create storage " "'%s' - %s\n", szName, ScText(sc)); if (*pszStructure == '(') pszStructure = CreateStructure(pstgChild, pszStructure+1)+1; pstgChild->Release(); break; case 's': sc = DfGetScode(pstg->CreateStream(atcName, STMP(STGM_READWRITE), 0, 0, &pstmChild)); if (FAILED(sc)) error(EXIT_BADSC, "CreateStructure: can't create stream " "'%s' - %s\n", szName, ScText(sc)); pstmChild->Release(); break; } if (*pszStructure == ',') pszStructure++; } pstg->Commit(0); return pszStructure; }
// Verifies the fields of a STATSTG
void VerifyStat(STATSTG *pstat, OLECHAR *ptcsName, DWORD type, DWORD grfMode) { if (ptcsName == NULL) { if (pstat->pwcsName != NULL) error(EXIT_BADSC, "Stat name should be NULL - is %p\n", pstat->pwcsName); } else if (olecscmp(pstat->pwcsName, ptcsName)) error(EXIT_BADSC, "Stat name mismatch - has '%s' vs. '%s'\n", OlecsOut(pstat->pwcsName), OlecsOut(ptcsName)); if (pstat->type != type) error(EXIT_BADSC, "Stat type mismatch - has %lu vs. %lu\n", pstat->type, type); if (pstat->grfMode != grfMode) error(EXIT_BADSC, "Stat mode mismatch - has 0x%lX vs. 0x%lX\n", pstat->grfMode, grfMode); }
// Checks on a file's existence
BOOL Exists(OLECHAR *file) { OFSTRUCT of;
#ifndef OLEWIDECHAR
return OpenFile(file, &of, OF_EXIST | OF_SHARE_DENY_NONE) != HFILE_ERROR ? TRUE : FALSE; #else
char szName[_MAX_PATH]; wcstombs(szName, file, _MAX_PATH); return OpenFile(szName, &of, OF_EXIST | OF_SHARE_DENY_NONE) != HFILE_ERROR ? TRUE : FALSE; #endif
}
// Gets a file's length
ULONG Length(OLECHAR *file) { ULONG cb;
#ifndef WIN32
OFSTRUCT of; int hf; hf = OpenFile(file, &of, OF_READ | OF_SHARE_DENY_NONE); if (hf == HFILE_ERROR) error(EXIT_BADSC, "Length: Unable to open '%s'\n", OlecsOut(file)); cb = (ULONG)_llseek(hf, 0, SEEK_END); if (cb == (ULONG)HFILE_ERROR) error(EXIT_BADSC, "Length: Unable to get length for '%s'\n", OlecsOut(file)); _lclose(hf);
#else
// use WIN32 APIs
HANDLE hf;
#if !defined(UNICODE)
// Chicago - call ANSI CreateFile
char szName[_MAX_PATH]; if (wcstombs(szName, file, _MAX_PATH) == (size_t)-1) return 0;
hf = CreateFile ( szName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
#else
hf = CreateFile ( file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
#endif // !defined(UNICODE)
if (hf == INVALID_HANDLE_VALUE) error(EXIT_BADSC, "Length: Unable to open '%s'\n", OlecsOut(file)); cb = (ULONG)GetFileSize(hf, NULL); if (cb == (ULONG)0xFFFFFFFF) error(EXIT_BADSC, "Length: Unable to get length for '%s'\n", OlecsOut(file)); CloseHandle(hf);
#endif // !WIN32
return cb; }
// Original mode when a new mode is forced
// Used by ForceDirect, ForceTransacted and Unforce
static DWORD dwTransOld; static DWORD dwRDWOld;
// Forces direct mode to be active
// Note: this uses a static variable so it can\'t be nested
void ForceDirect(void) { dwTransOld = dwTransacted; dwTransacted = STGM_DIRECT; dwRDWOld = dwRootDenyWrite; dwRootDenyWrite = STGM_SHARE_EXCLUSIVE; }
// Forces transacted mode similarly to ForceDirect
void ForceTransacted(void) { dwTransOld = dwTransacted; dwRDWOld = dwRootDenyWrite; dwTransacted = STGM_TRANSACTED; }
// Returns to the original mode after a ForceDirect or ForceTransacted
void Unforce(void) { dwTransacted = dwTransOld; dwRootDenyWrite = dwRDWOld; }
// Equality for FILETIME
BOOL IsEqualTime(FILETIME ttTime, FILETIME ttCheck) { // File times can be off by as much as 2 seconds due to FAT rounding
LONGLONG tmTime = *(LONGLONG *)&ttTime; LONGLONG tmCheck = *(LONGLONG *)&ttCheck; LONGLONG tmDelta = tmTime - tmCheck;
return tmDelta < 20000000i64 && tmDelta > -2i64 ; }
// Get a fully qualified path for a file name
void GetFullPath(OLECHAR *file, OLECHAR *path) { #ifndef UNICODE
char buf[_MAX_PATH]; OFSTRUCT of;
OLETOA(file, buf, _MAX_PATH); OpenFile(buf, &of, OF_PARSE); ATOOLE((char *)of.szPathName, path, _MAX_PATH); #else
OLECHAR *ptcsFile;
GetFullPathName(file, _MAX_PATH, path, &ptcsFile); #endif
}
// Memory helper functions
HRESULT drtMemAlloc(ULONG ulcb, void **ppv) { HRESULT hr; IMalloc *pMalloc = NULL;
if (SUCCEEDED(DfGetScode(hr = CoGetMalloc(MEMCTX_TASK, &pMalloc)))) { *ppv = pMalloc->Alloc(ulcb); pMalloc->Release();
if (*ppv == NULL) return ResultFromScode(E_OUTOFMEMORY); }
return hr; }
void drtMemFree(void *pv) { IMalloc FAR* pMalloc; if (SUCCEEDED(GetScode(CoGetMalloc(MEMCTX_TASK, &pMalloc)))) { pMalloc->Free(pv); pMalloc->Release(); } }
#pragma pack(1)
struct SplitGuid { DWORD dw1; WORD w1; WORD w2; BYTE b[8]; }; #pragma pack()
char *GuidText(GUID const *pguid) { static char buf[39]; SplitGuid *psg = (SplitGuid *)pguid;
sprintf(buf, "{%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}", psg->dw1, psg->w1, psg->w2, psg->b[0], psg->b[1], psg->b[2], psg->b[3], psg->b[4], psg->b[5], psg->b[6], psg->b[7]); return buf; }
|