Leaked source code of windows server 2003
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.

1463 lines
36 KiB

  1. //+============================================================================
  2. //
  3. // File: PropDump.cxx
  4. //
  5. // Purpose:
  6. // This file contains routines to dump all the properties of all
  7. // the property sets of a DocFile. It's started by calling
  8. // DumpOleStorage().
  9. //
  10. //+============================================================================
  11. // --------
  12. // Includes
  13. // --------
  14. #include "pch.cxx"
  15. // -------
  16. // Globals
  17. // -------
  18. OLECHAR *oszDays[] =
  19. {
  20. OLESTR("Sun"),
  21. OLESTR("Mon"),
  22. OLESTR("Tue"),
  23. OLESTR("Wed"),
  24. OLESTR("Thu"),
  25. OLESTR("Fri"),
  26. OLESTR("Sat")
  27. };
  28. OLECHAR *oszMonths[] =
  29. {
  30. OLESTR("Jan"), OLESTR("Feb"), OLESTR("Mar"), OLESTR("Apr"), OLESTR("May"), OLESTR("Jun"),
  31. OLESTR("Jul"), OLESTR("Aug"), OLESTR("Sep"), OLESTR("Oct"), OLESTR("Nov"), OLESTR("Dec")
  32. };
  33. //+----------------------------------------------------------------------------
  34. //+----------------------------------------------------------------------------
  35. OLECHAR *
  36. oszft(FILETIME *pft)
  37. {
  38. static OLECHAR oszbuf[32];
  39. #ifdef _MAC
  40. soprintf( oszbuf, OLESTR("%08X-%08X"), pft->dwHighDateTime, pft->dwLowDateTime );
  41. #else
  42. FILETIME ftlocal;
  43. SYSTEMTIME st;
  44. oszbuf[0] = '\0';
  45. if (pft->dwHighDateTime != 0 || pft->dwLowDateTime != 0)
  46. {
  47. if (!FileTimeToLocalFileTime(pft, &ftlocal) ||
  48. !FileTimeToSystemTime(&ftlocal, &st))
  49. {
  50. return(OLESTR("Time???"));
  51. }
  52. soprintf(
  53. oszbuf,
  54. OLESTR("%s %s %2d %2d:%02d:%02d %4d"),
  55. oszDays[st.wDayOfWeek],
  56. oszMonths[st.wMonth - 1],
  57. st.wDay,
  58. st.wHour,
  59. st.wMinute,
  60. st.wSecond,
  61. st.wYear);
  62. }
  63. #endif
  64. return(oszbuf);
  65. }
  66. VOID
  67. DumpTime(OLECHAR *pozname, FILETIME *pft)
  68. {
  69. LARGE_INTEGER UNALIGNED *pli = (LARGE_INTEGER UNALIGNED *) pft;
  70. ASYNC_PRINTF(
  71. "%s%08lx:%08lx%hs%s\n",
  72. pozname,
  73. pli->HighPart,
  74. pli->LowPart,
  75. pli->QuadPart == 0? g_szEmpty : " - ",
  76. oszft((FILETIME *) pft));
  77. }
  78. VOID
  79. PrintGuid(GUID *pguid)
  80. {
  81. ASYNC_PRINTF(
  82. "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  83. pguid->Data1,
  84. pguid->Data2,
  85. pguid->Data3,
  86. pguid->Data4[0],
  87. pguid->Data4[1],
  88. pguid->Data4[2],
  89. pguid->Data4[3],
  90. pguid->Data4[4],
  91. pguid->Data4[5],
  92. pguid->Data4[6],
  93. pguid->Data4[7]);
  94. }
  95. VOID
  96. ListPropSetHeader(
  97. STATPROPSETSTG *pspss,
  98. OLECHAR *poszName)
  99. {
  100. BOOLEAN fDocumentSummarySection2;
  101. OLECHAR oszStream[CCH_PROPSETSZ];
  102. fDocumentSummarySection2 = (BOOLEAN)
  103. memcmp(&pspss->fmtid, &FMTID_UserDefinedProperties, sizeof(GUID)) == 0;
  104. ASYNC_PRINTF(" Property set ");
  105. PrintGuid(&pspss->fmtid);
  106. RtlGuidToPropertySetName(&pspss->fmtid, oszStream);
  107. ASYNC_OPRINTF(
  108. OLESTR("\n %hs Name %s"),
  109. (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)?
  110. "Embedding" : "Stream",
  111. oszStream);
  112. if (poszName != NULL || fDocumentSummarySection2)
  113. {
  114. ASYNC_OPRINTF(
  115. OLESTR(" (%s)"),
  116. poszName != NULL? poszName : OLESTR("User defined properties"));
  117. }
  118. ASYNC_PRINTF("\n");
  119. if (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)
  120. {
  121. DumpTime(OLESTR(" Create Time "), &pspss->ctime);
  122. }
  123. DumpTime(OLESTR(" Modify Time "), &pspss->mtime);
  124. if (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)
  125. {
  126. DumpTime(OLESTR(" Access Time "), &pspss->atime);
  127. }
  128. }
  129. typedef enum _PUBLICPROPSET
  130. {
  131. PUBPS_UNKNOWN = 0,
  132. PUBPS_SUMMARYINFO = 3,
  133. PUBPS_DOCSUMMARYINFO = 4,
  134. PUBPS_USERDEFINED = 5,
  135. } PUBLICPROPSET;
  136. #define BSTRLEN(bstrVal) *((ULONG *) bstrVal - 1)
  137. ULONG
  138. SizeProp(PROPVARIANT *pv)
  139. {
  140. ULONG j;
  141. ULONG cbprop = 0;
  142. switch (pv->vt)
  143. {
  144. default:
  145. case VT_EMPTY:
  146. case VT_NULL:
  147. break;
  148. case VT_UI1:
  149. cbprop = sizeof(pv->bVal);
  150. break;
  151. case VT_I2:
  152. case VT_UI2:
  153. case VT_BOOL:
  154. cbprop = sizeof(pv->iVal);
  155. break;
  156. case VT_I4:
  157. case VT_UI4:
  158. case VT_R4:
  159. case VT_ERROR:
  160. cbprop = sizeof(pv->lVal);
  161. break;
  162. case VT_I8:
  163. case VT_UI8:
  164. case VT_R8:
  165. case VT_CY:
  166. case VT_DATE:
  167. case VT_FILETIME:
  168. cbprop = sizeof(pv->hVal);
  169. break;
  170. case VT_CLSID:
  171. cbprop = sizeof(*pv->puuid);
  172. break;
  173. case VT_BLOB_OBJECT:
  174. case VT_BLOB:
  175. cbprop = pv->blob.cbSize + sizeof(pv->blob.cbSize);
  176. break;
  177. case VT_CF:
  178. cbprop = sizeof(pv->pclipdata->cbSize) +
  179. pv->pclipdata->cbSize;
  180. break;
  181. case VT_BSTR:
  182. // count + string
  183. cbprop = sizeof(ULONG);
  184. if (pv->bstrVal != NULL)
  185. {
  186. cbprop += BSTRLEN(pv->bstrVal);
  187. }
  188. break;
  189. case VT_LPSTR:
  190. // count + string + null char
  191. cbprop = sizeof(ULONG);
  192. if (pv->pszVal != NULL)
  193. {
  194. cbprop += strlen(pv->pszVal) + 1;
  195. }
  196. break;
  197. case VT_STREAM:
  198. case VT_STREAMED_OBJECT:
  199. case VT_STORAGE:
  200. case VT_STORED_OBJECT:
  201. case VT_LPWSTR:
  202. // count + string + null char
  203. cbprop = sizeof(ULONG);
  204. if (pv->pwszVal != NULL)
  205. {
  206. cbprop += sizeof(pv->pwszVal[0]) * (wcslen(pv->pwszVal) + 1);
  207. }
  208. break;
  209. // vectors
  210. case VT_VECTOR | VT_UI1:
  211. cbprop = sizeof(pv->caub.cElems) +
  212. pv->caub.cElems * sizeof(pv->caub.pElems[0]);
  213. break;
  214. case VT_VECTOR | VT_I2:
  215. case VT_VECTOR | VT_UI2:
  216. case VT_VECTOR | VT_BOOL:
  217. cbprop = sizeof(pv->cai.cElems) +
  218. pv->cai.cElems * sizeof(pv->cai.pElems[0]);
  219. break;
  220. case VT_VECTOR | VT_I4:
  221. case VT_VECTOR | VT_UI4:
  222. case VT_VECTOR | VT_R4:
  223. case VT_VECTOR | VT_ERROR:
  224. cbprop = sizeof(pv->cal.cElems) +
  225. pv->cal.cElems * sizeof(pv->cal.pElems[0]);
  226. break;
  227. case VT_VECTOR | VT_I8:
  228. case VT_VECTOR | VT_UI8:
  229. case VT_VECTOR | VT_R8:
  230. case VT_VECTOR | VT_CY:
  231. case VT_VECTOR | VT_DATE:
  232. case VT_VECTOR | VT_FILETIME:
  233. cbprop = sizeof(pv->cah.cElems) +
  234. pv->cah.cElems * sizeof(pv->cah.pElems[0]);
  235. break;
  236. case VT_VECTOR | VT_CLSID:
  237. cbprop = sizeof(pv->cauuid.cElems) +
  238. pv->cauuid.cElems * sizeof(pv->cauuid.pElems[0]);
  239. break;
  240. case VT_VECTOR | VT_CF:
  241. cbprop = sizeof(pv->caclipdata.cElems);
  242. for (j = 0; j < pv->caclipdata.cElems; j++)
  243. {
  244. cbprop += sizeof(pv->caclipdata.pElems[j].cbSize) +
  245. DwordAlign(pv->caclipdata.pElems[j].cbSize);
  246. }
  247. break;
  248. case VT_VECTOR | VT_BSTR:
  249. cbprop = sizeof(pv->cabstr.cElems);
  250. for (j = 0; j < pv->cabstr.cElems; j++)
  251. {
  252. // count + string + null char
  253. cbprop += sizeof(ULONG);
  254. if (pv->cabstr.pElems[j] != NULL)
  255. {
  256. cbprop += DwordAlign(BSTRLEN(pv->cabstr.pElems[j]));
  257. }
  258. }
  259. break;
  260. case VT_VECTOR | VT_LPSTR:
  261. cbprop = sizeof(pv->calpstr.cElems);
  262. for (j = 0; j < pv->calpstr.cElems; j++)
  263. {
  264. // count + string + null char
  265. cbprop += sizeof(ULONG);
  266. if (pv->calpstr.pElems[j] != NULL)
  267. {
  268. cbprop += DwordAlign(strlen(pv->calpstr.pElems[j]) + 1);
  269. }
  270. }
  271. break;
  272. case VT_VECTOR | VT_LPWSTR:
  273. cbprop = sizeof(pv->calpwstr.cElems);
  274. for (j = 0; j < pv->calpwstr.cElems; j++)
  275. {
  276. // count + string + null char
  277. cbprop += sizeof(ULONG);
  278. if (pv->calpwstr.pElems[j] != NULL)
  279. {
  280. cbprop += DwordAlign(
  281. sizeof(pv->calpwstr.pElems[j][0]) *
  282. (wcslen(pv->calpwstr.pElems[j]) + 1));
  283. }
  284. }
  285. break;
  286. case VT_VECTOR | VT_VARIANT:
  287. cbprop = sizeof(pv->calpwstr.cElems);
  288. for (j = 0; j < pv->calpwstr.cElems; j++)
  289. {
  290. cbprop += SizeProp(&pv->capropvar.pElems[j]);
  291. }
  292. break;
  293. }
  294. return(DwordAlign(cbprop) + DwordAlign(sizeof(pv->vt)));
  295. }
  296. PUBLICPROPSET
  297. GuidToPropSet(GUID *pguid)
  298. {
  299. PUBLICPROPSET pubps = PUBPS_UNKNOWN;
  300. if (pguid != NULL)
  301. {
  302. if (memcmp(pguid, &FMTID_SummaryInformation, sizeof(GUID)) == 0)
  303. {
  304. pubps = PUBPS_SUMMARYINFO;
  305. }
  306. else if (memcmp(pguid, &FMTID_DocSummaryInformation, sizeof(GUID)) == 0)
  307. {
  308. pubps = PUBPS_DOCSUMMARYINFO;
  309. }
  310. else if (memcmp(pguid, &FMTID_UserDefinedProperties, sizeof(GUID)) == 0)
  311. {
  312. pubps = PUBPS_USERDEFINED;
  313. }
  314. }
  315. return(pubps);
  316. }
  317. char
  318. PrintableChar(char ch)
  319. {
  320. if (ch < ' ' || ch > '~')
  321. {
  322. ch = '.';
  323. }
  324. return(ch);
  325. }
  326. VOID
  327. DumpHex(BYTE *pb, ULONG cb, ULONG base)
  328. {
  329. char *pszsep;
  330. ULONG r, i, cbremain = 0;
  331. int fZero = FALSE;
  332. int fSame = FALSE;
  333. for (r = 0; r < cb; r += 16)
  334. {
  335. cbremain = cb - r;
  336. if (r != 0 && cbremain >= 16)
  337. {
  338. if (pb[r] == 0)
  339. {
  340. ULONG j;
  341. for (j = r + 1; j < cb; j++)
  342. {
  343. if (pb[j] != 0)
  344. {
  345. break;
  346. }
  347. }
  348. if (j == cb)
  349. {
  350. fZero = TRUE;
  351. break;
  352. }
  353. }
  354. if (memcmp(&pb[r], &pb[r - 16], 16) == 0)
  355. {
  356. fSame = TRUE;
  357. continue;
  358. }
  359. }
  360. if (fSame)
  361. {
  362. ASYNC_PRINTF("\n\t *");
  363. fSame = FALSE;
  364. }
  365. for (i = 0; i < min(cbremain, 16); i++)
  366. {
  367. pszsep = " ";
  368. if ((i % 8) == 0) // 0 or 8
  369. {
  370. pszsep = " ";
  371. if (i == 0) // 0
  372. {
  373. // start a new line
  374. ASYNC_PRINTF("%s %04x:", r == 0? "" : "\n", r + base);
  375. pszsep = " ";
  376. }
  377. }
  378. ASYNC_PRINTF("%s%02x", pszsep, pb[r + i]);
  379. }
  380. if (i != 0)
  381. {
  382. ASYNC_PRINTF("%*s", 3 + (16 - i)*3 + ((i <= 8)? 1 : 0), "");
  383. for (i = 0; i < min(cbremain, 16); i++)
  384. {
  385. ASYNC_PRINTF("%c", PrintableChar(pb[r + i]));
  386. }
  387. }
  388. }
  389. if (r != 0)
  390. {
  391. ASYNC_PRINTF("\n");
  392. }
  393. if (fZero)
  394. {
  395. ASYNC_PRINTF(" Remaining %lx bytes are zero\n", cbremain);
  396. }
  397. }
  398. // Property Id's for Summary Info
  399. #define PID_TITLE 0x00000002L // VT_LPSTR
  400. #define PID_SUBJECT 0x00000003L // VT_LPSTR
  401. #define PID_AUTHOR 0x00000004L // VT_LPSTR
  402. #define PID_KEYWORDS 0x00000005L // VT_LPSTR
  403. #define PID_COMMENTS 0x00000006L // VT_LPSTR
  404. #define PID_TEMPLATE 0x00000007L // VT_LPSTR
  405. #define PID_LASTAUTHOR 0x00000008L // VT_LPSTR
  406. #define PID_REVNUMBER 0x00000009L // VT_LPSTR
  407. #define PID_EDITTIME 0x0000000aL // VT_FILETIME
  408. #define PID_LASTPRINTED 0x0000000bL // VT_FILETIME
  409. #define PID_CREATE_DTM 0x0000000cL // VT_FILETIME
  410. #define PID_LASTSAVE_DTM 0x0000000dL // VT_FILETIME
  411. #define PID_PAGECOUNT 0x0000000eL // VT_I4
  412. #define PID_WORDCOUNT 0x0000000fL // VT_I4
  413. #define PID_CHARCOUNT 0x00000010L // VT_I4
  414. #define PID_THUMBNAIL 0x00000011L // VT_CF
  415. #define PID_APPNAME 0x00000012L // VT_LPSTR
  416. #define PID_SECURITY_DSI 0x00000013L // VT_I4
  417. // Property Id's for Document Summary Info
  418. #define PID_CATEGORY 0x00000002L // VT_LPSTR
  419. #define PID_PRESFORMAT 0x00000003L // VT_LPSTR
  420. #define PID_BYTECOUNT 0x00000004L // VT_I4
  421. #define PID_LINECOUNT 0x00000005L // VT_I4
  422. #define PID_PARACOUNT 0x00000006L // VT_I4
  423. #define PID_SLIDECOUNT 0x00000007L // VT_I4
  424. #define PID_NOTECOUNT 0x00000008L // VT_I4
  425. #define PID_HIDDENCOUNT 0x00000009L // VT_I4
  426. #define PID_MMCLIPCOUNT 0x0000000aL // VT_I4
  427. #define PID_SCALE 0x0000000bL // VT_BOOL
  428. #define PID_HEADINGPAIR 0x0000000cL // VT_VECTOR | VT_VARIANT
  429. #define PID_DOCPARTS 0x0000000dL // VT_VECTOR | VT_LPSTR
  430. #define PID_MANAGER 0x0000000eL // VT_LPSTR
  431. #define PID_COMPANY 0x0000000fL // VT_LPSTR
  432. #define PID_LINKSDIRTY 0x00000010L // VT_BOOL
  433. #define PID_CCHWITHSPACES 0x00000011L // VT_I4
  434. #define PID_GUID 0x00000012L // VT_LPSTR
  435. #define PID_SHAREDDOC 0x00000013L // VT_BOOL
  436. #define PID_LINKBASE 0x00000014L // VT_LPSTR
  437. #define PID_HLINKS 0x00000015L // VT_VECTOR | VT_VARIANT
  438. #define PID_HYPERLINKSCHANGED 0x00000016L // VT_BOOL
  439. VOID
  440. DisplayProps(
  441. GUID *pguid,
  442. ULONG cprop,
  443. PROPID apid[],
  444. STATPROPSTG asps[],
  445. PROPVARIANT *av,
  446. BOOLEAN fsumcat,
  447. ULONG *pcbprop)
  448. {
  449. PROPVARIANT *pv;
  450. PROPVARIANT *pvend;
  451. STATPROPSTG *psps;
  452. BOOLEAN fVariantVector;
  453. PUBLICPROPSET pubps;
  454. fVariantVector = (asps == NULL);
  455. pubps = GuidToPropSet(pguid);
  456. pvend = &av[cprop];
  457. for (pv = av, psps = asps; pv < pvend; pv++, psps++)
  458. {
  459. ULONG j;
  460. ULONG cbprop;
  461. PROPID propid;
  462. OLECHAR *postrName;
  463. char *psz;
  464. BOOLEAN fNewLine = TRUE;
  465. int ccol;
  466. static char szNoFormat[] = " (no display format)";
  467. char achvt[19 + 8 + 1];
  468. cbprop = SizeProp(pv);
  469. *pcbprop += cbprop;
  470. postrName = NULL;
  471. if (asps != NULL)
  472. {
  473. propid = psps->propid;
  474. postrName = psps->lpwstrName;
  475. }
  476. else
  477. {
  478. ASSERT(apid != NULL);
  479. propid = apid[0];
  480. }
  481. ASYNC_PRINTF(" ");
  482. ccol = 0;
  483. if (propid != PID_ILLEGAL)
  484. {
  485. ASYNC_PRINTF(" %04x", propid);
  486. ccol += 5;
  487. if (propid & (0xf << 28))
  488. {
  489. ccol += 4;
  490. }
  491. else if (propid & (0xf << 24))
  492. {
  493. ccol += 3;
  494. }
  495. else if (propid & (0xf << 20))
  496. {
  497. ccol += 2;
  498. }
  499. else if (propid & (0xf << 16))
  500. {
  501. ccol++;
  502. }
  503. }
  504. if (postrName != NULL)
  505. {
  506. ASYNC_OPRINTF(OLESTR(" '%s'"), postrName);
  507. ccol += ocslen(postrName) + 3;
  508. }
  509. else if (fVariantVector)
  510. {
  511. ULONG i = (ULONG) ((ULONG_PTR)pv - (ULONG_PTR)av);
  512. ASYNC_PRINTF("[%x]", i);
  513. do
  514. {
  515. ccol++;
  516. i >>= 4;
  517. } while (i != 0);
  518. ccol += 2;
  519. }
  520. else
  521. {
  522. psz = NULL;
  523. switch (propid)
  524. {
  525. case PID_LOCALE: psz = "Locale"; break;
  526. case PID_SECURITY: psz = "SecurityId"; break;
  527. case PID_MODIFY_TIME: psz = "ModifyTime"; break;
  528. case PID_CODEPAGE: psz = "CodePage"; break;
  529. case PID_DICTIONARY: psz = "Dictionary"; break;
  530. }
  531. if (psz == NULL)
  532. switch (pubps)
  533. {
  534. case PUBPS_SUMMARYINFO:
  535. switch (propid)
  536. {
  537. case PID_TITLE: psz = "Title"; break;
  538. case PID_SUBJECT: psz = "Subject"; break;
  539. case PID_AUTHOR: psz = "Author"; break;
  540. case PID_KEYWORDS: psz = "Keywords"; break;
  541. case PID_COMMENTS: psz = "Comments"; break;
  542. case PID_TEMPLATE: psz = "Template"; break;
  543. case PID_LASTAUTHOR: psz = "LastAuthor"; break;
  544. case PID_REVNUMBER: psz = "RevNumber"; break;
  545. case PID_EDITTIME: psz = "EditTime"; break;
  546. case PID_LASTPRINTED: psz = "LastPrinted"; break;
  547. case PID_CREATE_DTM: psz = "CreateDateTime"; break;
  548. case PID_LASTSAVE_DTM: psz = "LastSaveDateTime";break;
  549. case PID_PAGECOUNT: psz = "PageCount"; break;
  550. case PID_WORDCOUNT: psz = "WordCount"; break;
  551. case PID_CHARCOUNT: psz = "CharCount"; break;
  552. case PID_THUMBNAIL: psz = "ThumbNail"; break;
  553. case PID_APPNAME: psz = "AppName"; break;
  554. case PID_DOC_SECURITY: psz = "Security"; break;
  555. }
  556. break;
  557. case PUBPS_DOCSUMMARYINFO:
  558. switch (propid)
  559. {
  560. case PID_CATEGORY: psz = "Category"; break;
  561. case PID_PRESFORMAT: psz = "PresFormat"; break;
  562. case PID_BYTECOUNT: psz = "ByteCount"; break;
  563. case PID_LINECOUNT: psz = "LineCount"; break;
  564. case PID_PARACOUNT: psz = "ParaCount"; break;
  565. case PID_SLIDECOUNT: psz = "SlideCount"; break;
  566. case PID_NOTECOUNT: psz = "NoteCount"; break;
  567. case PID_HIDDENCOUNT: psz = "HiddenCount"; break;
  568. case PID_MMCLIPCOUNT: psz = "MmClipCount"; break;
  569. case PID_SCALE: psz = "Scale"; break;
  570. case PID_HEADINGPAIR: psz = "HeadingPair"; break;
  571. case PID_DOCPARTS: psz = "DocParts"; break;
  572. case PID_MANAGER: psz = "Manager"; break;
  573. case PID_COMPANY: psz = "Company"; break;
  574. case PID_LINKSDIRTY: psz = "LinksDirty"; break;
  575. case PID_CCHWITHSPACES: psz = "CchWithSpaces"; break;
  576. case PID_GUID: psz = "Guid"; break;
  577. case PID_SHAREDDOC: psz = "SharedDoc"; break;
  578. case PID_LINKBASE: psz = "LinkBase"; break;
  579. case PID_HLINKS: psz = "HLinks"; break;
  580. case PID_HYPERLINKSCHANGED: psz = "HyperLinksChanged";break;
  581. }
  582. break;
  583. }
  584. if (psz != NULL)
  585. {
  586. ASYNC_PRINTF(" %s", psz);
  587. ccol += strlen(psz) + 1;
  588. }
  589. }
  590. #define CCOLPROPID 20
  591. if (ccol != CCOLPROPID)
  592. {
  593. if (ccol > CCOLPROPID)
  594. {
  595. ccol = -1;
  596. }
  597. ASYNC_PRINTF("%s%*s", ccol == -1? "\n" : "", CCOLPROPID - ccol, "");
  598. }
  599. ASYNC_PRINTF(" %08x %04x %04x ", propid, cbprop, pv->vt);
  600. psz = "";
  601. switch (pv->vt)
  602. {
  603. default:
  604. psz = achvt;
  605. sprintf(psz, "Unknown (vt = %hx)", pv->vt);
  606. break;
  607. case VT_EMPTY:
  608. ASYNC_PRINTF("EMPTY");
  609. break;
  610. case VT_NULL:
  611. ASYNC_PRINTF("NULL");
  612. break;
  613. case VT_UI1:
  614. ASYNC_PRINTF("UI1 = %02lx", pv->bVal);
  615. psz = "";
  616. break;
  617. case VT_I2:
  618. psz = "I2";
  619. goto doshort;
  620. case VT_UI2:
  621. psz = "UI2";
  622. goto doshort;
  623. case VT_BOOL:
  624. psz = "BOOL";
  625. doshort:
  626. ASYNC_PRINTF("%s = %04hx", psz, pv->iVal);
  627. psz = g_szEmpty;
  628. break;
  629. case VT_I4:
  630. psz = "I4";
  631. goto dolong;
  632. case VT_UI4:
  633. psz = "UI4";
  634. goto dolong;
  635. case VT_R4:
  636. psz = "R4";
  637. goto dolong;
  638. case VT_ERROR:
  639. psz = "ERROR";
  640. dolong:
  641. ASYNC_PRINTF("%s = %08lx", psz, pv->lVal);
  642. psz = g_szEmpty;
  643. break;
  644. case VT_I8:
  645. psz = "I8";
  646. goto dolonglong;
  647. case VT_UI8:
  648. psz = "UI8";
  649. goto dolonglong;
  650. case VT_R8:
  651. psz = "R8";
  652. goto dolonglong;
  653. case VT_CY:
  654. psz = "R8";
  655. goto dolonglong;
  656. case VT_DATE:
  657. psz = "R8";
  658. dolonglong:
  659. ASYNC_PRINTF(
  660. "%s = %08lx:%08lx",
  661. psz,
  662. pv->hVal.HighPart,
  663. pv->hVal.LowPart);
  664. psz = g_szEmpty;
  665. break;
  666. case VT_FILETIME:
  667. DumpTime(OLESTR("FILETIME =\n\t "), &pv->filetime);
  668. fNewLine = FALSE; // skip newline printf
  669. break;
  670. case VT_CLSID:
  671. ASYNC_PRINTF("CLSID =\n\t ");
  672. PrintGuid(pv->puuid);
  673. break;
  674. case VT_BLOB:
  675. psz = "BLOB";
  676. goto doblob;
  677. case VT_BLOB_OBJECT:
  678. psz = "BLOB_OBJECT";
  679. doblob:
  680. ASYNC_PRINTF("%s (cbSize %x)", psz, pv->blob.cbSize);
  681. if (pv->blob.cbSize != 0)
  682. {
  683. ASYNC_PRINTF(" =\n");
  684. DumpHex(pv->blob.pBlobData, pv->blob.cbSize, 0);
  685. }
  686. psz = g_szEmpty;
  687. break;
  688. case VT_CF:
  689. ASYNC_PRINTF(
  690. "CF (cbSize %x, ulClipFmt %x)\n",
  691. pv->pclipdata->cbSize,
  692. pv->pclipdata->ulClipFmt);
  693. DumpHex(pv->pclipdata->pClipData,
  694. pv->pclipdata->cbSize - sizeof(pv->pclipdata->ulClipFmt),
  695. 0);
  696. break;
  697. case VT_STREAM:
  698. psz = "STREAM";
  699. goto dostring;
  700. case VT_STREAMED_OBJECT:
  701. psz = "STREAMED_OBJECT";
  702. goto dostring;
  703. case VT_STORAGE:
  704. psz = "STORAGE";
  705. goto dostring;
  706. case VT_STORED_OBJECT:
  707. psz = "STORED_OBJECT";
  708. goto dostring;
  709. case VT_BSTR:
  710. ASYNC_PRINTF(
  711. "BSTR (cb = %04lx)%s\n",
  712. pv->bstrVal == NULL? 0 : BSTRLEN(pv->bstrVal),
  713. pv->bstrVal == NULL? " NULL" : g_szEmpty);
  714. if (pv->bstrVal != NULL)
  715. {
  716. DumpHex(
  717. (BYTE *) pv->bstrVal,
  718. BSTRLEN(pv->bstrVal) + sizeof(WCHAR),
  719. 0);
  720. }
  721. break;
  722. case VT_LPSTR:
  723. psz = "LPSTR";
  724. ASYNC_PRINTF(
  725. "%s = %s%s%s",
  726. psz,
  727. pv->pszVal == NULL? g_szEmpty : "'",
  728. pv->pszVal == NULL? "NULL" : pv->pszVal,
  729. pv->pszVal == NULL? g_szEmpty : "'");
  730. psz = g_szEmpty;
  731. break;
  732. case VT_LPWSTR:
  733. psz = "LPWSTR";
  734. dostring:
  735. ASYNC_PRINTF(
  736. "%s = %s%ws%s",
  737. psz,
  738. pv->pwszVal == NULL? g_szEmpty : "'",
  739. pv->pwszVal == NULL? L"NULL" : pv->pwszVal,
  740. pv->pwszVal == NULL? g_szEmpty : "'");
  741. psz = g_szEmpty;
  742. break;
  743. // vectors
  744. case VT_VECTOR | VT_UI1:
  745. ASYNC_PRINTF("UI1[%x] =", pv->caub.cElems);
  746. for (j = 0; j < pv->caub.cElems; j++)
  747. {
  748. if ((j % 16) == 0)
  749. {
  750. ASYNC_PRINTF("\n %02hx:", j);
  751. }
  752. ASYNC_PRINTF(" %02hx", pv->caub.pElems[j]);
  753. }
  754. break;
  755. case VT_VECTOR | VT_I2:
  756. psz = "I2";
  757. goto doshortvector;
  758. case VT_VECTOR | VT_UI2:
  759. psz = "UI2";
  760. goto doshortvector;
  761. case VT_VECTOR | VT_BOOL:
  762. psz = "BOOL";
  763. doshortvector:
  764. ASYNC_PRINTF("%s[%x] =", psz, pv->cai.cElems);
  765. for (j = 0; j < pv->cai.cElems; j++)
  766. {
  767. if ((j % 8) == 0)
  768. {
  769. ASYNC_PRINTF("\n %04hx:", j);
  770. }
  771. ASYNC_PRINTF(" %04hx", pv->cai.pElems[j]);
  772. }
  773. psz = g_szEmpty;
  774. break;
  775. case VT_VECTOR | VT_I4:
  776. psz = "I4";
  777. goto dolongvector;
  778. case VT_VECTOR | VT_UI4:
  779. psz = "UI4";
  780. goto dolongvector;
  781. case VT_VECTOR | VT_R4:
  782. psz = "R4";
  783. goto dolongvector;
  784. case VT_VECTOR | VT_ERROR:
  785. psz = "ERROR";
  786. dolongvector:
  787. ASYNC_PRINTF("%s[%x] =", psz, pv->cal.cElems);
  788. for (j = 0; j < pv->cal.cElems; j++)
  789. {
  790. if ((j % 4) == 0)
  791. {
  792. ASYNC_PRINTF("\n %04x:", j);
  793. }
  794. ASYNC_PRINTF(" %08lx", pv->cal.pElems[j]);
  795. }
  796. psz = g_szEmpty;
  797. break;
  798. case VT_VECTOR | VT_I8:
  799. psz = "I8";
  800. goto dolonglongvector;
  801. case VT_VECTOR | VT_UI8:
  802. psz = "UI8";
  803. goto dolonglongvector;
  804. case VT_VECTOR | VT_R8:
  805. psz = "R8";
  806. goto dolonglongvector;
  807. case VT_VECTOR | VT_CY:
  808. psz = "CY";
  809. goto dolonglongvector;
  810. case VT_VECTOR | VT_DATE:
  811. psz = "DATE";
  812. dolonglongvector:
  813. ASYNC_PRINTF("%s[%x] =", psz, pv->cah.cElems);
  814. for (j = 0; j < pv->cah.cElems; j++)
  815. {
  816. if ((j % 2) == 0)
  817. {
  818. ASYNC_PRINTF("\n %04x:", j);
  819. }
  820. ASYNC_PRINTF(
  821. " %08lx:%08lx",
  822. pv->cah.pElems[j].HighPart,
  823. pv->cah.pElems[j].LowPart);
  824. }
  825. psz = g_szEmpty;
  826. break;
  827. case VT_VECTOR | VT_FILETIME:
  828. ASYNC_PRINTF("FILETIME[%x] =\n", pv->cafiletime.cElems);
  829. for (j = 0; j < pv->cafiletime.cElems; j++)
  830. {
  831. ASYNC_PRINTF(" %04x: ", j);
  832. DumpTime(OLESTR(""), &pv->cafiletime.pElems[j]);
  833. }
  834. fNewLine = FALSE; // skip newline printf
  835. break;
  836. case VT_VECTOR | VT_CLSID:
  837. ASYNC_PRINTF("CLSID[%x] =", pv->cauuid.cElems);
  838. for (j = 0; j < pv->cauuid.cElems; j++)
  839. {
  840. ASYNC_PRINTF("\n %04x: ", j);
  841. PrintGuid(&pv->cauuid.pElems[j]);
  842. }
  843. break;
  844. case VT_VECTOR | VT_CF:
  845. ASYNC_PRINTF("CF[%x] =", pv->caclipdata.cElems);
  846. for (j = 0; j < pv->caclipdata.cElems; j++)
  847. {
  848. ASYNC_PRINTF("\n %04x: (cbSize %x, ulClipFmt %x) =\n",
  849. j,
  850. pv->caclipdata.pElems[j].cbSize,
  851. pv->caclipdata.pElems[j].ulClipFmt);
  852. DumpHex(
  853. pv->caclipdata.pElems[j].pClipData,
  854. pv->caclipdata.pElems[j].cbSize - sizeof(pv->caclipdata.pElems[j].ulClipFmt),
  855. 0);
  856. }
  857. break;
  858. case VT_VECTOR | VT_BSTR:
  859. ASYNC_PRINTF("BSTR[%x] =", pv->cabstr.cElems);
  860. for (j = 0; j < pv->cabstr.cElems; j++)
  861. {
  862. BSTR bstr = pv->cabstr.pElems[j];
  863. ASYNC_PRINTF(
  864. "\n %04x: cb = %04lx%s\n",
  865. j,
  866. bstr == NULL? 0 : BSTRLEN(pv->cabstr.pElems[j]),
  867. bstr == NULL? " NULL" : g_szEmpty);
  868. if (bstr != NULL)
  869. {
  870. DumpHex((BYTE *) bstr, BSTRLEN(bstr) + sizeof(WCHAR), 0);
  871. }
  872. }
  873. break;
  874. case VT_VECTOR | VT_LPSTR:
  875. ASYNC_PRINTF("LPSTR[%x] =", pv->calpstr.cElems);
  876. for (j = 0; j < pv->calpstr.cElems; j++)
  877. {
  878. CHAR *psz = pv->calpstr.pElems[j];
  879. ASYNC_PRINTF(
  880. "\n %04x: %s%s%s",
  881. j,
  882. psz == NULL? g_szEmpty : "'",
  883. psz == NULL? "NULL" : psz,
  884. psz == NULL? g_szEmpty : "'");
  885. }
  886. break;
  887. case VT_VECTOR | VT_LPWSTR:
  888. ASYNC_PRINTF("LPWSTR[%x] =", pv->calpwstr.cElems);
  889. for (j = 0; j < pv->calpwstr.cElems; j++)
  890. {
  891. WCHAR *pwsz = pv->calpwstr.pElems[j];
  892. ASYNC_PRINTF(
  893. "\n %04x: %s%ws%s",
  894. j,
  895. pwsz == NULL? g_szEmpty : "'",
  896. pwsz == NULL? L"NULL" : pwsz,
  897. pwsz == NULL? g_szEmpty : "'");
  898. }
  899. break;
  900. case VT_VECTOR | VT_VARIANT:
  901. ASYNC_PRINTF("VARIANT[%x] =\n", pv->capropvar.cElems);
  902. DisplayProps(
  903. pguid,
  904. pv->capropvar.cElems,
  905. &propid,
  906. NULL,
  907. pv->capropvar.pElems,
  908. fsumcat,
  909. pcbprop);
  910. fNewLine = FALSE; // skip newline printf
  911. break;
  912. }
  913. if (*psz != '\0')
  914. {
  915. ASYNC_PRINTF("%s", psz);
  916. if (pv->vt & VT_VECTOR)
  917. {
  918. ASYNC_PRINTF("[%x]", pv->cal.cElems);
  919. }
  920. ASYNC_PRINTF("%s", szNoFormat);
  921. }
  922. if (!fVariantVector && apid != NULL && apid[pv - av] != propid)
  923. {
  924. ASYNC_PRINTF(" (bad PROPID: %04x)", apid[pv - av]);
  925. fNewLine = TRUE;
  926. }
  927. if (asps != NULL && pv->vt != psps->vt)
  928. {
  929. ASYNC_PRINTF(" (bad STATPROPSTG VARTYPE: %04x)", psps->vt);
  930. fNewLine = TRUE;
  931. }
  932. if (fNewLine)
  933. {
  934. ASYNC_PRINTF("\n");
  935. }
  936. }
  937. }
  938. STATPROPSTG aspsStatic[] = {
  939. { NULL, PID_CODEPAGE, VT_I2 },
  940. { NULL, PID_MODIFY_TIME, VT_FILETIME },
  941. { NULL, PID_SECURITY, VT_UI4 },
  942. };
  943. #define CPROPSTATIC (sizeof(aspsStatic)/sizeof(aspsStatic[0]))
  944. #define CB_STREAM_OVERHEAD 28
  945. #define CB_PROPSET_OVERHEAD (CB_STREAM_OVERHEAD + 8)
  946. #define CB_PROP_OVERHEAD 8
  947. HRESULT
  948. DumpOlePropertySet(
  949. IPropertySetStorage *ppsstg,
  950. STATPROPSETSTG *pspss,
  951. ULONG *pcprop,
  952. ULONG *pcbprop)
  953. {
  954. HRESULT hr;
  955. IEnumSTATPROPSTG *penumsps = NULL;
  956. IPropertyStorage *pps;
  957. ULONG cprop, cbpropset;
  958. PROPID propid;
  959. OLECHAR *poszName;
  960. ULONG ispsStatic;
  961. *pcprop = *pcbprop = 0;
  962. hr = ppsstg->Open(
  963. pspss->fmtid,
  964. STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  965. &pps);
  966. if( FAILED(hr) )
  967. return(hr);
  968. propid = PID_DICTIONARY;
  969. hr = pps->ReadPropertyNames(1, &propid, &poszName);
  970. if( (HRESULT) S_FALSE == hr )
  971. hr = S_OK;
  972. Check( S_OK, hr );
  973. ListPropSetHeader(pspss, poszName);
  974. if (poszName != NULL)
  975. {
  976. CoTaskMemFree(poszName);
  977. }
  978. cprop = cbpropset = 0;
  979. Check(S_OK, pps->Enum(&penumsps) );
  980. ispsStatic = 0;
  981. hr = S_OK;
  982. while (hr == S_OK)
  983. {
  984. STATPROPSTG sps = {NULL, 0, 0};
  985. PROPSPEC propspec;
  986. PROPVARIANT propvar;
  987. ULONG count = 0;
  988. hr = (HRESULT) S_FALSE;
  989. if (ispsStatic == 0)
  990. {
  991. hr = penumsps->Next(1, &sps, &count);
  992. }
  993. if (hr != S_OK)
  994. {
  995. if (hr == (HRESULT) S_FALSE)
  996. {
  997. hr = S_OK;
  998. if (ispsStatic >= CPROPSTATIC)
  999. {
  1000. break;
  1001. }
  1002. sps = aspsStatic[ispsStatic];
  1003. ispsStatic++;
  1004. count = 1;
  1005. }
  1006. Check( S_OK, hr );
  1007. }
  1008. PropVariantInit(&propvar);
  1009. if (sps.lpwstrName != NULL)
  1010. {
  1011. propspec.ulKind = PRSPEC_LPWSTR;
  1012. propspec.lpwstr = sps.lpwstrName;
  1013. }
  1014. else
  1015. {
  1016. propspec.ulKind = PRSPEC_PROPID;
  1017. propspec.propid = sps.propid;
  1018. }
  1019. hr = pps->ReadMultiple(1, &propspec, &propvar);
  1020. if (hr == (HRESULT) S_FALSE)
  1021. {
  1022. if (g_fVerbose)
  1023. {
  1024. ASYNC_PRINTF(
  1025. "%s(%u, %x) vt=%x returned hr=%x\n",
  1026. "IPropertyStorage::ReadMultiple",
  1027. ispsStatic,
  1028. propspec.propid,
  1029. propvar.vt,
  1030. hr);
  1031. }
  1032. ASSERT(propvar.vt == VT_EMPTY);
  1033. hr = S_OK;
  1034. }
  1035. Check( S_OK, hr );
  1036. if (ispsStatic == 0 || propvar.vt != VT_EMPTY)
  1037. {
  1038. ASSERT(count == 1);
  1039. cprop += count;
  1040. if (cprop == 1)
  1041. {
  1042. ASYNC_PRINTF(g_szPropHeader);
  1043. }
  1044. DisplayProps(
  1045. &pspss->fmtid,
  1046. 1,
  1047. NULL,
  1048. &sps,
  1049. &propvar,
  1050. FALSE,
  1051. &cbpropset);
  1052. g_pfnPropVariantClear(&propvar);
  1053. }
  1054. if (sps.lpwstrName != NULL)
  1055. {
  1056. CoTaskMemFree(sps.lpwstrName);
  1057. }
  1058. }
  1059. if (penumsps != NULL)
  1060. {
  1061. penumsps->Release();
  1062. }
  1063. pps->Release();
  1064. if (cprop != 0)
  1065. {
  1066. cbpropset += CB_PROPSET_OVERHEAD + cprop * CB_PROP_OVERHEAD;
  1067. ASYNC_PRINTF(" %04x bytes in %u properties\n\n", cbpropset, cprop);
  1068. }
  1069. *pcprop = cprop;
  1070. *pcbprop = cbpropset;
  1071. return(hr);
  1072. }
  1073. HRESULT
  1074. DumpOlePropertySets(
  1075. IStorage *pstg,
  1076. IPropertySetStorage *pIPropSetStorage,
  1077. OLECHAR *aocpath)
  1078. {
  1079. HRESULT hr = S_OK;
  1080. IPropertySetStorage *ppsstg = pIPropSetStorage;
  1081. ULONG cbproptotal = 0;
  1082. ULONG cproptotal = 0;
  1083. ULONG cpropset = 0;
  1084. IID IIDpsstg = IID_IPropertySetStorage;
  1085. if (ppsstg == NULL)
  1086. {
  1087. Check(S_OK, StgToPropSetStg( pstg, &ppsstg ));
  1088. }
  1089. {
  1090. IEnumSTATPROPSETSTG *penumspss = NULL;
  1091. Check(S_OK, ppsstg->Enum(&penumspss) );
  1092. while (hr == S_OK)
  1093. {
  1094. STATPROPSETSTG spss;
  1095. ULONG count;
  1096. BOOLEAN fDocumentSummarySection2;
  1097. hr = penumspss->Next(1, &spss, &count);
  1098. if (hr != S_OK)
  1099. {
  1100. if (hr == (HRESULT) S_FALSE)
  1101. {
  1102. hr = (HRESULT) S_OK;
  1103. }
  1104. Check( (HRESULT) S_OK, hr );
  1105. break;
  1106. }
  1107. ASSERT(count == 1);
  1108. fDocumentSummarySection2 = FALSE;
  1109. while (TRUE)
  1110. {
  1111. ULONG cprop, cbprop;
  1112. HRESULT hr;
  1113. hr = DumpOlePropertySet(
  1114. ppsstg,
  1115. &spss,
  1116. &cprop,
  1117. &cbprop);
  1118. if( (HRESULT) STG_E_FILENOTFOUND == hr
  1119. &&
  1120. fDocumentSummarySection2 )
  1121. {
  1122. hr = S_OK;
  1123. }
  1124. cpropset++;
  1125. cproptotal += cprop;
  1126. cbproptotal += cbprop;
  1127. if (memcmp(&spss.fmtid, &FMTID_DocSummaryInformation, sizeof(FMTID)))
  1128. {
  1129. break;
  1130. }
  1131. spss.fmtid = FMTID_UserDefinedProperties;
  1132. fDocumentSummarySection2 = TRUE;
  1133. }
  1134. }
  1135. if (penumspss != NULL)
  1136. {
  1137. penumspss->Release();
  1138. }
  1139. ppsstg->Release();
  1140. }
  1141. if ((cbproptotal | cproptotal | cpropset) != 0)
  1142. {
  1143. ASYNC_PRINTF(
  1144. " %04x bytes in %u properties in %u property sets\n",
  1145. cbproptotal,
  1146. cproptotal,
  1147. cpropset);
  1148. }
  1149. return(hr);
  1150. }
  1151. NTSTATUS
  1152. DumpOleStream(
  1153. LPSTREAM pstm,
  1154. ULONG cb)
  1155. {
  1156. ULONG cbTotal = 0;
  1157. while (TRUE)
  1158. {
  1159. ULONG cbOut;
  1160. BYTE ab[4096];
  1161. Check(S_OK, pstm->Read(ab, min(cb, sizeof(ab)), &cbOut) );
  1162. if (cbOut == 0)
  1163. {
  1164. break;
  1165. }
  1166. if (g_fVerbose)
  1167. {
  1168. DumpHex(ab, cbOut, cbTotal);
  1169. }
  1170. cb -= cbOut;
  1171. cbTotal += cbOut;
  1172. }
  1173. return(STATUS_SUCCESS);
  1174. }
  1175. VOID
  1176. DumpOleStorage(
  1177. IStorage *pstg,
  1178. IPropertySetStorage *pIPropertySetStorage,
  1179. LPOLESTR aocpath )
  1180. {
  1181. LPENUMSTATSTG penum;
  1182. STATSTG ss;
  1183. IStorage* pstgChild;
  1184. LPSTREAM pstmChild;
  1185. char *szType;
  1186. OLECHAR *pocChild;
  1187. HRESULT hr;
  1188. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  1189. Check( S_OK, DumpOlePropertySets(pstg, pIPropertySetStorage, aocpath) );
  1190. if (NULL == pstg)
  1191. {
  1192. return;
  1193. }
  1194. Check( S_OK, pstg->EnumElements(0, NULL, 0, &penum) );
  1195. pocChild = &aocpath[ocslen(aocpath)];
  1196. // Continue enumeration until IEnumStatStg::Next returns non-S_OK
  1197. while (TRUE)
  1198. {
  1199. ULONG ulCount;
  1200. // Enumerate one element at a time
  1201. hr = penum->Next(1, &ss, &ulCount);
  1202. if( (HRESULT) S_FALSE == hr )
  1203. break;
  1204. else
  1205. Check( S_OK, hr );
  1206. // Select the human-readable type of object to display
  1207. switch (ss.type)
  1208. {
  1209. case STGTY_STREAM: szType = "Stream"; break;
  1210. case STGTY_STORAGE: szType = "Storage"; break;
  1211. case STGTY_LOCKBYTES: szType = "LockBytes"; break;
  1212. case STGTY_PROPERTY: szType = "Property"; break;
  1213. default: szType = "<Unknown>"; break;
  1214. }
  1215. if (g_fVerbose)
  1216. {
  1217. ASYNC_OPRINTF(
  1218. OLESTR("Type=%hs Size=%lx Mode=%lx LocksSupported=%lx StateBits=%lx '%s' + '%s'\n"),
  1219. szType,
  1220. ss.cbSize.LowPart,
  1221. ss.grfMode,
  1222. ss.grfLocksSupported,
  1223. ss.grfStateBits,
  1224. aocpath,
  1225. ss.pwcsName);
  1226. ASYNC_PRINTF("ss.clsid = ");
  1227. PrintGuid(&ss.clsid);
  1228. ASYNC_PRINTF("\n");
  1229. }
  1230. // If a stream, output the data in hex format.
  1231. if (ss.type == STGTY_STREAM)
  1232. {
  1233. ASYNC_OPRINTF(
  1234. OLESTR("Stream %s:%s, Size=%lx\n"),
  1235. aocpath,
  1236. ss.pwcsName,
  1237. ss.cbSize.LowPart);
  1238. Check(S_OK, pstg->OpenStream(
  1239. ss.pwcsName,
  1240. NULL,
  1241. STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  1242. 0,
  1243. &pstmChild) );
  1244. Check(S_OK, DumpOleStream(pstmChild, ss.cbSize.LowPart) );
  1245. pstmChild->Release();
  1246. }
  1247. // If a storage, recurse
  1248. if (ss.type == STGTY_STORAGE)
  1249. {
  1250. ASYNC_OPRINTF(
  1251. OLESTR("Storage %s\\%s, Size=%lx\n"),
  1252. aocpath,
  1253. ss.pwcsName,
  1254. ss.cbSize.LowPart);
  1255. Check( S_OK, pstg->OpenStorage(
  1256. ss.pwcsName,
  1257. NULL,
  1258. STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  1259. NULL,
  1260. 0,
  1261. &pstgChild) );
  1262. *pocChild = L'\\';
  1263. ocscpy(pocChild + 1, ss.pwcsName);
  1264. DumpOleStorage(pstgChild, NULL, aocpath);
  1265. pstgChild->Release();
  1266. *pocChild = L'\0';
  1267. }
  1268. CoTaskMemFree(ss.pwcsName);
  1269. PRINTF( "\n" );
  1270. }
  1271. penum->Release();
  1272. return;
  1273. }