|
|
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
//
// File: PropVar.c
//
// Purpose: This file provides Office-aware routines which
// operate on PropVariants. They are Office-aware in
// that they only operate on the subset of
// VarTypes which are used by Office.
//
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
#include "priv.h"
#pragma hdrstop
/////////////////////////////////////////////////////////////////////////////////
//
// Function: FPropVarLoad
//
// Purpse: Load data into a PropVariant. If the target PropVariant
// already contains data, it will be freed.
//
// Note that new memory is allocated, if necessary, to hold
// the data in the PropVariant. Also note that the
// resulting PropVariant should be freed by the caller using
// PropVariantClear.
//
// Inputs: LPPROPVARIANT - to be loaded. This should be a valid
// (i.e. intialized) PropVariant.
// VARTYPE - of the new PropVariant (must be a member of
// the limited set used by Office).
// LPVOID - Either the data to be loaded, or a pointer
// to such data, depending on the type.
//
// Output: TRUE if and only if successful.
//
/////////////////////////////////////////////////////////////////////////////////
BOOL FPropVarLoad ( LPPROPVARIANT lppropvar, VARTYPE vt, LPVOID const lpv ) { // ------
// Locals
// ------
BOOL fSuccess = FALSE; // Return code
ULONG cch, cb;
// ----------
// Initialize
// ----------
Assert (lppropvar != NULL); Assert (lpv != NULL);
// Free any data currently in the PropVariant.
PropVariantClear (lppropvar);
// ---------------------------------------------------
// Set the value of the PropVariant based on the type.
// ---------------------------------------------------
switch (vt) { // Strings
case VT_LPTSTR:
// Determine the character and byte count.
cch = CchTszLen(lpv); // Doesn't include the NULL.
cb = CBTSTR(lpv); // *Does* include the NULL.
// Allocate memory in the PropVariant.
lppropvar->pszVal = CoTaskMemAlloc (cb); if (lppropvar->pszVal == NULL) { MESSAGE(TEXT("Couldn't allocate new VT_LPTSTR")); goto Exit; }
// Copy the string to the PropVariant and terminate it.
PbSzNCopy (lppropvar->pszVal, lpv, cch); ((LPTSTR)lppropvar->pszVal)[cch] = TEXT('\0');
break;
// DWORDs
case VT_I4:
lppropvar->lVal = *(DWORD*) lpv; break;
// FileTime
case VT_FILETIME:
PbMemCopy (&lppropvar->filetime, lpv, sizeof(FILETIME)); break;
// Double
case VT_R8: PbMemCopy (&lppropvar->dblVal, lpv, sizeof(double)); break;
// Bool
case VT_BOOL: lppropvar->boolVal = *(VARIANT_BOOL*) lpv ? VARIANT_TRUE : VARIANT_FALSE; break;
// Invalid type.
default: MESSAGE(TEXT("Invalid VarType")); goto Exit; }
// Set the VT of the PropVariant, and we're done.
lppropvar->vt = vt;
// ----
// Exit
// ----
fSuccess = TRUE;
Exit: return (fSuccess);
} // FPropVarLoad
////////////////////////////////////////////////////////////////////////////////
//
// Function: FCoStrToWStr
//
// Purpose: Convert a COM string (ANSI) to a COM wide-string.
// ("COM" because the string is allocated using
// the COM heap).
//
// Inputs: LPWSTR* - The converted string.
// LPSTR - The original string.
// UINT - The ANSI code page.
//
// Output: TRUE if and only if successful.
//
////////////////////////////////////////////////////////////////////////////////
BOOL FCoStrToWStr( LPWSTR *lplpwstr, const LPSTR lpstr, UINT uCodePage) { // ------
// Locals
// ------
BOOL fSuccess = FALSE; // Return value.
ULONG cchBuffer = 0; // Size of converted string (includes NULL).
Assert (lpstr != NULL && lplpwstr != NULL);
// ------------------
// Convert the string
// ------------------
// Make two passes. The first will calculate the
// size of the target buffer, the second will actually
// make the conversion.
*lplpwstr = NULL;
while (TRUE) { cchBuffer = MultiByteToWideChar( uCodePage, // Source code page
0, // Default flags
lpstr, // Source string
-1, // Default length
*lplpwstr, // Destination string
cchBuffer ); // Max dest string characters.
// Is this the second pass (when the conversion should
// have taken place)?
if (*lplpwstr != NULL) { // If we got a good result, then we're done.
if (cchBuffer != 0) { break; }
// 0 was returned. There was an error.
else { AssertSz (0, TEXT("Couldn't convert MBCS to Wide")); goto Exit; } }
// Otherwise, this is the first pass. We need to
// allocate a buffer.
else { // We should have gotten a positive buffer size.
if (cchBuffer == 0) { AssertSz(0, TEXT("MultiByteToWideChar returned invalid target buffer size")); goto Exit; }
// Allocate memory for the converted string.
else { *lplpwstr = (LPWSTR) CoTaskMemAlloc( cchBuffer * 2 ); if ( *lplpwstr == NULL) { AssertSz (0, TEXT("Could not allocate memory for wide string")); goto Exit; } } } // if( *lplpwstr != NULL ... else
} // while (TRUE)
// ----
// Exit
// ----
fSuccess = TRUE;
Exit:
// If there was a problem, free the Unicode string.
if (!fSuccess) { CoTaskMemFree (*lplpwstr); *lplpwstr = NULL; }
return (fSuccess);
} // FCoStrToWStr
////////////////////////////////////////////////////////////////////////////////
//
// Function: FCoWStrToStr
//
// Purpose: Convert a COM wide-string to an ANSI string.
// ("COM" because the string is allocated using
// the COM heap).
//
// Inputs: LPSTR* - The converted string.
// LPWSTR - The source string.
// UINT - The ANSI code page.
//
// Output: TRUE if and only if successful.
//
////////////////////////////////////////////////////////////////////////////////
BOOL FCoWStrToStr( LPSTR *lplpstr, const LPWSTR lpwstr, UINT uCodePage) { // ------
// Locals
// ------
BOOL fSuccess = FALSE; // Return result
ULONG cch; // Charcters in original string (w/o NULL).
ULONG cbBuffer = 0; // Size of target buffer (including NULL)
Assert (lpwstr != NULL && lplpstr != NULL);
// ------------------
// Convert the String
// ------------------
// We'll make two calls to WideCharToMultiByte.
// In the first, we'll determine the size required
// for the multi-byte string. We'll use this
// to allocate memory. In the second pass, we'll actually
// make the conversion.
cch = CchWszLen( lpwstr ); // How big is the source string?
*lplpstr = NULL; // Initialize the target buffer.
while (TRUE) { cbBuffer = WideCharToMultiByte( uCodePage, // Source code page
0, // Default flags
lpwstr, // Source string
cch + 1, // # chars in wide string (including NULL)
*lplpstr, // Destination string
cbBuffer, // Size of destination buffer
NULL, NULL ); // No default character
// Is this the second pass (when the conversion should
// have taken place)?
if (*lplpstr != NULL) { // If we got a good result, then we're done.
if (cbBuffer != 0) { break; }
// 0 was returned. There was an error.
else { AssertSz (0, TEXT("Couldn't convert Wide to MBCS")); goto Exit; } }
// Otherwise, this is the first pass. We need to
// allocate a buffer.
else { // We should have gotten a positive buffer size.
if (cbBuffer == 0) { AssertSz(0, TEXT("WideCharMultiByte returned invalid target buffer size")); goto Exit; }
// Allocate memory for the converted string.
else { *lplpstr = (LPSTR) CoTaskMemAlloc( cbBuffer ); if ( *lplpstr == NULL) { AssertSz (0, TEXT("Could not allocate memory for wide string")); goto Exit; } } } // if( lpstr != NULL ... else
} // while (TRUE)
// ----
// Exit
// ----
fSuccess = TRUE;
Exit:
// If there was a problem, free the new string.
if (!fSuccess) { CoTaskMemFree (*lplpstr); *lplpstr = NULL; }
return (fSuccess);
} // FCoWStrToStr
//////////////////////////////////////////////////////////////////////////////
//
// Function: FPropVarConvertString
//
// Purpose: Convert a PropVariant from VT_LPSTR to VT_LPWSTR,
// or vice-versa. The correct direction is inferred
// from the input. The source PropVariant is not
// modified.
//
// If the PropVariant is a Vector, all elements are
// converted.
//
// Inputs: LPPROPVARIANT - The buffer in which to put the
// converted PropVariant.
// LPPROPVARIANT - The source of the conversion.
// UINT - The code page of VT_LPSTRs.
//
// Output: TRUE if successful. If unsuccessful, the original
// PropVariant will be returned unmodified.
//
// Pre-Conditions:
// The input must be either a VT_LPSTR or a VT_LPWSTR
// (with or without the VT_VECTOR bit set).
// &&
// The destination PropVariant is VT_EMPTY.
// &&
// The code page must not be CP_WINUNICODE (Unicode
// LPSTRs are not legal in the SumInfo property sets).
//
//////////////////////////////////////////////////////////////////////////////
BOOL FPropVarConvertString( LPPROPVARIANT lppropvarDest, const LPPROPVARIANT lppropvarSource, UINT uCodePage) {
// ------
// Locals
// ------
BOOL fSuccess = FALSE; // Return code.
BOOL fConvertToAnsi; // Indicates the direction of the conversion.
LPSTR *lplpstrDest; // Pointer to pointer to a converted string.
LPSTR lpstrSource; // Pointer to a string to be converted.
ULONG cElems; // The number of strings still requiring conversion
ULONG ulIndex = 0; // Index into vector (if this VT is a vector)
// ----------
// Initialize
// ----------
Assert(lppropvarDest != NULL && lppropvarSource != NULL); Assert(lppropvarDest->vt == VT_EMPTY); Assert(uCodePage != CP_WINUNICODE);
// Determine the direction of the conversion.
fConvertToAnsi = (lppropvarSource->vt & ~VT_VECTOR) == VT_LPSTR ? FALSE : TRUE;
// -----------------------------------
// Initialize based on the Vector bit.
// -----------------------------------
if (lppropvarSource->vt & VT_VECTOR) { // We're a vector.
cElems = lppropvarSource->calpstr.cElems;
// Allocate an array of string pointers, putting it in
// lppropvarDest.
lppropvarDest->calpstr.pElems = CoTaskMemAlloc( cElems * sizeof(*lppropvarDest->calpstr.pElems) ); if (lppropvarDest->calpstr.pElems == NULL) { AssertSz(0,TEXT("Couldn't allocate memory for pElemsNew")); goto Exit; }
// Fill this new buffer so we don't get confused in the error path.
FillBuf (lppropvarDest->calpstr.pElems, 0, cElems * sizeof(*lppropvarDest->calpstr.pElems));
lppropvarDest->calpstr.cElems = cElems;
// Initialize the pointers for the first string to convert.
lplpstrDest = &lppropvarDest->calpstr.pElems[ 0 ]; lpstrSource = lppropvarSource->calpstr.pElems[ 0 ];
} // if (lppropvar->vt & VT_VECTOR)
else { // We're not a vector, initialize to the only string.
cElems = 1;
lplpstrDest = &lppropvarDest->pszVal; lpstrSource = lppropvarSource->pszVal; }
// ---------------------
// Convert the String(s)
// ---------------------
while (cElems) {
if (fConvertToAnsi) { if (!FCoWStrToStr ((LPSTR*)lplpstrDest, (LPWSTR) lpstrSource, uCodePage)) { goto Exit; } } else { if (!FCoStrToWStr ((LPWSTR*) lplpstrDest, (LPSTR) lpstrSource, uCodePage)) { goto Exit; } }
// Move on to the next entry, if there is one.
if (--cElems) { ulIndex++; lplpstrDest = &lppropvarDest->calpstr.pElems[ ulIndex ]; lpstrSource = lppropvarSource->calpstr.pElems[ ulIndex ];
} // if (--cElems)
} // while (cElems)
// Switch the destination VT to VT_LPSTR (for ansi strings) or VT_LPWSTR
// (for Unicode strings), preserving all other bits.
lppropvarDest->vt = (lppropvarSource->vt & ~(VT_LPSTR|VT_LPWSTR)) | (fConvertToAnsi ? VT_LPSTR : VT_LPWSTR);
// ----
// Exit
// ----
fSuccess = TRUE;
Exit:
if (!fSuccess) PropVariantClear (lppropvarDest);
return( fSuccess );
} // FPropVarConvertString
////////////////////////////////////////////////////////////////////////////////
//
// Function: FPropVarCopyToBuf
//
// Purpose: Copy the value from a PropVariant to a buffer.
// (The caller indicates how large the buffer is).
// The VarType of the PropVar must be from the
// valid Office sub-set.
//
// Inputs: LPPROPVARIANT - The source.
// DWORD - The size of the target buffer.
// LPVOID - The target buffer.
//
// Output: TRUE if successful.
//
////////////////////////////////////////////////////////////////////////////////
BOOL FPropVarCopyToBuf (LPPROPVARIANT const lppropvar, DWORD cbMax, LPVOID lpvBuf) { // ------
// Locals
// ------
BOOL fSuccess = FALSE; DWORD cb;
// ----------------
// Check the inputs
// ----------------
Assert (lppropvar != NULL); Assert (lpvBuf != NULL);
// ---------------------
// Copy, based on the VT
// ---------------------
switch (lppropvar->vt) { // File Time
case VT_FILETIME : if (cbMax < sizeof(FILETIME)) return(FALSE); PbMemCopy (lpvBuf, &lppropvar->filetime, sizeof(FILETIME)); break;
// Double
case VT_R8: if (cbMax < sizeof(double)) return(FALSE); PbMemCopy (lpvBuf, &lppropvar->dblVal, sizeof(double));
// Boolean
case VT_BOOL: if (cbMax < sizeof(WORD)) return(FALSE);
*(WORD *)lpvBuf = (WORD)lppropvar->boolVal; break;
// DWORD
case VT_I4: if (cbMax < sizeof(DWORD)) return(FALSE);
*(DWORD *)lpvBuf = (DWORD)lppropvar->ulVal; break;
// String
case VT_LPTSTR: if (lppropvar->pszVal == NULL) return(FALSE);
// Calculate the number of characters to copy (not
// including the NULL). But don't let it exceed
// cbMax - sizeof('\0').
cb = min ( CchTszLen ((LPTSTR)lppropvar->pszVal) * sizeof(TCHAR), cbMax - sizeof(TCHAR));
PbMemCopy(lpvBuf, lppropvar->pszVal, cb); ((LPTSTR) lpvBuf)[ cb/sizeof(TCHAR) ] = TEXT('\0'); break;
// Invalid type.
default : AssertSz (0, TEXT("Invalid type in FPropVarCopyToBuf")); goto Exit;
} // switch (lppropvar->vt)
fSuccess = TRUE;
// ----
// Exit
// ----
Exit:
return (fSuccess);
} // FPropVarCopyToBuf
|