675 lines
18 KiB
C
675 lines
18 KiB
C
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
|
|
|
|
|