windows-nt/Source/XPSP1/NT/shell/ext/docprop/propvar.c
2020-09-26 16:20:57 +08:00

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