Source code of Windows XP (NT5)
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.

517 lines
13 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: util.cxx
  7. //
  8. // Contents: DRT support routines
  9. //
  10. // History: 22-Sep-92 DrewB Created
  11. //
  12. //---------------------------------------------------------------
  13. #include "headers.cxx"
  14. #pragma hdrstop
  15. #include <stdarg.h>
  16. #include <direct.h>
  17. #include <io.h>
  18. #if DBG == 1
  19. #include <dfdeb.hxx>
  20. #endif
  21. #define DEFAULT_DATA_DIR "."
  22. BOOL fExitOnFail = TRUE;
  23. char szOrigDir[_MAX_PATH] = ".";
  24. // Preserve the current directory and change
  25. // directory into the data directory
  26. void SetData(void)
  27. {
  28. char *pszDataDir;
  29. _getcwd(szOrigDir, _MAX_PATH);
  30. pszDataDir = getenv("DRTDATA");
  31. if (pszDataDir == NULL)
  32. pszDataDir = DEFAULT_DATA_DIR;
  33. _chdir(pszDataDir);
  34. }
  35. // Clean up the data directory
  36. void CleanData(void)
  37. {
  38. _unlink(OlecsOut(DRTDF));
  39. _unlink(OlecsOut(MARSHALDF));
  40. }
  41. // Restore the original directory
  42. void UnsetData(void)
  43. {
  44. _chdir(szOrigDir);
  45. }
  46. // Output a message if fVerbose is true
  47. void out(char *fmt, ...)
  48. {
  49. va_list args;
  50. if (fVerbose)
  51. {
  52. va_start(args, fmt);
  53. vprintf(fmt, args);
  54. va_end(args);
  55. }
  56. }
  57. // Print out an error message and terminate the DRT
  58. void error(int code, char *fmt, ...)
  59. {
  60. va_list args;
  61. va_start(args, fmt);
  62. #if !defined(FLAT) || defined(FPRINTF_WORKS)
  63. fprintf(stderr, "** Fatal error **: ");
  64. vfprintf(stderr, fmt, args);
  65. #else
  66. printf("** Fatal error **: ");
  67. vprintf(fmt, args);
  68. #endif
  69. va_end(args);
  70. CleanData();
  71. UnsetData();
  72. exit(code);
  73. }
  74. // Converts a TCHAR string to a char pointer in a temporary buffer
  75. // This implementation treats the conversion buffer as a circular
  76. // buffer so more than one string can be held (depending on the size
  77. // of the strings)
  78. #define BUFSIZE 1024
  79. char *OlecsOut(OLECHAR const *ptcs)
  80. {
  81. #ifdef OLEWIDECHAR
  82. static char szBuffer[BUFSIZE];
  83. static char *pszBuf = szBuffer;
  84. char *pszTmp;
  85. if (ptcs == NULL)
  86. return NULL;
  87. if (wcslen(ptcs) >= (size_t)(BUFSIZE-(pszBuf-szBuffer)))
  88. pszBuf = szBuffer;
  89. wcstombs(pszBuf, ptcs, BUFSIZE);
  90. szBuffer[BUFSIZE-1] = 0;
  91. pszTmp = pszBuf;
  92. pszBuf += strlen(pszBuf)+1;
  93. return pszTmp;
  94. #else
  95. return (char *)ptcs;
  96. #endif
  97. }
  98. typedef struct
  99. {
  100. SCODE sc;
  101. char *text;
  102. } StatusCodeText;
  103. static StatusCodeText scodes[] =
  104. {
  105. S_OK, "S_OK",
  106. S_FALSE, "S_FALSE",
  107. STG_E_INVALIDFUNCTION, "STG_E_INVALIDFUNCTION",
  108. STG_E_FILENOTFOUND, "STG_E_FILENOTFOUND",
  109. STG_E_PATHNOTFOUND, "STG_E_PATHNOTFOUND",
  110. STG_E_TOOMANYOPENFILES, "STG_E_TOOMANYOPENFILES",
  111. STG_E_ACCESSDENIED, "STG_E_ACCESSDENIED",
  112. STG_E_INVALIDHANDLE, "STG_E_INVALIDHANDLE",
  113. STG_E_INSUFFICIENTMEMORY, "STG_E_INSUFFICIENTMEMORY",
  114. STG_E_INVALIDPOINTER, "STG_E_INVALIDPOINTER",
  115. STG_E_NOMOREFILES, "STG_E_NOMOREFILES",
  116. STG_E_DISKISWRITEPROTECTED, "STG_E_DISKISWRITEPROTECTED",
  117. STG_E_SEEKERROR, "STG_E_SEEKERROR",
  118. STG_E_WRITEFAULT, "STG_E_WRITEFAULT",
  119. STG_E_READFAULT, "STG_E_READFAULT",
  120. STG_E_SHAREVIOLATION, "STG_E_SHAREVIOLATION",
  121. STG_E_LOCKVIOLATION, "STG_E_LOCKVIOLATION",
  122. STG_E_FILEALREADYEXISTS, "STG_E_FILEALREADYEXISTS",
  123. STG_E_INVALIDPARAMETER, "STG_E_INVALIDPARAMETER",
  124. STG_E_MEDIUMFULL, "STG_E_MEDIUMFULL",
  125. STG_E_ABNORMALAPIEXIT, "STG_E_ABNORMALAPIEXIT",
  126. STG_E_INVALIDHEADER, "STG_E_INVALIDHEADER",
  127. STG_E_INVALIDNAME, "STG_E_INVALIDNAME",
  128. STG_E_UNKNOWN, "STG_E_UNKNOWN",
  129. STG_E_UNIMPLEMENTEDFUNCTION, "STG_E_UNIMPLEMENTEDFUNCTION",
  130. STG_E_INVALIDFLAG, "STG_E_INVALIDFLAG",
  131. STG_E_INUSE, "STG_E_INUSE",
  132. STG_E_NOTCURRENT, "STG_E_NOTCURRENT",
  133. STG_E_REVERTED, "STG_E_REVERTED",
  134. STG_E_CANTSAVE, "STG_E_CANTSAVE",
  135. STG_E_OLDFORMAT, "STG_E_OLDFORMAT",
  136. STG_E_OLDDLL, "STG_E_OLDDLL",
  137. STG_E_SHAREREQUIRED, "STG_E_SHAREREQUIRED",
  138. STG_E_NOTFILEBASEDSTORAGE, "STG_E_NOTFILEBASEDSTORAGE",
  139. STG_E_EXTANTMARSHALLINGS, "STG_E_EXTANTMARSHALLINGS",
  140. STG_S_CONVERTED, "STG_S_CONVERTED"
  141. };
  142. #define NSCODETEXT (sizeof(scodes)/sizeof(scodes[0]))
  143. // Convert a status code to text
  144. char *ScText(SCODE sc)
  145. {
  146. int i;
  147. for (i = 0; i<NSCODETEXT; i++)
  148. if (scodes[i].sc == sc)
  149. return scodes[i].text;
  150. return "?";
  151. }
  152. // Output a call result and check for failure
  153. HRESULT Result(HRESULT hr)
  154. {
  155. SCODE sc;
  156. sc = DfGetScode(hr);
  157. out(" - %s (0x%lX)\n", ScText(sc), sc);
  158. if (FAILED(sc) && fExitOnFail)
  159. error(EXIT_BADSC, "Unexpected call failure\n");
  160. return hr;
  161. }
  162. // Perform Result() when the expectation is failure
  163. HRESULT IllResult(char *pszText, HRESULT hr)
  164. {
  165. SCODE sc;
  166. sc = DfGetScode(hr);
  167. out("%s - %s (0x%lX)\n", pszText, ScText(sc), sc);
  168. if (SUCCEEDED(sc) && fExitOnFail)
  169. error(EXIT_BADSC, "Unexpected call success\n");
  170. return hr;
  171. }
  172. // DEBUG - Check for memory leaks
  173. void CheckMemory(void)
  174. {
  175. #if DBG == 1
  176. if (fVerbose || DfGetMemAlloced() != 0)
  177. {
  178. out("Memory held: %lu bytes\n", DfGetMemAlloced());
  179. if (DfGetMemAlloced() != 0)
  180. {
  181. DfPrintAllocs();
  182. error(EXIT_BADSC, "Memory leak\n");
  183. }
  184. }
  185. #endif
  186. }
  187. // DEBUG - Set the debugging level
  188. void SetDebug(ULONG ulDf, ULONG ulMsf)
  189. {
  190. #if DBG == 1
  191. DfDebug(ulDf, ulMsf);
  192. #endif
  193. }
  194. // Check whether a given storage has a certain
  195. // structure or not
  196. // Structure is given as a string with elements:
  197. // <Type><Name><Options>[,...]
  198. // Type - d for docfile and s for stream
  199. // Name - Characters up to a '(' or ','
  200. // Options - For a docfile, you can specify a recursive check
  201. // in parentheses
  202. //
  203. // Example: dDocfile(sStream,dDocfile)
  204. char *VerifyStructure(IStorage *pstg, char *pszStructure)
  205. {
  206. char szName[CWCSTORAGENAME], *psz;
  207. IStorage *pstgChild;
  208. char chType;
  209. SCODE sc;
  210. CStrList sl;
  211. SStrEntry *pse;
  212. IEnumSTATSTG *penm;
  213. STATSTG stat;
  214. OLECHAR atcName[CWCSTORAGENAME];
  215. if (FAILED(sc = DfGetScode(pstg->EnumElements(0, NULL, 0, &penm))))
  216. error(EXIT_BADSC, "VerifyStructure: Unable to create enumerator - "
  217. "%s (0x%lX)\n", ScText(sc), sc);
  218. for (;;)
  219. {
  220. sc = DfGetScode(penm->Next(1, &stat, NULL));
  221. if (sc == S_FALSE)
  222. break;
  223. else if (FAILED(sc))
  224. error(EXIT_BADSC, "VerifyStructure: Unable to enumerate - "
  225. "%s (0x%lX)\n", ScText(sc), sc);
  226. pse = sl.Add(stat.pwcsName);
  227. if (pse == NULL)
  228. error(EXIT_OOM, "VerifyStructure: Unable to allocate string\n");
  229. pse->user.dw = stat.type;
  230. drtMemFree(stat.pwcsName);
  231. }
  232. penm->Release();
  233. while (*pszStructure && *pszStructure != ')')
  234. {
  235. chType = *pszStructure++;
  236. psz = szName;
  237. while (*pszStructure && *pszStructure != '(' &&
  238. *pszStructure != ')' && *pszStructure != ',')
  239. *psz++ = *pszStructure++;
  240. *psz = 0;
  241. ATOOLE(szName, atcName, CWCSTORAGENAME);
  242. pse = sl.Find(atcName);
  243. if (pse == NULL)
  244. error(EXIT_BADSC, "VerifyStructure: '%s' not found\n", szName);
  245. switch(chType)
  246. {
  247. case 'd':
  248. if (pse->user.dw != STGTY_STORAGE)
  249. error(EXIT_BADSC, "VerifyStructure: '%s' is not a storage\n",
  250. szName);
  251. sc = DfGetScode(pstg->OpenStorage(atcName, NULL,
  252. STGP(STGM_READWRITE), NULL,
  253. 0, &pstgChild));
  254. if (FAILED(sc))
  255. error(EXIT_BADSC, "VerifyStructure: can't open storage "
  256. "'%s' - %s\n", szName, ScText(sc));
  257. if (*pszStructure == '(')
  258. pszStructure = VerifyStructure(pstgChild, pszStructure+1)+1;
  259. pstgChild->Release();
  260. break;
  261. case 's':
  262. if (pse->user.dw != STGTY_STREAM)
  263. error(EXIT_BADSC, "VerifyStructure: '%s' is not a stream\n",
  264. szName);
  265. break;
  266. }
  267. sl.Remove(pse);
  268. if (*pszStructure == ',')
  269. pszStructure++;
  270. }
  271. for (pse = sl.GetHead(); pse; pse = pse->pseNext)
  272. error(EXIT_BADSC, "VerifyStructure: additional member '%s'\n",
  273. OlecsOut(pse->atc));
  274. return pszStructure;
  275. }
  276. // Creates a structure using the same syntax
  277. // as VerifyStructure
  278. char *CreateStructure(IStorage *pstg, char *pszStructure)
  279. {
  280. char szName[CWCSTORAGENAME], *psz;
  281. IStorage *pstgChild;
  282. IStream *pstmChild;
  283. char chType;
  284. SCODE sc;
  285. OLECHAR atcName[CWCSTORAGENAME];
  286. while (*pszStructure && *pszStructure != ')')
  287. {
  288. chType = *pszStructure++;
  289. psz = szName;
  290. while (*pszStructure && *pszStructure != '(' &&
  291. *pszStructure != ')' && *pszStructure != ',')
  292. *psz++ = *pszStructure++;
  293. *psz = 0;
  294. ATOOLE(szName, atcName, CWCSTORAGENAME);
  295. switch(chType)
  296. {
  297. case 'd':
  298. sc = DfGetScode(pstg->CreateStorage(atcName, STGP(STGM_READWRITE),
  299. 0, 0, &pstgChild));
  300. if (FAILED(sc))
  301. error(EXIT_BADSC, "CreateStructure: can't create storage "
  302. "'%s' - %s\n", szName, ScText(sc));
  303. if (*pszStructure == '(')
  304. pszStructure = CreateStructure(pstgChild, pszStructure+1)+1;
  305. pstgChild->Release();
  306. break;
  307. case 's':
  308. sc = DfGetScode(pstg->CreateStream(atcName, STMP(STGM_READWRITE),
  309. 0, 0, &pstmChild));
  310. if (FAILED(sc))
  311. error(EXIT_BADSC, "CreateStructure: can't create stream "
  312. "'%s' - %s\n", szName, ScText(sc));
  313. pstmChild->Release();
  314. break;
  315. }
  316. if (*pszStructure == ',')
  317. pszStructure++;
  318. }
  319. pstg->Commit(0);
  320. return pszStructure;
  321. }
  322. // Verifies the fields of a STATSTG
  323. void VerifyStat(STATSTG *pstat, OLECHAR *ptcsName, DWORD type, DWORD grfMode)
  324. {
  325. if (ptcsName == NULL)
  326. {
  327. if (pstat->pwcsName != NULL)
  328. error(EXIT_BADSC, "Stat name should be NULL - is %p\n",
  329. pstat->pwcsName);
  330. }
  331. else if (olecscmp(pstat->pwcsName, ptcsName))
  332. error(EXIT_BADSC, "Stat name mismatch - has '%s' vs. '%s'\n",
  333. OlecsOut(pstat->pwcsName), OlecsOut(ptcsName));
  334. if (pstat->type != type)
  335. error(EXIT_BADSC, "Stat type mismatch - has %lu vs. %lu\n",
  336. pstat->type, type);
  337. if (pstat->grfMode != grfMode)
  338. error(EXIT_BADSC, "Stat mode mismatch - has 0x%lX vs. 0x%lX\n",
  339. pstat->grfMode, grfMode);
  340. }
  341. // Checks on a file's existence
  342. BOOL Exists(OLECHAR *file)
  343. {
  344. OFSTRUCT of;
  345. #ifndef OLEWIDECHAR
  346. return OpenFile(file, &of, OF_EXIST | OF_SHARE_DENY_NONE) !=
  347. HFILE_ERROR ? TRUE : FALSE;
  348. #else
  349. char szName[_MAX_PATH];
  350. wcstombs(szName, file, _MAX_PATH);
  351. return OpenFile(szName, &of, OF_EXIST | OF_SHARE_DENY_NONE) !=
  352. HFILE_ERROR ? TRUE : FALSE;
  353. #endif
  354. }
  355. // Gets a file's length
  356. ULONG Length(OLECHAR *file)
  357. {
  358. OFSTRUCT of;
  359. ULONG cb;
  360. int hf;
  361. #ifndef OLEWIDECHAR
  362. hf = OpenFile(file, &of, OF_READ | OF_SHARE_DENY_NONE);
  363. #else
  364. char szName[_MAX_PATH];
  365. wcstombs(szName, file, _MAX_PATH);
  366. hf = OpenFile(szName, &of, OF_READ | OF_SHARE_DENY_NONE);
  367. #endif
  368. if (hf == HFILE_ERROR)
  369. error(EXIT_BADSC, "Length: Unable to open '%s'\n", OlecsOut(file));
  370. cb = (ULONG)_llseek(hf, 0, SEEK_END);
  371. if (cb == (ULONG)HFILE_ERROR)
  372. error(EXIT_BADSC, "Length: Unable to get length for '%s'\n",
  373. OlecsOut(file));
  374. _lclose(hf);
  375. return cb;
  376. }
  377. // Original mode when a new mode is forced
  378. // Used by ForceDirect, ForceTransacted and Unforce
  379. static DWORD dwTransOld;
  380. static DWORD dwRDWOld;
  381. // Forces direct mode to be active
  382. // Note: this uses a static variable so it can\'t be nested
  383. void ForceDirect(void)
  384. {
  385. dwTransOld = dwTransacted;
  386. dwTransacted = STGM_DIRECT;
  387. dwRDWOld = dwRootDenyWrite;
  388. dwRootDenyWrite = STGM_SHARE_EXCLUSIVE;
  389. }
  390. // Forces transacted mode similarly to ForceDirect
  391. void ForceTransacted(void)
  392. {
  393. dwTransOld = dwTransacted;
  394. dwRDWOld = dwRootDenyWrite;
  395. dwTransacted = STGM_TRANSACTED;
  396. }
  397. // Returns to the original mode after a ForceDirect or ForceTransacted
  398. void Unforce(void)
  399. {
  400. dwTransacted = dwTransOld;
  401. dwRootDenyWrite = dwRDWOld;
  402. }
  403. // Equality for FILETIME
  404. BOOL IsEqualTime(FILETIME ttTime, FILETIME ttCheck)
  405. {
  406. return ttTime.dwLowDateTime == ttCheck.dwLowDateTime &&
  407. ttTime.dwHighDateTime == ttCheck.dwHighDateTime;
  408. }
  409. // Get a fully qualified path for a file name
  410. void GetFullPath(OLECHAR *file, OLECHAR *path)
  411. {
  412. #ifndef UNICODE
  413. char buf[_MAX_PATH];
  414. OFSTRUCT of;
  415. OLETOA(file, buf, _MAX_PATH);
  416. OpenFile(buf, &of, OF_PARSE);
  417. ATOOLE((char *)of.szPathName, path, _MAX_PATH);
  418. #else
  419. OLECHAR *ptcsFile;
  420. GetFullPathName(file, _MAX_PATH, path, &ptcsFile);
  421. #endif
  422. }
  423. // Memory helper functions
  424. HRESULT drtMemAlloc(ULONG ulcb, void **ppv)
  425. {
  426. HRESULT hr;
  427. IMalloc *pMalloc = NULL;
  428. if (SUCCEEDED(DfGetScode(hr = CoGetMalloc(MEMCTX_TASK, &pMalloc))))
  429. {
  430. *ppv = pMalloc->Alloc(ulcb);
  431. pMalloc->Release();
  432. if (*ppv == NULL)
  433. return ResultFromScode(E_OUTOFMEMORY);
  434. }
  435. return hr;
  436. }
  437. void drtMemFree(void *pv)
  438. {
  439. IMalloc FAR* pMalloc;
  440. if (SUCCEEDED(GetScode(CoGetMalloc(MEMCTX_TASK, &pMalloc))))
  441. {
  442. pMalloc->Free(pv);
  443. pMalloc->Release();
  444. }
  445. }
  446. #pragma pack(1)
  447. struct SplitGuid
  448. {
  449. DWORD dw1;
  450. WORD w1;
  451. WORD w2;
  452. BYTE b[8];
  453. };
  454. #pragma pack()
  455. char *GuidText(GUID const *pguid)
  456. {
  457. static char buf[39];
  458. SplitGuid *psg = (SplitGuid *)pguid;
  459. sprintf(buf, "{%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  460. psg->dw1, psg->w1, psg->w2, psg->b[0], psg->b[1], psg->b[2],
  461. psg->b[3], psg->b[4], psg->b[5], psg->b[6], psg->b[7]);
  462. return buf;
  463. }