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.

674 lines
18 KiB

  1. /////////////////////////////////////////////////////////////////////////////////
  2. /////////////////////////////////////////////////////////////////////////////////
  3. //
  4. // File: PropVar.c
  5. //
  6. // Purpose: This file provides Office-aware routines which
  7. // operate on PropVariants. They are Office-aware in
  8. // that they only operate on the subset of
  9. // VarTypes which are used by Office.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////////
  12. /////////////////////////////////////////////////////////////////////////////////
  13. #include "priv.h"
  14. #pragma hdrstop
  15. /////////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Function: FPropVarLoad
  18. //
  19. // Purpse: Load data into a PropVariant. If the target PropVariant
  20. // already contains data, it will be freed.
  21. //
  22. // Note that new memory is allocated, if necessary, to hold
  23. // the data in the PropVariant. Also note that the
  24. // resulting PropVariant should be freed by the caller using
  25. // PropVariantClear.
  26. //
  27. // Inputs: LPPROPVARIANT - to be loaded. This should be a valid
  28. // (i.e. intialized) PropVariant.
  29. // VARTYPE - of the new PropVariant (must be a member of
  30. // the limited set used by Office).
  31. // LPVOID - Either the data to be loaded, or a pointer
  32. // to such data, depending on the type.
  33. //
  34. // Output: TRUE if and only if successful.
  35. //
  36. /////////////////////////////////////////////////////////////////////////////////
  37. BOOL
  38. FPropVarLoad
  39. ( LPPROPVARIANT lppropvar,
  40. VARTYPE vt,
  41. LPVOID const lpv )
  42. {
  43. // ------
  44. // Locals
  45. // ------
  46. BOOL fSuccess = FALSE; // Return code
  47. ULONG cch, cb;
  48. // ----------
  49. // Initialize
  50. // ----------
  51. Assert (lppropvar != NULL);
  52. Assert (lpv != NULL);
  53. // Free any data currently in the PropVariant.
  54. PropVariantClear (lppropvar);
  55. // ---------------------------------------------------
  56. // Set the value of the PropVariant based on the type.
  57. // ---------------------------------------------------
  58. switch (vt)
  59. {
  60. // Strings
  61. case VT_LPTSTR:
  62. // Determine the character and byte count.
  63. cch = CchTszLen(lpv); // Doesn't include the NULL.
  64. cb = CBTSTR(lpv); // *Does* include the NULL.
  65. // Allocate memory in the PropVariant.
  66. lppropvar->pszVal = CoTaskMemAlloc (cb);
  67. if (lppropvar->pszVal == NULL)
  68. {
  69. MESSAGE(TEXT("Couldn't allocate new VT_LPTSTR"));
  70. goto Exit;
  71. }
  72. // Copy the string to the PropVariant and terminate it.
  73. PbSzNCopy (lppropvar->pszVal, lpv, cch);
  74. ((LPTSTR)lppropvar->pszVal)[cch] = TEXT('\0');
  75. break;
  76. // DWORDs
  77. case VT_I4:
  78. lppropvar->lVal = *(DWORD*) lpv;
  79. break;
  80. // FileTime
  81. case VT_FILETIME:
  82. PbMemCopy (&lppropvar->filetime, lpv, sizeof(FILETIME));
  83. break;
  84. // Double
  85. case VT_R8:
  86. PbMemCopy (&lppropvar->dblVal, lpv, sizeof(double));
  87. break;
  88. // Bool
  89. case VT_BOOL:
  90. lppropvar->boolVal = *(VARIANT_BOOL*) lpv ? VARIANT_TRUE : VARIANT_FALSE;
  91. break;
  92. // Invalid type.
  93. default:
  94. MESSAGE(TEXT("Invalid VarType"));
  95. goto Exit;
  96. }
  97. // Set the VT of the PropVariant, and we're done.
  98. lppropvar->vt = vt;
  99. // ----
  100. // Exit
  101. // ----
  102. fSuccess = TRUE;
  103. Exit:
  104. return (fSuccess);
  105. } // FPropVarLoad
  106. ////////////////////////////////////////////////////////////////////////////////
  107. //
  108. // Function: FCoStrToWStr
  109. //
  110. // Purpose: Convert a COM string (ANSI) to a COM wide-string.
  111. // ("COM" because the string is allocated using
  112. // the COM heap).
  113. //
  114. // Inputs: LPWSTR* - The converted string.
  115. // LPSTR - The original string.
  116. // UINT - The ANSI code page.
  117. //
  118. // Output: TRUE if and only if successful.
  119. //
  120. ////////////////////////////////////////////////////////////////////////////////
  121. BOOL
  122. FCoStrToWStr( LPWSTR *lplpwstr,
  123. const LPSTR lpstr,
  124. UINT uCodePage)
  125. {
  126. // ------
  127. // Locals
  128. // ------
  129. BOOL fSuccess = FALSE; // Return value.
  130. ULONG cchBuffer = 0; // Size of converted string (includes NULL).
  131. Assert (lpstr != NULL && lplpwstr != NULL);
  132. // ------------------
  133. // Convert the string
  134. // ------------------
  135. // Make two passes. The first will calculate the
  136. // size of the target buffer, the second will actually
  137. // make the conversion.
  138. *lplpwstr = NULL;
  139. while (TRUE)
  140. {
  141. cchBuffer = MultiByteToWideChar(
  142. uCodePage, // Source code page
  143. 0, // Default flags
  144. lpstr, // Source string
  145. -1, // Default length
  146. *lplpwstr, // Destination string
  147. cchBuffer ); // Max dest string characters.
  148. // Is this the second pass (when the conversion should
  149. // have taken place)?
  150. if (*lplpwstr != NULL)
  151. {
  152. // If we got a good result, then we're done.
  153. if (cchBuffer != 0)
  154. {
  155. break;
  156. }
  157. // 0 was returned. There was an error.
  158. else
  159. {
  160. AssertSz (0, TEXT("Couldn't convert MBCS to Wide"));
  161. goto Exit;
  162. }
  163. }
  164. // Otherwise, this is the first pass. We need to
  165. // allocate a buffer.
  166. else
  167. {
  168. // We should have gotten a positive buffer size.
  169. if (cchBuffer == 0)
  170. {
  171. AssertSz(0, TEXT("MultiByteToWideChar returned invalid target buffer size"));
  172. goto Exit;
  173. }
  174. // Allocate memory for the converted string.
  175. else
  176. {
  177. *lplpwstr = (LPWSTR) CoTaskMemAlloc( cchBuffer * 2 );
  178. if ( *lplpwstr == NULL)
  179. {
  180. AssertSz (0, TEXT("Could not allocate memory for wide string"));
  181. goto Exit;
  182. }
  183. }
  184. } // if( *lplpwstr != NULL ... else
  185. } // while (TRUE)
  186. // ----
  187. // Exit
  188. // ----
  189. fSuccess = TRUE;
  190. Exit:
  191. // If there was a problem, free the Unicode string.
  192. if (!fSuccess)
  193. {
  194. CoTaskMemFree (*lplpwstr);
  195. *lplpwstr = NULL;
  196. }
  197. return (fSuccess);
  198. } // FCoStrToWStr
  199. ////////////////////////////////////////////////////////////////////////////////
  200. //
  201. // Function: FCoWStrToStr
  202. //
  203. // Purpose: Convert a COM wide-string to an ANSI string.
  204. // ("COM" because the string is allocated using
  205. // the COM heap).
  206. //
  207. // Inputs: LPSTR* - The converted string.
  208. // LPWSTR - The source string.
  209. // UINT - The ANSI code page.
  210. //
  211. // Output: TRUE if and only if successful.
  212. //
  213. ////////////////////////////////////////////////////////////////////////////////
  214. BOOL
  215. FCoWStrToStr( LPSTR *lplpstr,
  216. const LPWSTR lpwstr,
  217. UINT uCodePage)
  218. {
  219. // ------
  220. // Locals
  221. // ------
  222. BOOL fSuccess = FALSE; // Return result
  223. ULONG cch; // Charcters in original string (w/o NULL).
  224. ULONG cbBuffer = 0; // Size of target buffer (including NULL)
  225. Assert (lpwstr != NULL && lplpstr != NULL);
  226. // ------------------
  227. // Convert the String
  228. // ------------------
  229. // We'll make two calls to WideCharToMultiByte.
  230. // In the first, we'll determine the size required
  231. // for the multi-byte string. We'll use this
  232. // to allocate memory. In the second pass, we'll actually
  233. // make the conversion.
  234. cch = CchWszLen( lpwstr ); // How big is the source string?
  235. *lplpstr = NULL; // Initialize the target buffer.
  236. while (TRUE)
  237. {
  238. cbBuffer = WideCharToMultiByte(
  239. uCodePage, // Source code page
  240. 0, // Default flags
  241. lpwstr, // Source string
  242. cch + 1, // # chars in wide string (including NULL)
  243. *lplpstr, // Destination string
  244. cbBuffer, // Size of destination buffer
  245. NULL, NULL ); // No default character
  246. // Is this the second pass (when the conversion should
  247. // have taken place)?
  248. if (*lplpstr != NULL)
  249. {
  250. // If we got a good result, then we're done.
  251. if (cbBuffer != 0)
  252. {
  253. break;
  254. }
  255. // 0 was returned. There was an error.
  256. else
  257. {
  258. AssertSz (0, TEXT("Couldn't convert Wide to MBCS"));
  259. goto Exit;
  260. }
  261. }
  262. // Otherwise, this is the first pass. We need to
  263. // allocate a buffer.
  264. else
  265. {
  266. // We should have gotten a positive buffer size.
  267. if (cbBuffer == 0)
  268. {
  269. AssertSz(0, TEXT("WideCharMultiByte returned invalid target buffer size"));
  270. goto Exit;
  271. }
  272. // Allocate memory for the converted string.
  273. else
  274. {
  275. *lplpstr = (LPSTR) CoTaskMemAlloc( cbBuffer );
  276. if ( *lplpstr == NULL)
  277. {
  278. AssertSz (0, TEXT("Could not allocate memory for wide string"));
  279. goto Exit;
  280. }
  281. }
  282. } // if( lpstr != NULL ... else
  283. } // while (TRUE)
  284. // ----
  285. // Exit
  286. // ----
  287. fSuccess = TRUE;
  288. Exit:
  289. // If there was a problem, free the new string.
  290. if (!fSuccess)
  291. {
  292. CoTaskMemFree (*lplpstr);
  293. *lplpstr = NULL;
  294. }
  295. return (fSuccess);
  296. } // FCoWStrToStr
  297. //////////////////////////////////////////////////////////////////////////////
  298. //
  299. // Function: FPropVarConvertString
  300. //
  301. // Purpose: Convert a PropVariant from VT_LPSTR to VT_LPWSTR,
  302. // or vice-versa. The correct direction is inferred
  303. // from the input. The source PropVariant is not
  304. // modified.
  305. //
  306. // If the PropVariant is a Vector, all elements are
  307. // converted.
  308. //
  309. // Inputs: LPPROPVARIANT - The buffer in which to put the
  310. // converted PropVariant.
  311. // LPPROPVARIANT - The source of the conversion.
  312. // UINT - The code page of VT_LPSTRs.
  313. //
  314. // Output: TRUE if successful. If unsuccessful, the original
  315. // PropVariant will be returned unmodified.
  316. //
  317. // Pre-Conditions:
  318. // The input must be either a VT_LPSTR or a VT_LPWSTR
  319. // (with or without the VT_VECTOR bit set).
  320. // &&
  321. // The destination PropVariant is VT_EMPTY.
  322. // &&
  323. // The code page must not be CP_WINUNICODE (Unicode
  324. // LPSTRs are not legal in the SumInfo property sets).
  325. //
  326. //////////////////////////////////////////////////////////////////////////////
  327. BOOL FPropVarConvertString( LPPROPVARIANT lppropvarDest,
  328. const LPPROPVARIANT lppropvarSource,
  329. UINT uCodePage)
  330. {
  331. // ------
  332. // Locals
  333. // ------
  334. BOOL fSuccess = FALSE; // Return code.
  335. BOOL fConvertToAnsi; // Indicates the direction of the conversion.
  336. LPSTR *lplpstrDest; // Pointer to pointer to a converted string.
  337. LPSTR lpstrSource; // Pointer to a string to be converted.
  338. ULONG cElems; // The number of strings still requiring conversion
  339. ULONG ulIndex = 0; // Index into vector (if this VT is a vector)
  340. // ----------
  341. // Initialize
  342. // ----------
  343. Assert(lppropvarDest != NULL && lppropvarSource != NULL);
  344. Assert(lppropvarDest->vt == VT_EMPTY);
  345. Assert(uCodePage != CP_WINUNICODE);
  346. // Determine the direction of the conversion.
  347. fConvertToAnsi = (lppropvarSource->vt & ~VT_VECTOR) == VT_LPSTR
  348. ? FALSE
  349. : TRUE;
  350. // -----------------------------------
  351. // Initialize based on the Vector bit.
  352. // -----------------------------------
  353. if (lppropvarSource->vt & VT_VECTOR)
  354. {
  355. // We're a vector.
  356. cElems = lppropvarSource->calpstr.cElems;
  357. // Allocate an array of string pointers, putting it in
  358. // lppropvarDest.
  359. lppropvarDest->calpstr.pElems = CoTaskMemAlloc( cElems
  360. * sizeof(*lppropvarDest->calpstr.pElems) );
  361. if (lppropvarDest->calpstr.pElems == NULL)
  362. {
  363. AssertSz(0,TEXT("Couldn't allocate memory for pElemsNew"));
  364. goto Exit;
  365. }
  366. // Fill this new buffer so we don't get confused in the error path.
  367. FillBuf (lppropvarDest->calpstr.pElems, 0,
  368. cElems * sizeof(*lppropvarDest->calpstr.pElems));
  369. lppropvarDest->calpstr.cElems = cElems;
  370. // Initialize the pointers for the first string to convert.
  371. lplpstrDest = &lppropvarDest->calpstr.pElems[ 0 ];
  372. lpstrSource = lppropvarSource->calpstr.pElems[ 0 ];
  373. } // if (lppropvar->vt & VT_VECTOR)
  374. else
  375. {
  376. // We're not a vector, initialize to the only string.
  377. cElems = 1;
  378. lplpstrDest = &lppropvarDest->pszVal;
  379. lpstrSource = lppropvarSource->pszVal;
  380. }
  381. // ---------------------
  382. // Convert the String(s)
  383. // ---------------------
  384. while (cElems)
  385. {
  386. if (fConvertToAnsi)
  387. {
  388. if (!FCoWStrToStr ((LPSTR*)lplpstrDest, (LPWSTR) lpstrSource,
  389. uCodePage))
  390. {
  391. goto Exit;
  392. }
  393. }
  394. else
  395. {
  396. if (!FCoStrToWStr ((LPWSTR*) lplpstrDest, (LPSTR) lpstrSource,
  397. uCodePage))
  398. {
  399. goto Exit;
  400. }
  401. }
  402. // Move on to the next entry, if there is one.
  403. if (--cElems)
  404. {
  405. ulIndex++;
  406. lplpstrDest = &lppropvarDest->calpstr.pElems[ ulIndex ];
  407. lpstrSource = lppropvarSource->calpstr.pElems[ ulIndex ];
  408. } // if (--cElems)
  409. } // while (cElems)
  410. // Switch the destination VT to VT_LPSTR (for ansi strings) or VT_LPWSTR
  411. // (for Unicode strings), preserving all other bits.
  412. lppropvarDest->vt = (lppropvarSource->vt & ~(VT_LPSTR|VT_LPWSTR))
  413. |
  414. (fConvertToAnsi ? VT_LPSTR : VT_LPWSTR);
  415. // ----
  416. // Exit
  417. // ----
  418. fSuccess = TRUE;
  419. Exit:
  420. if (!fSuccess)
  421. PropVariantClear (lppropvarDest);
  422. return( fSuccess );
  423. } // FPropVarConvertString
  424. ////////////////////////////////////////////////////////////////////////////////
  425. //
  426. // Function: FPropVarCopyToBuf
  427. //
  428. // Purpose: Copy the value from a PropVariant to a buffer.
  429. // (The caller indicates how large the buffer is).
  430. // The VarType of the PropVar must be from the
  431. // valid Office sub-set.
  432. //
  433. // Inputs: LPPROPVARIANT - The source.
  434. // DWORD - The size of the target buffer.
  435. // LPVOID - The target buffer.
  436. //
  437. // Output: TRUE if successful.
  438. //
  439. ////////////////////////////////////////////////////////////////////////////////
  440. BOOL
  441. FPropVarCopyToBuf
  442. (LPPROPVARIANT const lppropvar,
  443. DWORD cbMax,
  444. LPVOID lpvBuf)
  445. {
  446. // ------
  447. // Locals
  448. // ------
  449. BOOL fSuccess = FALSE;
  450. DWORD cb;
  451. // ----------------
  452. // Check the inputs
  453. // ----------------
  454. Assert (lppropvar != NULL);
  455. Assert (lpvBuf != NULL);
  456. // ---------------------
  457. // Copy, based on the VT
  458. // ---------------------
  459. switch (lppropvar->vt)
  460. {
  461. // File Time
  462. case VT_FILETIME :
  463. if (cbMax < sizeof(FILETIME))
  464. return(FALSE);
  465. PbMemCopy (lpvBuf, &lppropvar->filetime, sizeof(FILETIME));
  466. break;
  467. // Double
  468. case VT_R8:
  469. if (cbMax < sizeof(double))
  470. return(FALSE);
  471. PbMemCopy (lpvBuf, &lppropvar->dblVal, sizeof(double));
  472. // Boolean
  473. case VT_BOOL:
  474. if (cbMax < sizeof(WORD))
  475. return(FALSE);
  476. *(WORD *)lpvBuf = (WORD)lppropvar->boolVal;
  477. break;
  478. // DWORD
  479. case VT_I4:
  480. if (cbMax < sizeof(DWORD))
  481. return(FALSE);
  482. *(DWORD *)lpvBuf = (DWORD)lppropvar->ulVal;
  483. break;
  484. // String
  485. case VT_LPTSTR:
  486. if (lppropvar->pszVal == NULL)
  487. return(FALSE);
  488. // Calculate the number of characters to copy (not
  489. // including the NULL). But don't let it exceed
  490. // cbMax - sizeof('\0').
  491. cb = min ( CchTszLen ((LPTSTR)lppropvar->pszVal) * sizeof(TCHAR),
  492. cbMax - sizeof(TCHAR));
  493. PbMemCopy(lpvBuf, lppropvar->pszVal, cb);
  494. ((LPTSTR) lpvBuf)[ cb/sizeof(TCHAR) ] = TEXT('\0');
  495. break;
  496. // Invalid type.
  497. default :
  498. AssertSz (0, TEXT("Invalid type in FPropVarCopyToBuf"));
  499. goto Exit;
  500. } // switch (lppropvar->vt)
  501. fSuccess = TRUE;
  502. // ----
  503. // Exit
  504. // ----
  505. Exit:
  506. return (fSuccess);
  507. } // FPropVarCopyToBuf