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.
2014 lines
72 KiB
2014 lines
72 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1994 - 2000.
|
|
//
|
|
// File: tblvarnt.cxx
|
|
//
|
|
// Contents: Class to aid in dealing with PROPVARIANTs in the result table.
|
|
//
|
|
// Classes: VARNT_DATA - size and allignment constraints of variant types
|
|
// CTableVariant - Wrapper around PROPVARIANT
|
|
//
|
|
// History: 25 Jan 1994 AlanW Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pch.cxx"
|
|
#pragma hdrstop
|
|
|
|
#include <bigtable.hxx>
|
|
#include <tblvarnt.hxx>
|
|
#include <pmalloc.hxx>
|
|
|
|
#include "tabledbg.hxx"
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// The following structure gives the size and allignment requirements
|
|
// to store a bare variant type (without the variant overhead) in window
|
|
// row data. For variable length data, information about the location
|
|
// of pointers in the structure is given.
|
|
//
|
|
// Flags information is given as follows:
|
|
// 01 (CanBeVector) - base type can be in a vector
|
|
// 02 (ByRef) - includes pointer in first word of data part
|
|
// 04 (CntRef) - includes pointer in second word of data part
|
|
// 08 (StoreDirect) - variant form includes pointer; store direct in table
|
|
// 10 (MultiSize) - for data like BYTES that is inline in client output
|
|
// 20 (SimpleType) - simple inline datatype, like VT_I4
|
|
// 40 (OAType) - valid in OLE Automation variants (older style)
|
|
//
|
|
// NOTE: This table includes all valid types in PROPVARIANT;
|
|
// it is not limited to types in OLE-DB's appendix A.
|
|
// NOTE: Some types are listed in wtypes.h as being valid in automation
|
|
// variants, but we can't mark them as OAType until the language
|
|
// interpreters catch up and recognize those types.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
const CTableVariant::VARNT_DATA CTableVariant::varntData [] = {
|
|
// DBTYPE_VECTOR 0x1000
|
|
// DBTYPE_BYREF 0x4000
|
|
|
|
/* 0 0 VT_EMPTY */ { 0, 0, SimpleType|OAType},
|
|
/* 1 1 VT_NULL */ { 0, 0, SimpleType},
|
|
/* 2 2 VT_I2 */ { sizeof (short), sizeof (short), CanBeVector|SimpleType|OAType},
|
|
/* 3 3 VT_I4 */ { sizeof (long), sizeof (long), CanBeVector|SimpleType|OAType},
|
|
/* 4 4 VT_R4 */ { sizeof (float), sizeof (float), CanBeVector|SimpleType|OAType},
|
|
/* 5 5 VT_R8 */ { sizeof (double), sizeof (double), CanBeVector|SimpleType|OAType},
|
|
/* 6 6 VT_CY */ { sizeof (CY), sizeof (CY), CanBeVector|SimpleType|OAType},
|
|
/* 7 7 VT_DATE */ { sizeof (DATE), sizeof (DATE), CanBeVector|SimpleType|OAType},
|
|
/* 8 8 VT_BSTR */ { sizeof (void*), sizeof (void*), CanBeVector|ByRef|OAType},
|
|
/* 9 9 VT_DISPATCH*/ { sizeof (void *), sizeof (void *), 0},
|
|
/* a 10 VT_ERROR */ { sizeof(SCODE), sizeof(SCODE), CanBeVector|SimpleType|OAType},
|
|
/* b 11 VT_BOOL */ { sizeof (VARIANT_BOOL), sizeof (VARIANT_BOOL), CanBeVector|SimpleType|OAType},
|
|
/* c 12 VT_VARIANT */ { sizeof (PROPVARIANT), sizeof (double), ByRef|StoreDirect|CanBeVector|OAType},
|
|
/* d 13 VT_UNKNOWN */ { sizeof (void *), sizeof (void *), 0},
|
|
/* e 14 VT_DECIMAL */ { sizeof (DECIMAL), sizeof (LARGE_INTEGER), SimpleType|OAType},
|
|
/* f 15 */ { 0, 0, 0},
|
|
/* 10 16 VT_I1 */ { sizeof(char), sizeof(char), CanBeVector|SimpleType},
|
|
/* 11 17 VT_UI1 */ { sizeof(UCHAR), sizeof(UCHAR), CanBeVector|SimpleType|OAType},
|
|
/* 12 18 VT_UI2 */ { sizeof(unsigned short), sizeof(unsigned short), CanBeVector|SimpleType},
|
|
/* 13 19 VT_UI4 */ { sizeof(unsigned long), sizeof(unsigned long), CanBeVector|SimpleType},
|
|
/* 14 20 VT_I8 */ { sizeof (LARGE_INTEGER), sizeof (LARGE_INTEGER), CanBeVector|SimpleType},
|
|
/* 15 21 VT_UI8 */ { sizeof (LARGE_INTEGER), sizeof (LARGE_INTEGER), CanBeVector|SimpleType},
|
|
|
|
/* 16 22 VT_INT */ { sizeof (INT), sizeof (INT), SimpleType},
|
|
/* 17 23 VT_UINT */ { sizeof (UINT), sizeof (UINT), SimpleType},
|
|
// Codes 24-29 are valid for typelibs only
|
|
/* 18 24 */ { 0, 0, 0},
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 25-29, unused
|
|
/* 1e 30 VT_LPSTR */ { sizeof (LPSTR), sizeof (LPSTR), CanBeVector|ByRef},
|
|
/* 1f 31 VT_LPWSTR */ { sizeof (LPWSTR), sizeof (LPWSTR), CanBeVector|ByRef},
|
|
/* 20 32 */ { 0, 0, 0},
|
|
/* 21 33 */ { 0, 0, 0},
|
|
/* 22 34 */ { 0, 0, 0},
|
|
/* 23 35 */ { 0, 0, 0},
|
|
/* 24 36 VT_RECORD? */ { 0, 0, 0}, // SPECDEVIATION - what is it?
|
|
{0,0,0}, {0,0,0}, {0,0,0}, // 37-39, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 40-44, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 45-49, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 50-54, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 55-59, unused
|
|
/* 3c 60 */ { 0, 0, 0},
|
|
/* 3d 61 */ { 0, 0, 0},
|
|
/* 3e 62 */ { 0, 0, 0},
|
|
/* 3f 63 */ { 0, 0, 0},
|
|
/* 40 64 VT_FILETIME*/ { sizeof (FILETIME), sizeof (FILETIME), CanBeVector|SimpleType},
|
|
/* 41 65 VT_BLOB */ { sizeof (BLOB), sizeof (void*), CntRef},
|
|
|
|
// Can these really occur in properties??? varnt.idl says they
|
|
// are interface pointers
|
|
/* 42 66 VT_STREAM */ { sizeof (LPWSTR), sizeof (LPWSTR), ByRef},
|
|
/* 43 67 VT_STORAGE */ { sizeof (LPWSTR), sizeof (LPWSTR), ByRef},
|
|
|
|
// NOTE: object-valued properties must be retrieved as Entry IDs
|
|
// (workid, propid)
|
|
|
|
// Can these really occur in properties??? varnt.idl says they
|
|
// are interface pointers. Even if so, is the definition
|
|
// below appropriate?
|
|
|
|
/* 44 68 VT_STREAMED_OBJECT */ { 2*sizeof (ULONG), sizeof (ULONG), 0},
|
|
/* 45 69 VT_STORED_OBJECT */ { 2*sizeof (ULONG), sizeof (ULONG), 0},
|
|
/* 46 70 VT_BLOB_OBJECT */ { 2*sizeof (ULONG), sizeof (ULONG), 0},
|
|
/* 47 71 VT_CF */ { sizeof (CLIPDATA*), sizeof (CLIPDATA*), CanBeVector|ByRef},
|
|
/* 48 72 VT_CLSID */ { sizeof (GUID), sizeof DWORD, StoreDirect|ByRef|CanBeVector},
|
|
};
|
|
|
|
const unsigned CTableVariant::cVarntData = sizeof CTableVariant::varntData /
|
|
sizeof CTableVariant::varntData[0];
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// This table is like the table above, but is for DBVARIANT extensions,
|
|
// i.e., those whose variant type values are 128 and above.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
const CTableVariant::VARNT_DATA CTableVariant::varntExtData [] = {
|
|
//
|
|
// Additional type definitions above those in PROPVARIANT.
|
|
// Some cannot be used for variant binding.
|
|
//
|
|
{ 0, sizeof BYTE, MultiSize}, // DBTYPE_BYTES = x80 128,
|
|
{ 0, sizeof CHAR, MultiSize}, // DBTYPE_STR = x81 129,
|
|
{ 0, sizeof WCHAR, MultiSize}, // DBTYPE_WSTR = x82 130,
|
|
{ sizeof LONGLONG, sizeof LONGLONG, 0}, // DBTYPE_NUMERIC = x83 131,
|
|
{ 0, 0, 0}, // DBTYPE_UDT = x84 132,
|
|
{ sizeof DBDATE, sizeof USHORT, 0}, // DBTYPE_DBDATE = x85 133,
|
|
{ sizeof DBTIME, sizeof USHORT, 0}, // DBTYPE_DBTIME = x86 134,
|
|
{ sizeof DBTIMESTAMP, sizeof ULONG, 0}, // DBTYPE_DBTIMESTAMP= x87 135,
|
|
{ sizeof HCHAPTER, sizeof ULONG, 0}, // DBTYPE_HCHAPTER = x88 136,
|
|
{ 0, 0, 0}, // was DBTYPE_DBFILETIME
|
|
{ sizeof PROPVARIANT, sizeof(double), 0}, // DBTYPE_PROPVARIANT = X8a 138,
|
|
{ sizeof DB_VARNUMERIC, sizeof BYTE, 0}, // DBTYPE_VARNUMERIC = x8b 139,
|
|
};
|
|
|
|
const unsigned CTableVariant::cVarntExtData =
|
|
sizeof CTableVariant::varntExtData / sizeof CTableVariant::varntExtData[0];
|
|
|
|
#ifdef _WIN64
|
|
//
|
|
// VARIANT DATA for Win32 clients on a Win64 server
|
|
// Pointer references must be 32 bits in length (sizeof ULONG)
|
|
// See '+' for changed entries
|
|
//
|
|
|
|
const CTableVariant::VARNT_DATA CTableVariant::varntData32 [] = {
|
|
// DBTYPE_VECTOR 0x1000
|
|
// DBTYPE_BYREF 0x4000
|
|
|
|
/* 0 0 VT_EMPTY */ { 0, 0, SimpleType|OAType},
|
|
/* 1 1 VT_NULL */ { 0, 0, SimpleType},
|
|
/* 2 2 VT_I2 */ { sizeof (short), sizeof (short), CanBeVector|SimpleType|OAType},
|
|
/* 3 3 VT_I4 */ { sizeof (long), sizeof (long), CanBeVector|SimpleType|OAType},
|
|
/* 4 4 VT_R4 */ { sizeof (float), sizeof (float), CanBeVector|SimpleType|OAType},
|
|
/* 5 5 VT_R8 */ { sizeof (double), sizeof (double), CanBeVector|SimpleType|OAType},
|
|
/* 6 6 VT_CY */ { sizeof (CY), sizeof (CY), CanBeVector|SimpleType|OAType},
|
|
/* 7 7 VT_DATE */ { sizeof (DATE), sizeof (DATE), CanBeVector|SimpleType|OAType},
|
|
/*+8 8 VT_BSTR */ { sizeof (ULONG), sizeof (ULONG), CanBeVector|ByRef|OAType},
|
|
/*+9 9 VT_DISPATCH*/ { sizeof (ULONG), sizeof (ULONG), 0},
|
|
/* a 10 VT_ERROR */ { sizeof (SCODE), sizeof(SCODE), CanBeVector|SimpleType|OAType},
|
|
/* b 11 VT_BOOL */ { sizeof (VARIANT_BOOL), sizeof (VARIANT_BOOL), CanBeVector|SimpleType|OAType},
|
|
/*+c 12 VT_VARIANT */ { sizeof (PROPVARIANT32), sizeof (double), ByRef|StoreDirect|CanBeVector|OAType},
|
|
/* d 13 VT_UNKNOWN */ { sizeof (ULONG), sizeof (ULONG), 0},
|
|
/* e 14 VT_DECIMAL */ { sizeof (DECIMAL), sizeof (LARGE_INTEGER), SimpleType|OAType},
|
|
/* f 15 */ { 0, 0, 0},
|
|
/* 10 16 VT_I1 */ { sizeof(char), sizeof(char), CanBeVector|SimpleType},
|
|
/* 11 17 VT_UI1 */ { sizeof(UCHAR), sizeof(UCHAR), CanBeVector|SimpleType|OAType},
|
|
/* 12 18 VT_UI2 */ { sizeof(unsigned short), sizeof(unsigned short), CanBeVector|SimpleType},
|
|
/* 13 19 VT_UI4 */ { sizeof(unsigned long), sizeof(unsigned long), CanBeVector|SimpleType},
|
|
/* 14 20 VT_I8 */ { sizeof (LARGE_INTEGER), sizeof (LARGE_INTEGER), CanBeVector|SimpleType},
|
|
/* 15 21 VT_UI8 */ { sizeof (LARGE_INTEGER), sizeof (LARGE_INTEGER), CanBeVector|SimpleType},
|
|
|
|
/* 16 22 VT_INT */ { sizeof (INT), sizeof (INT), SimpleType},
|
|
/* 17 23 VT_UINT */ { sizeof (UINT), sizeof (UINT), SimpleType},
|
|
// Codes 24-29 are valid for typelibs only
|
|
/* 18 24 */ { 0, 0, 0},
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 25-29, unused
|
|
/*+1e 30 VT_LPSTR */ { sizeof (ULONG), sizeof (ULONG), CanBeVector|ByRef},
|
|
/* 1f 31 VT_LPWSTR */ { sizeof (ULONG), sizeof (ULONG), CanBeVector|ByRef},
|
|
/* 20 32 */ { 0, 0, 0},
|
|
/* 21 33 */ { 0, 0, 0},
|
|
/* 22 34 */ { 0, 0, 0},
|
|
/* 23 35 */ { 0, 0, 0},
|
|
/* 24 36 VT_RECORD? */ { 0, 0, 0}, // SPECDEVIATION - what is it?
|
|
{0,0,0}, {0,0,0}, {0,0,0}, // 37-39, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 40-44, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 45-49, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 50-54, unused
|
|
{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, // 55-59, unused
|
|
/* 3c 60 */ { 0, 0, 0},
|
|
/* 3d 61 */ { 0, 0, 0},
|
|
/* 3e 62 */ { 0, 0, 0},
|
|
/* 3f 63 */ { 0, 0, 0},
|
|
/* 40 64 VT_FILETIME*/ { sizeof (FILETIME), sizeof (FILETIME), CanBeVector|SimpleType},
|
|
/*+41 65 VT_BLOB */ { sizeof (BLOB32), sizeof (ULONG), CntRef},
|
|
|
|
// Can these really occur in properties??? varnt.idl says they
|
|
// are interface pointers
|
|
/*+42 66 VT_STREAM */ { sizeof (ULONG), sizeof (ULONG), ByRef},
|
|
/*+43 67 VT_STORAGE */ { sizeof (ULONG), sizeof (ULONG), ByRef},
|
|
|
|
// NOTE: object-valued properties must be retrieved as Entry IDs
|
|
// (workid, propid)
|
|
|
|
// Can these really occur in properties??? varnt.idl says they
|
|
// are interface pointers. Even if so, is the definition
|
|
// below appropriate?
|
|
|
|
/* 44 68 VT_STREAMED_OBJECT */ { 2*sizeof (ULONG), sizeof (ULONG), 0},
|
|
/* 45 69 VT_STORED_OBJECT */ { 2*sizeof (ULONG), sizeof (ULONG), 0},
|
|
/* 46 70 VT_BLOB_OBJECT */ { 2*sizeof (ULONG), sizeof (ULONG), 0},
|
|
/*+47 71 VT_CF */ { sizeof (ULONG), sizeof (ULONG), CanBeVector|ByRef},
|
|
/* 48 72 VT_CLSID */ { sizeof (GUID), sizeof DWORD, StoreDirect|ByRef|CanBeVector},
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// This table is like the table above, but is for DBVARIANT extensions,
|
|
// i.e., those whose variant type values are 128 and above.
|
|
//
|
|
// This one is also for 64 bit servers talking to 32 bit clients
|
|
//--------------------------------------------------------------------------
|
|
|
|
const CTableVariant::VARNT_DATA CTableVariant::varntExtData32 [] = {
|
|
//
|
|
// Additional type definitions above those in PROPVARIANT.
|
|
// Some cannot be used for variant binding.
|
|
//
|
|
{ 0, sizeof BYTE, MultiSize}, // DBTYPE_BYTES = x80 128,
|
|
{ 0, sizeof CHAR, MultiSize}, // DBTYPE_STR = x81 129,
|
|
{ 0, sizeof WCHAR, MultiSize}, // DBTYPE_WSTR = x82 130,
|
|
{ sizeof LONGLONG, sizeof LONGLONG, 0}, // DBTYPE_NUMERIC = x83 131,
|
|
{ 0, 0, 0}, // DBTYPE_UDT = x84 132,
|
|
{ sizeof DBDATE, sizeof USHORT, 0}, // DBTYPE_DBDATE = x85 133,
|
|
{ sizeof DBTIME, sizeof USHORT, 0}, // DBTYPE_DBTIME = x86 134,
|
|
{ sizeof DBTIMESTAMP, sizeof ULONG, 0}, // DBTYPE_DBTIMESTAMP= x87 135,
|
|
{ sizeof ULONG, sizeof ULONG, 0}, // DBTYPE_HCHAPTER = x88 136,
|
|
{ 0, 0, 0}, // was DBTYPE_DBFILETIME
|
|
{ sizeof PROPVARIANT32, sizeof(double), 0}, // DBTYPE_PROPVARIANT = X8a 138,
|
|
{ sizeof DB_VARNUMERIC, sizeof BYTE, 0}, // DBTYPE_VARNUMERIC = x8b 139,
|
|
};
|
|
|
|
#endif // _WIN64
|
|
|
|
|
|
//
|
|
// Variant helper methods
|
|
//
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::Copy, public
|
|
// CTableVariant::CopyData, private
|
|
//
|
|
// Synopsis: Copy the data of a variant. One method copies the variant
|
|
// and its data, the other copies the variant only.
|
|
//
|
|
// Arguments: [pvarntDest] - pointer to destination variant (Copy method only)
|
|
// [rVarAllocator] - pointer to variable allocator for dest. data
|
|
// [cbDest] - expected size in bytes of variable data
|
|
// [pbBias] - base address of variable data if offset stored in
|
|
// variant
|
|
//
|
|
// Returns: VOID* - the address to which the data was copied
|
|
//
|
|
// Notes: If the variant is an internal form, double indirect
|
|
// data will use offsets, not pointers. The input
|
|
// variant from external callers will generally have
|
|
// pointers, not offsets even for internal form variants.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CTableVariant::Copy(
|
|
CTableVariant *pvarntDest,
|
|
PVarAllocator &rVarAllocator,
|
|
USHORT cbDest,
|
|
BYTE* pbBias) const
|
|
{
|
|
// Copy into a temp variant so if copy fails the output variant
|
|
// isn't affected. Clients don't always check return codes.
|
|
|
|
CTableVariant tmp = *this;
|
|
|
|
BOOL fBased = rVarAllocator.IsBasedMemory();
|
|
if ( fBased )
|
|
{
|
|
tmp.SetDataSize((USHORT) cbDest);
|
|
}
|
|
else
|
|
{
|
|
tmp.ResetDataSize( );
|
|
}
|
|
|
|
if (cbDest != 0)
|
|
{
|
|
BYTE* pbDest = (BYTE *) CopyData(rVarAllocator, cbDest, pbBias);
|
|
|
|
if ( fBased )
|
|
pbDest = (BYTE*) rVarAllocator.PointerToOffset(pbDest);
|
|
|
|
if ( tmp.VariantPointerInFirstWord() )
|
|
{
|
|
tmp.pszVal = (LPSTR)pbDest;
|
|
}
|
|
else
|
|
{
|
|
Win4Assert( tmp.VariantPointerInSecondWord() );
|
|
|
|
tmp.blob.pBlobData = pbDest;
|
|
}
|
|
}
|
|
|
|
*pvarntDest = tmp;
|
|
}
|
|
|
|
|
|
VOID* CTableVariant::CopyData(
|
|
PVarAllocator &rVarAllocator,
|
|
USHORT cbDest, BYTE* pbBias ) const
|
|
{
|
|
BYTE* pbSrc = VariantPointerInFirstWord() ?
|
|
(BYTE*)pszVal : blob.pBlobData;
|
|
pbSrc += (ULONG_PTR)pbBias;
|
|
|
|
Win4Assert( cbDest != 0 );
|
|
|
|
// optimize this most typical path
|
|
if ( VT_LPWSTR == vt )
|
|
{
|
|
return (BYTE*) rVarAllocator.CopyTo( cbDest, pbSrc );
|
|
}
|
|
|
|
if (vt == VT_BSTR)
|
|
{
|
|
// Need to allow for byte count before the string
|
|
return rVarAllocator.CopyBSTR(cbDest -
|
|
(sizeof (DWORD) + sizeof (OLECHAR)),
|
|
(WCHAR *)pbSrc );
|
|
}
|
|
|
|
//
|
|
// Determine if offsets or pointers are used in the source data. If
|
|
// offsets are used, and offsets will be used in the destination, the
|
|
// data can simply be block copied. Otherwise, vectors of strings and
|
|
// vectors of variants must have pointers translated to offsets or
|
|
// vice-versa.
|
|
//
|
|
|
|
if ( _IsInternalVariant() && rVarAllocator.IsBasedMemory() )
|
|
{
|
|
Win4Assert( vt != VT_VARIANT && vt != VT_BSTR );
|
|
//
|
|
// We're copying with offsets to a destination with offsets.
|
|
// Just copy.
|
|
//
|
|
return rVarAllocator.CopyTo(cbDest, pbSrc);
|
|
}
|
|
|
|
BYTE* pbDest = 0;
|
|
|
|
switch (vt)
|
|
{
|
|
case VT_LPSTR:
|
|
case VT_CLSID:
|
|
case VT_BLOB:
|
|
case VT_VECTOR | VT_I2:
|
|
case VT_VECTOR | VT_I4:
|
|
case VT_VECTOR | VT_R4:
|
|
case VT_VECTOR | VT_R8:
|
|
case VT_VECTOR | VT_CY:
|
|
case VT_VECTOR | VT_DATE:
|
|
case VT_VECTOR | VT_ERROR:
|
|
case VT_VECTOR | VT_BOOL:
|
|
case VT_VECTOR | VT_I1:
|
|
case VT_VECTOR | VT_UI1:
|
|
case VT_VECTOR | VT_UI2:
|
|
case VT_VECTOR | VT_UI4:
|
|
case VT_VECTOR | VT_I8:
|
|
case VT_VECTOR | VT_UI8:
|
|
case VT_VECTOR | VT_FILETIME:
|
|
case VT_VECTOR | VT_CLSID:
|
|
//
|
|
// There are no embedded pointers. Just copy.
|
|
//
|
|
pbDest = (BYTE*) rVarAllocator.CopyTo(cbDest, pbSrc);
|
|
break;
|
|
|
|
case VT_VECTOR | VT_BSTR:
|
|
pbDest = (BYTE*) rVarAllocator.Allocate( calpstr.cElems * sizeof (BSTR) );
|
|
|
|
if (pbDest != 0)
|
|
{
|
|
BSTR* paStr = (BSTR*) pbDest;
|
|
CABSTR caStr = cabstr;
|
|
caStr.pElems = (BSTR*)pbSrc;
|
|
|
|
for (unsigned i = 0; i < caStr.cElems; i++)
|
|
{
|
|
pbSrc = pbBias + (ULONG_PTR) caStr.pElems[i];
|
|
|
|
ULONG cb = BSTRLEN((BSTR)pbSrc);
|
|
|
|
BYTE *pbTmp = (BYTE *) rVarAllocator.PointerToOffset(
|
|
rVarAllocator.CopyBSTR(cb, (WCHAR*)pbSrc));
|
|
|
|
paStr[i] = (BSTR) pbTmp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_VECTOR | VT_LPWSTR:
|
|
case VT_VECTOR | VT_LPSTR:
|
|
pbDest = (BYTE*) rVarAllocator.Allocate( calpstr.cElems * sizeof (LPSTR) );
|
|
|
|
if (pbDest != 0)
|
|
{
|
|
LPSTR* paStr = (LPSTR*) pbDest;
|
|
CALPSTR caStr = calpstr;
|
|
caStr.pElems = (LPSTR*)pbSrc;
|
|
|
|
for (unsigned i = 0; i < caStr.cElems; i++)
|
|
{
|
|
ULONG cb;
|
|
pbSrc = pbBias + (ULONG_PTR) caStr.pElems[i];
|
|
|
|
if ( ( VT_LPWSTR | VT_VECTOR ) == vt )
|
|
cb = (wcslen((LPWSTR)pbSrc) + 1) * sizeof (WCHAR);
|
|
else
|
|
cb = (strlen((LPSTR)pbSrc) + 1) * sizeof (CHAR);
|
|
|
|
paStr[i] = (LPSTR) rVarAllocator.PointerToOffset(
|
|
rVarAllocator.CopyTo(cb, pbSrc));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_CF:
|
|
{
|
|
pbDest = (BYTE *) rVarAllocator.Allocate( sizeof CLIPDATA );
|
|
CLIPDATA *pClipData = (CLIPDATA *) pbDest;
|
|
pClipData->cbSize = pclipdata->cbSize;
|
|
pClipData->ulClipFmt = pclipdata->ulClipFmt;
|
|
|
|
ULONG cbData = CBPCLIPDATA( *pclipdata );
|
|
pClipData->pClipData = 0;
|
|
pClipData->pClipData = (BYTE *) rVarAllocator.Allocate( cbData );
|
|
RtlCopyMemory( pClipData->pClipData, pclipdata->pClipData, cbData );
|
|
pClipData->pClipData = (BYTE *) rVarAllocator.PointerToOffset( pClipData->pClipData );
|
|
}
|
|
break;
|
|
|
|
case VT_VECTOR | VT_CF:
|
|
{
|
|
// allocate the array of pointers to clip format elements
|
|
|
|
ULONG cbArray = caclipdata.cElems * sizeof caclipdata.pElems[0];
|
|
pbDest = (BYTE *) rVarAllocator.Allocate( cbArray );
|
|
|
|
if ( 0 != pbDest )
|
|
{
|
|
CLIPDATA * aData = (CLIPDATA *) pbDest;
|
|
RtlZeroMemory( aData, cbArray );
|
|
|
|
for ( unsigned i = 0; i < caclipdata.cElems; i++ )
|
|
{
|
|
aData[i].cbSize = caclipdata.pElems[i].cbSize;
|
|
aData[i].ulClipFmt = caclipdata.pElems[i].ulClipFmt;
|
|
ULONG cbData = CBPCLIPDATA( caclipdata.pElems[ i ] );
|
|
aData[i].pClipData = (BYTE *) rVarAllocator.Allocate( cbData );
|
|
RtlCopyMemory( aData[i].pClipData,
|
|
caclipdata.pElems[i].pClipData,
|
|
cbData );
|
|
aData[i].pClipData = (BYTE *) rVarAllocator.PointerToOffset( aData[i].pClipData );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_VECTOR | VT_VARIANT:
|
|
//
|
|
// Copy vector of variant. Recurses for any element of the
|
|
// vector that has variable data. Special handling is needed
|
|
// for the case of pVarAllocator being a size allocator, which
|
|
// is indicated by an allocation return being zero (the allocators
|
|
// throw an exception if out of memory).
|
|
//
|
|
|
|
pbDest = (BYTE*) rVarAllocator.Allocate( capropvar.cElems *
|
|
sizeof CTableVariant );
|
|
|
|
if (pbDest != 0)
|
|
{
|
|
CTableVariant* paVarnt = (CTableVariant*) pbDest;
|
|
|
|
CTableVariant* paSrcVarnt = (CTableVariant*)
|
|
(pbBias + (ULONG_PTR) capropvar.pElems);
|
|
for (unsigned i = 0; i < capropvar.cElems; i++)
|
|
{
|
|
ULONG cbVarData = paSrcVarnt->VarDataSize();
|
|
Win4Assert( cbVarData <= USHRT_MAX );
|
|
|
|
paSrcVarnt->Copy(paVarnt, rVarAllocator, (USHORT)cbVarData,
|
|
_IsInternalVariant() ? (BYTE *)paSrcVarnt : 0);
|
|
|
|
paSrcVarnt++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_ARRAY | VT_I2:
|
|
case VT_ARRAY | VT_I4:
|
|
case VT_ARRAY | VT_R4:
|
|
case VT_ARRAY | VT_R8:
|
|
case VT_ARRAY | VT_CY:
|
|
case VT_ARRAY | VT_DATE:
|
|
case VT_ARRAY | VT_BSTR:
|
|
case VT_ARRAY | VT_ERROR:
|
|
case VT_ARRAY | VT_BOOL:
|
|
case VT_ARRAY | VT_VARIANT:
|
|
case VT_ARRAY | VT_DECIMAL:
|
|
case VT_ARRAY | VT_I1:
|
|
case VT_ARRAY | VT_UI1:
|
|
case VT_ARRAY | VT_UI2:
|
|
case VT_ARRAY | VT_UI4:
|
|
case VT_ARRAY | VT_INT:
|
|
case VT_ARRAY | VT_UINT:
|
|
{
|
|
SAFEARRAY * pSaSrc = parray;
|
|
SAFEARRAY * pSaDest = 0;
|
|
|
|
if ( SaCreateAndCopy( rVarAllocator, pSaSrc, &pSaDest ) &&
|
|
0 != pSaDest )
|
|
SaCreateData( rVarAllocator,
|
|
vt & ~VT_ARRAY,
|
|
*pSaSrc,
|
|
*pSaDest,
|
|
TRUE );
|
|
|
|
pbDest = (BYTE*)pSaDest;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
tbDebugOut(( DEB_WARN, "Unsupported variant type %4x\n", (int) vt ));
|
|
Win4Assert(! "Unsupported variant type in CTableVariant::CopyData");
|
|
}
|
|
|
|
//
|
|
// NOTE: pbDest can be null if the allocator we were passed is a
|
|
// size allocator.
|
|
//
|
|
//Win4Assert(pbDest != 0);
|
|
return pbDest;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::FixDataPointers, public
|
|
//
|
|
// Synopsis: Adjust offsets to be pointers for variable data
|
|
//
|
|
// Arguments: [pbBias] - adjustment base for variable data pointer
|
|
// [pArrayAlloc] - Pointer to an allocator
|
|
//
|
|
// Returns: -Nothing-
|
|
//
|
|
// History: 22 Sep 1999 KLam Reinstated and added code
|
|
//
|
|
// Notes: This routine can be recursive when operating on variants
|
|
// which contain vectors of variants. As a side-effect, the
|
|
// signature which indicates an internal form of variant is
|
|
// cleared.
|
|
//
|
|
// This routine is only be used for communication between a 32
|
|
// bit server and 64 bit client. So the pointers found in the
|
|
// rows are always 32 bits. Note the casting.
|
|
// Arrays of of pointers are stored in the pArrayAlloc buffer.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CTableVariant::FixDataPointers(BYTE* pbBias, CFixedVarAllocator *pArrayAlloc)
|
|
{
|
|
PROPVARIANT32 *pThis32 = (PROPVARIANT32 *)this;
|
|
|
|
USHORT flags = _FindVarType( pThis32->vt ).flags;
|
|
BOOL fVectorOrArray = ( 0 != ( (VT_ARRAY|VT_VECTOR) & pThis32->vt ) );
|
|
USHORT vtBase = pThis32->vt & VT_TYPEMASK;
|
|
BOOL fSafeArray = ( (0 != ( VT_ARRAY & pThis32->vt )) || (VT_SAFEARRAY == vtBase) );
|
|
|
|
// If a simple type and not a vector, just return
|
|
|
|
tbDebugOut(( DEB_TRACE, "CTableVariant::FixDataPointers [this:0x%I64x] (Bias: 0x%I64x) pThis32->vt:0x%x\n",
|
|
this, pbBias, vt ));
|
|
|
|
if ( ( 0 != ( flags & SimpleType ) ) &&
|
|
( ! fVectorOrArray ) )
|
|
return;
|
|
|
|
Win4Assert( _IsInternalVariant() );
|
|
|
|
// Clear internal reserved fields
|
|
|
|
ResetDataSize();
|
|
|
|
BYTE* pbVarData;
|
|
|
|
if ( ( ! fVectorOrArray ) &&
|
|
( 0 != ( flags & ByRef ) ) )
|
|
{
|
|
pszVal = (LPSTR) ( pbBias + pThis32->p );
|
|
|
|
tbDebugOut(( DEB_TRACE, "CTableVariant::FixDataPointers setting string to 0x%I64x\n", pszVal ));
|
|
return;
|
|
}
|
|
else if ( fSafeArray )
|
|
{
|
|
pbVarData = pbVal = pbBias + pThis32->p;
|
|
tbDebugOut(( DEB_TRACE, "CTableVariant::FixDataPointers setting SafeArray to 0x%I64x\n", pszVal ));
|
|
}
|
|
else
|
|
{
|
|
Win4Assert( VariantPointerInSecondWord() );
|
|
blob.pBlobData = pbVarData = pbBias + pThis32->blob.pBlob;
|
|
blob.cbSize = pThis32->blob.cbSize;
|
|
tbDebugOut(( DEB_TRACE, "CTableVariant::FixDataPointers setting value to 0x%I64x\n", pbVarData ));
|
|
}
|
|
|
|
//
|
|
// Adjust offsets to pointers in vectors with pointers
|
|
//
|
|
if (vt == (VT_LPWSTR|VT_VECTOR) ||
|
|
vt == (VT_LPSTR|VT_VECTOR) ||
|
|
vt == (VT_BSTR|VT_VECTOR))
|
|
{
|
|
LPSTR * paNewArray = (LPSTR *)pArrayAlloc->Allocate( calpstr.cElems * (sizeof (void *)) );
|
|
ULONG * puStr = (ULONG *) pbVarData;
|
|
for (unsigned i = 0; i < calpstr.cElems; i++)
|
|
paNewArray[i] = (LPSTR) (puStr[i] + pbBias);
|
|
// Point to the new bigger array
|
|
blob.pBlobData = pbVarData = (BYTE *)paNewArray;
|
|
tbDebugOut(( DEB_TRACE, "CTableVariant::FixDataPointers setting vector to 0x%I64x\n", paNewArray ));
|
|
}
|
|
// VECTOR of VARIANTS aren't currently supported
|
|
// This branch is untested
|
|
else if (vt == (VT_VARIANT|VT_VECTOR))
|
|
{
|
|
CTableVariant* pVarnt = (CTableVariant*) pbVarData;
|
|
|
|
tbDebugOut(( DEB_TRACE, "CTableVariant::FixDataPointers recursively setting variant vector!\n" ));
|
|
for (unsigned i = 0; i < capropvar.cElems; i++)
|
|
{
|
|
pVarnt->FixDataPointers(pbBias, pArrayAlloc);
|
|
pVarnt++;
|
|
}
|
|
}
|
|
else if ( fSafeArray )
|
|
{
|
|
SAFEARRAY32 *pSafeArray32 = (SAFEARRAY32 *) pbVarData;
|
|
// Get the size of the safearray
|
|
unsigned cbSASize = sizeof (SAFEARRAY) + ( (pSafeArray32->cDims - 1 ) * sizeof (SAFEARRAYBOUND) );
|
|
|
|
// Allocate a new SAFEARRAY for WIN64
|
|
SAFEARRAY *pSafeArray = (SAFEARRAY *)pArrayAlloc->Allocate( cbSASize );
|
|
|
|
// Copy the SAFEARRAY
|
|
tbDebugOut(( DEB_TRACE,
|
|
"CTableVariant::FixDataPointers SafeArray32\n\tcDims:%d fFeatures:0x%x cbElements:%d cLocks:%d pvData:0x%I64x\n",
|
|
pSafeArray32->cDims, pSafeArray32->fFeatures, pSafeArray32->cbElements, pSafeArray32->cLocks, pSafeArray32->pvData ));
|
|
|
|
pSafeArray->cDims = pSafeArray32->cDims;
|
|
pSafeArray->fFeatures = pSafeArray32->fFeatures;
|
|
pSafeArray->cbElements = pSafeArray32->cbElements;
|
|
pSafeArray->cLocks = pSafeArray32->cLocks;
|
|
pSafeArray->pvData = pSafeArray32->pvData + pbBias;
|
|
memcpy ( pSafeArray->rgsabound, pSafeArray32->rgsabound, pSafeArray32->cDims * sizeof (SAFEARRAYBOUND) );
|
|
|
|
tbDebugOut(( DEB_TRACE,
|
|
"CTableVariant::FixDataPointers SafeArray\n\tcDims:%d fFeatures:0x%x cbElements:%d cLocks:%d pvData:0x%I64x\n",
|
|
pSafeArray->cDims, pSafeArray->fFeatures, pSafeArray->cbElements, pSafeArray->cLocks, pSafeArray->pvData ));
|
|
|
|
// Point the table variant at it
|
|
parray = pSafeArray;
|
|
|
|
tbDebugOut(( DEB_TRACE,
|
|
"CTableVariant::FixDataPointers setting safearray to 0x%I64x with array at 0x%I64x\n",
|
|
pSafeArray, pSafeArray->pvData ));
|
|
|
|
// Safearray of BSTR
|
|
if ( VT_BSTR == vtBase )
|
|
{
|
|
// Pointing to an array of pointers so adjust the size
|
|
pSafeArray->cbElements = sizeof (void *);
|
|
|
|
// Get the number of elements in the safe array
|
|
unsigned cBstrElements = pSafeArray->rgsabound[0].cElements;
|
|
for ( unsigned j = 1; j < pSafeArray->cDims; j++ )
|
|
cBstrElements *= pSafeArray->rgsabound[j].cElements;
|
|
|
|
unsigned cbBstrElements = cBstrElements * sizeof (void *);
|
|
ULONG_PTR *apStrings = (ULONG_PTR *) pArrayAlloc->Allocate ( cbBstrElements );
|
|
ULONG *pulBstr = (ULONG *) pSafeArray->pvData;
|
|
for ( j = 0; j < cBstrElements; j++ )
|
|
apStrings[j] = (ULONG_PTR) (pulBstr[j] + pbBias);
|
|
pSafeArray->pvData = apStrings;
|
|
|
|
tbDebugOut(( DEB_TRACE,
|
|
"CTableVariant::FixDataPointers setting safearray BSTRs to 0x%I64x\n",
|
|
apStrings ));
|
|
}
|
|
else if ( VT_VARIANT == vtBase )
|
|
{
|
|
// Pointing to an array of variants so adjust its size
|
|
pSafeArray->cbElements = sizeof ( PROPVARIANT );
|
|
|
|
// Get the number of elements in the safe array
|
|
unsigned cVarElements = pSafeArray->rgsabound[0].cElements;
|
|
for ( unsigned k = 1; k < pSafeArray->cDims; k++ )
|
|
cVarElements *= pSafeArray->rgsabound[k].cElements;
|
|
|
|
unsigned cbVarElements = cVarElements * sizeof (PROPVARIANT);
|
|
PROPVARIANT *apVar = (PROPVARIANT *) pArrayAlloc->Allocate ( cbVarElements );
|
|
PROPVARIANT32 *pVar32 = (PROPVARIANT32 *) pSafeArray->pvData;
|
|
CTableVariant *ptv;
|
|
for ( k = 0; k < cVarElements; k++ )
|
|
{
|
|
apVar[k].vt = pVar32[k].vt;
|
|
apVar[k].wReserved1 = _wInternalSig;
|
|
apVar[k].wReserved2 = pVar32[k].wReserved2;
|
|
apVar[k].wReserved3 = _wInternalSig;
|
|
|
|
apVar[k].blob.cbSize = pVar32[k].blob.cbSize;
|
|
ULONG ulBlob = pVar32[k].blob.pBlob;
|
|
apVar[k].blob.pBlobData = (BYTE *) UlongToPtr( ulBlob ) ;
|
|
ptv = (CTableVariant *)&apVar[k];
|
|
ptv->FixDataPointers ( pbBias, pArrayAlloc );
|
|
}
|
|
|
|
pSafeArray->pvData = apVar;
|
|
|
|
tbDebugOut(( DEB_TRACE,
|
|
"CTableVariant::FixDataPointers setting safearray BSTRs to 0x%I64x\n",
|
|
apVar ));
|
|
}
|
|
}
|
|
} //FixDataPointers
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::VarDataSize32, public
|
|
//
|
|
// Synopsis: Compute variable data size of a 64 bit variant for a Win32
|
|
// machine
|
|
//
|
|
// Arguments: [pbBase] - Buffer containing variant data
|
|
// [ulpOffset] - Offset of buffer on the client
|
|
//
|
|
// Returns: ULONG - size in bytes of data which is outside the
|
|
// variant structure itself
|
|
//
|
|
// Notes: For variants which are stored internally in the table,
|
|
// the size is computed once and stored in the wReserved2
|
|
// field of the variant structure.
|
|
//
|
|
// This function must be called **BEFORE** 32 pointer fixing
|
|
//
|
|
// History: 11-04-99 KLam Created for Win64
|
|
// 12-Feb-2000 KLam Vector string pointers not rebased
|
|
// BSTRs not multiplied by sizeof (OLECHAR)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
ULONG CTableVariant::VarDataSize32 ( BYTE *pbBase,
|
|
ULONG_PTR ulpOffset ) const
|
|
{
|
|
if ( VT_LPWSTR == vt )
|
|
{
|
|
LPWSTR lpwstrRef = (LPWSTR)( ((UINT_PTR)pwszVal - ulpOffset ) + pbBase );
|
|
return ( wcslen( lpwstrRef ) + 1 ) * sizeof (WCHAR);
|
|
}
|
|
|
|
if ( IsSimpleType( vt ) )
|
|
{
|
|
if ( 0 == ( ( VT_ARRAY | VT_VECTOR ) & vt ) )
|
|
{
|
|
return 0;
|
|
}
|
|
else if ( vt & VT_VECTOR )
|
|
{
|
|
USHORT cbSize, cbAllign, rgFlags;
|
|
|
|
VartypeInfo32( vt, cbSize, cbAllign, rgFlags );
|
|
|
|
return cbSize * cai.cElems;
|
|
}
|
|
}
|
|
|
|
Win4Assert( 0 == ( vt & VT_BYREF ) );
|
|
|
|
switch (vt)
|
|
{
|
|
case VT_LPSTR:
|
|
{
|
|
LPSTR lpstrRef = (LPSTR)( ((UINT_PTR)pszVal - ulpOffset ) + pbBase );
|
|
return strlen(lpstrRef) + 1;
|
|
}
|
|
|
|
case VT_BLOB:
|
|
return blob.cbSize;
|
|
|
|
case VT_BSTR:
|
|
{
|
|
BSTR bstrRef = (BSTR)( ((UINT_PTR)bstrVal - ulpOffset ) + pbBase );
|
|
tbDebugOut(( DEB_TRACE,
|
|
"VarDataSize32 sizing BSTR at bstrRef: 0x%I64x with size %d\n",
|
|
bstrRef, BSTRLEN(bstrRef) ));
|
|
|
|
Win4Assert(bstrRef[ BSTRLEN(bstrRef) / sizeof (OLECHAR) ] == OLESTR('\0'));
|
|
return ( BSTRLEN(bstrRef) * sizeof (OLECHAR) )
|
|
+ sizeof (DWORD) + sizeof (OLECHAR);
|
|
}
|
|
|
|
case VT_BSTR | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof (PTR32) * cabstr.cElems;
|
|
BSTR * abstrRef = (BSTR *)( ((UINT_PTR)cabstr.pElems - ulpOffset ) + pbBase );
|
|
tbDebugOut(( DEB_TRACE,
|
|
"VarDataSize32 sizing %d BSTR(s) vector at abstrRef: 0x%I64x \n",
|
|
cabstr.cElems, abstrRef ));
|
|
for (unsigned i=0; i < cabstr.cElems; i++)
|
|
{
|
|
BSTR bstrFixed = (BSTR)((((UINT_PTR)(abstrRef[i])) - ulpOffset ) + pbBase);
|
|
cbTotal += ( BSTRLEN( bstrFixed ) * sizeof (OLECHAR) ) +
|
|
sizeof (DWORD) + sizeof (OLECHAR);
|
|
}
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_LPSTR | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof (PTR32) * calpstr.cElems;
|
|
LPSTR * alpstrRef = (LPSTR *)( ((UINT_PTR)calpstr.pElems - ulpOffset ) + pbBase );
|
|
for (unsigned i=0; i < calpstr.cElems; i++)
|
|
{
|
|
LPSTR lpstrFixed = (LPSTR)(( ((UINT_PTR)(alpstrRef[i])) - ulpOffset ) + pbBase);
|
|
cbTotal += strlen( lpstrFixed ) + 1;
|
|
}
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_LPWSTR | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof(PTR32) * calpwstr.cElems;
|
|
LPWSTR * alpwstr = (LPWSTR *)( ((UINT_PTR)calpwstr.pElems - ulpOffset ) + pbBase );
|
|
for (unsigned i=0; i < calpwstr.cElems; i++)
|
|
{
|
|
LPWSTR lpwstrFixed = (LPWSTR)(( ((UINT_PTR)(alpwstr[i])) - ulpOffset ) + pbBase);
|
|
cbTotal += (wcslen( lpwstrFixed ) + 1) * sizeof (WCHAR);
|
|
}
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_VARIANT | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof PROPVARIANT32 * capropvar.cElems;
|
|
CTableVariant * atv = (CTableVariant *)( ((UINT_PTR)capropvar.pElems - ulpOffset ) + pbBase );
|
|
for (unsigned i=0; i < capropvar.cElems; i++)
|
|
cbTotal += atv[i].VarDataSize();
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_CLSID :
|
|
{
|
|
return sizeof CLSID;
|
|
}
|
|
|
|
case VT_CLSID | VT_VECTOR :
|
|
{
|
|
return sizeof CLSID * cai.cElems;
|
|
}
|
|
|
|
case VT_CF :
|
|
{
|
|
if ( 0 != pclipdata )
|
|
{
|
|
CLIPDATA * pclipRef = (CLIPDATA *)( ((UINT_PTR)pclipdata - ulpOffset ) + pbBase );
|
|
return sizeof CLIPDATA32 + CBPCLIPDATA( *pclipRef );
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
case VT_CF | VT_VECTOR :
|
|
{
|
|
ULONG cb = sizeof CLIPDATA32 * caclipdata.cElems;
|
|
CLIPDATA * aclipRef = (CLIPDATA *)( ((UINT_PTR)(caclipdata.pElems) - ulpOffset ) + pbBase );
|
|
for ( ULONG i = 0; i < caclipdata.cElems; i++ )
|
|
cb += CBPCLIPDATA( aclipRef[i] );
|
|
return cb;
|
|
}
|
|
|
|
case VT_ARRAY | VT_I4:
|
|
case VT_ARRAY | VT_UI1:
|
|
case VT_ARRAY | VT_I2:
|
|
case VT_ARRAY | VT_R4:
|
|
case VT_ARRAY | VT_R8:
|
|
case VT_ARRAY | VT_BOOL:
|
|
case VT_ARRAY | VT_ERROR:
|
|
case VT_ARRAY | VT_CY:
|
|
case VT_ARRAY | VT_DATE:
|
|
case VT_ARRAY | VT_I1:
|
|
case VT_ARRAY | VT_UI2:
|
|
case VT_ARRAY | VT_UI4:
|
|
case VT_ARRAY | VT_INT:
|
|
case VT_ARRAY | VT_UINT:
|
|
case VT_ARRAY | VT_DECIMAL:
|
|
case VT_ARRAY | VT_BSTR:
|
|
case VT_ARRAY | VT_VARIANT:
|
|
{
|
|
LPSAFEARRAY psaRef = (LPSAFEARRAY)( ((UINT_PTR)parray - ulpOffset ) + pbBase );
|
|
return SaComputeSize32( vt & ~VT_ARRAY, *psaRef, pbBase, ulpOffset );
|
|
}
|
|
|
|
case VT_EMPTY :
|
|
return 0;
|
|
|
|
default:
|
|
tbDebugOut(( DEB_WARN, "Unsupported variant type %4x\n", (int) vt ));
|
|
Win4Assert(! "Unsupported variant type in CTableVariant::VarDataSize");
|
|
return 0;
|
|
}
|
|
} // VarDataSize32
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CTableVariant::SaComputeSize32, public static
|
|
//
|
|
// Synopsis: Computes the size of a safearray for a 32 bit machine.
|
|
//
|
|
// Arguments: [vt] - variant type (VT_ARRAY assumed)
|
|
// [saSrc] - 64 bit source safearry
|
|
// [pbBase] - Buffer containing variant data
|
|
// [ulpOffset] - Offset of buffer on the client
|
|
//
|
|
// Returns: ULONG - number of bytes of memory needed to store safearray
|
|
//
|
|
// History: 5-01-98 AlanW Created
|
|
// 11-4-99 KLam Adjusted for 32bit array on 64bit machine
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
ULONG CTableVariant::SaComputeSize32( VARTYPE vt,
|
|
SAFEARRAY & saSrc,
|
|
BYTE *pbBase,
|
|
ULONG_PTR ulpOffset )
|
|
{
|
|
//
|
|
// get number of data elements in array and size of the header.
|
|
//
|
|
unsigned cDataElements = 1;
|
|
for ( unsigned i = 0; i < saSrc.cDims; i++ )
|
|
// This array is in place so no pointer fixing is necessary
|
|
cDataElements *= saSrc.rgsabound[i].cElements;
|
|
|
|
Win4Assert( 0 != saSrc.cDims );
|
|
|
|
ULONG cb = sizeof (SAFEARRAY32) +
|
|
(saSrc.cDims-1) * sizeof (SAFEARRAYBOUND) +
|
|
cDataElements * saSrc.cbElements;
|
|
|
|
cb = AlignBlock( cb, sizeof LONGLONG );
|
|
|
|
switch (vt)
|
|
{
|
|
case VT_I4:
|
|
case VT_UI1:
|
|
case VT_I2:
|
|
case VT_R4:
|
|
case VT_R8:
|
|
case VT_BOOL:
|
|
case VT_ERROR:
|
|
case VT_CY:
|
|
case VT_DATE:
|
|
case VT_I1:
|
|
case VT_UI2:
|
|
case VT_UI4:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
case VT_DECIMAL:
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
{
|
|
BSTR *pBstrSrc = (BSTR *)( ( ((UINT_PTR)saSrc.pvData) - ulpOffset ) + pbBase );
|
|
|
|
for ( unsigned i = 0; i < cDataElements; i++ )
|
|
{
|
|
Win4Assert( pBstrSrc[i] != 0 );
|
|
|
|
BSTR bstrRef = (BSTR) ( ( ( (UINT_PTR) (pBstrSrc[i]) ) - ulpOffset ) + pbBase );
|
|
tbDebugOut(( DEB_TRACE,
|
|
"Sizing Array of BSTR: 0x%I64x BSTR[%d]: %xI64x (size: %d)\n",
|
|
pBstrSrc, bstrRef, BSTRLEN(bstrRef) ));
|
|
cb += AlignBlock( SysStringByteLen(bstrRef) +
|
|
sizeof ULONG + sizeof WCHAR,
|
|
sizeof LONGLONG );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_VARIANT:
|
|
{
|
|
CAllocStorageVariant *pVarnt = (CAllocStorageVariant *)( ((UINT_PTR)saSrc.pvData - ulpOffset ) + pbBase );
|
|
|
|
for ( unsigned i = 0; i < cDataElements; i++ )
|
|
{
|
|
if ( VT_BSTR == pVarnt[i].vt )
|
|
{
|
|
BSTR bstrRef = (BSTR)( ((UINT_PTR)pVarnt[i].bstrVal - ulpOffset ) + pbBase );
|
|
cb += AlignBlock( SysStringByteLen( bstrRef ) +
|
|
sizeof ULONG + sizeof WCHAR,
|
|
sizeof LONGLONG );
|
|
}
|
|
else if ( 0 != (pVarnt[i].vt & VT_ARRAY) )
|
|
{
|
|
LPSAFEARRAY psaRef = (LPSAFEARRAY)( ((UINT_PTR)pVarnt[i].parray - ulpOffset ) + pbBase );
|
|
cb += AlignBlock( SaComputeSize32( (pVarnt[i].vt & ~VT_ARRAY),
|
|
*psaRef,
|
|
pbBase,
|
|
ulpOffset ),
|
|
sizeof LONGLONG );
|
|
}
|
|
else
|
|
{
|
|
Win4Assert( pVarnt[i].vt != VT_VARIANT );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ciDebugOut(( DEB_ERROR, "Unexpected SafeArray type: vt=%x\n", vt ) );
|
|
Win4Assert( !"Unexpected SafeArray Type" );
|
|
return 1;
|
|
}
|
|
|
|
return cb;
|
|
} // SaComputeSize32
|
|
|
|
|
|
#endif // _WIN64
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::VarDataSize, public
|
|
//
|
|
// Synopsis: Compute variable data size for a variant
|
|
//
|
|
// Arguments: - none -
|
|
//
|
|
// Returns: ULONG - size in bytes of data which is outside the
|
|
// variant structure itself
|
|
//
|
|
// Notes: For variants which are stored internally in the table,
|
|
// the size is computed once and stored in the wReserved2
|
|
// field of the variant structure.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
ULONG CTableVariant::VarDataSize (void) const
|
|
{
|
|
// short-circuit this common path: VT_LPWSTR
|
|
|
|
if ( VT_LPWSTR == vt )
|
|
return ( wcslen( pwszVal ) + 1 ) * sizeof (WCHAR);
|
|
|
|
if ( IsSimpleType( vt ) )
|
|
{
|
|
if ( 0 == ( ( VT_ARRAY | VT_VECTOR ) & vt ) )
|
|
{
|
|
return 0;
|
|
}
|
|
else if ( vt & VT_VECTOR )
|
|
{
|
|
USHORT cbSize, cbAllign, rgFlags;
|
|
|
|
VartypeInfo( vt, cbSize, cbAllign, rgFlags );
|
|
|
|
return cbSize * cai.cElems;
|
|
}
|
|
}
|
|
|
|
Win4Assert( 0 == ( vt & VT_BYREF ) );
|
|
|
|
switch (vt)
|
|
{
|
|
case VT_LPSTR:
|
|
return strlen(pszVal) + 1;
|
|
|
|
case VT_BLOB:
|
|
return blob.cbSize;
|
|
|
|
case VT_BSTR:
|
|
Win4Assert(bstrVal[ BSTRLEN(bstrVal) / sizeof (OLECHAR) ] == OLESTR('\0'));
|
|
return BSTRLEN(bstrVal) + sizeof (DWORD) + sizeof (OLECHAR);
|
|
|
|
case VT_BSTR | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof (void *) * cabstr.cElems;
|
|
for (unsigned i=0; i<cabstr.cElems; i++)
|
|
cbTotal += BSTRLEN(cabstr.pElems[i]) +
|
|
sizeof (DWORD) + sizeof (OLECHAR);
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_LPSTR | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof (void *) * calpstr.cElems;
|
|
for (unsigned i=0; i<calpstr.cElems; i++)
|
|
cbTotal += strlen(calpstr.pElems[i]) + 1;
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_LPWSTR | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof( void * ) * calpwstr.cElems;
|
|
for (unsigned i=0; i<calpwstr.cElems; i++)
|
|
cbTotal += (wcslen(calpwstr.pElems[i]) + 1) * sizeof (WCHAR);
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_VARIANT | VT_VECTOR:
|
|
{
|
|
ULONG cbTotal = sizeof PROPVARIANT * capropvar.cElems;
|
|
for (unsigned i=0; i<capropvar.cElems; i++)
|
|
cbTotal += ((CTableVariant &)capropvar.pElems[i]).VarDataSize();
|
|
return cbTotal;
|
|
}
|
|
|
|
case VT_CLSID :
|
|
{
|
|
return sizeof CLSID;
|
|
}
|
|
|
|
case VT_CLSID | VT_VECTOR :
|
|
{
|
|
return sizeof CLSID * cai.cElems;
|
|
}
|
|
|
|
case VT_CF :
|
|
{
|
|
if ( 0 != pclipdata )
|
|
return sizeof CLIPDATA + CBPCLIPDATA( *pclipdata );
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
case VT_CF | VT_VECTOR :
|
|
{
|
|
ULONG cb = sizeof CLIPDATA * caclipdata.cElems;
|
|
for ( ULONG i = 0; i < caclipdata.cElems; i++ )
|
|
cb += CBPCLIPDATA( caclipdata.pElems[i] );
|
|
return cb;
|
|
}
|
|
|
|
case VT_ARRAY | VT_I4:
|
|
case VT_ARRAY | VT_UI1:
|
|
case VT_ARRAY | VT_I2:
|
|
case VT_ARRAY | VT_R4:
|
|
case VT_ARRAY | VT_R8:
|
|
case VT_ARRAY | VT_BOOL:
|
|
case VT_ARRAY | VT_ERROR:
|
|
case VT_ARRAY | VT_CY:
|
|
case VT_ARRAY | VT_DATE:
|
|
case VT_ARRAY | VT_I1:
|
|
case VT_ARRAY | VT_UI2:
|
|
case VT_ARRAY | VT_UI4:
|
|
case VT_ARRAY | VT_INT:
|
|
case VT_ARRAY | VT_UINT:
|
|
case VT_ARRAY | VT_DECIMAL:
|
|
case VT_ARRAY | VT_BSTR:
|
|
case VT_ARRAY | VT_VARIANT:
|
|
return SaComputeSize( vt & ~VT_ARRAY, *parray);
|
|
|
|
case VT_EMPTY :
|
|
return 0;
|
|
|
|
default:
|
|
tbDebugOut(( DEB_WARN, "Unsupported variant type %4x\n", (int) vt ));
|
|
Win4Assert(! "Unsupported variant type in CTableVariant::VarDataSize");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
const USHORT CTableVariant::_wInternalSig = 0x3210;
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CTableVariant::Init, public
|
|
//
|
|
// Synopsis: Fills in a variant with new data
|
|
//
|
|
// Arguments: [vtIn] -- the data type of the new variant
|
|
// [pbData] -- pointer to source of data
|
|
// [cbData] -- size in bytes of data at pbData
|
|
//
|
|
// Returns: -Nothing-
|
|
//
|
|
// Notes: The variant is reused. The caller is responsible
|
|
// for freeing any memory from the previous contents
|
|
// of the variant prior to calling Init.
|
|
//
|
|
// If pbData is NULL and cbData is zero, only the
|
|
// variant type is filled in.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CTableVariant::Init(
|
|
VARTYPE vtIn,
|
|
BYTE* pbData,
|
|
ULONG cbData)
|
|
{
|
|
// Clean out the entire variant
|
|
RtlZeroMemory(this, sizeof CTableVariant);
|
|
|
|
vt = vtIn; // default; minor exceptions below
|
|
|
|
if (pbData == 0 && cbData == 0)
|
|
return;
|
|
|
|
if ( VT_VARIANT == vtIn )
|
|
{
|
|
tbDebugOut(( DEB_ITRACE, "CTableVariant::Init from vt_variant\n" ));
|
|
* this = * ((CTableVariant *) pbData);
|
|
}
|
|
else if (vtIn & VT_VECTOR)
|
|
{
|
|
Win4Assert( cbData == sizeof (CAI) );
|
|
RtlCopyMemory((BYTE *)&cai, pbData, sizeof (CAI));
|
|
}
|
|
else if ( IsSimpleType( vtIn ) )
|
|
{
|
|
RtlCopyMemory( (BYTE *)&iVal, pbData, cbData );
|
|
}
|
|
else
|
|
{
|
|
switch (vtIn)
|
|
{
|
|
case VT_CLSID:
|
|
Win4Assert(cbData == sizeof (GUID));
|
|
puuid = (GUID *)pbData;
|
|
break;
|
|
case VT_BSTR:
|
|
case VT_LPSTR:
|
|
case VT_LPWSTR:
|
|
Win4Assert(cbData == sizeof (LPSTR));
|
|
pszVal = *(LPSTR *)pbData;
|
|
break;
|
|
case VT_BLOB:
|
|
Win4Assert(cbData == sizeof (BLOB));
|
|
blob = *(BLOB *)pbData;
|
|
break;
|
|
default:
|
|
tbDebugOut(( DEB_WARN, "Unsupported variant type %4x\n", (int) vtIn ));
|
|
Win4Assert(! "unsupported variant type in CTableVariant::Init");
|
|
}
|
|
}
|
|
} //Init
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::_StoreString, private
|
|
//
|
|
// Synopsis: Copy variant string data, coerce if possible
|
|
//
|
|
// Arguments: [pbDstBuf] -- destination buffer
|
|
// [cbDstBuf] -- size of destination buffer
|
|
// [vtDst] -- data type of the dest
|
|
// [rcbDstLen] -- on return, length of destination data
|
|
// [rPool] -- to use for destination byref allocations
|
|
//
|
|
// Returns: status for copy
|
|
|
|
// Notes: Expects the 'this' data type to be either VT_LPSTR,
|
|
// VT_LPWSTR or VT_BSTR.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DBSTATUS CTableVariant::_StoreString( BYTE * pbDstBuf,
|
|
DBLENGTH cbDstBuf,
|
|
VARTYPE vtDst,
|
|
DBLENGTH & rcbDstLen,
|
|
PVarAllocator & rPool) const
|
|
{
|
|
DBSTATUS DstStatus = DBSTATUS_S_OK;
|
|
ULONG cbSrc = (vt == VT_BSTR) ? BSTRLEN(bstrVal) + sizeof (OLECHAR) :
|
|
VarDataSize();
|
|
|
|
// if both are VT_LPWSTR or
|
|
// both are VT_LPSTR or
|
|
// dst is byref wstr and source is VT_LPWSTR or
|
|
// dst is byref str and source is VT_LPSTR
|
|
|
|
if ( ( (vtDst == vt) &&
|
|
(IsLPWSTR(vtDst))) ||
|
|
( (vtDst == vt) &&
|
|
(IsLPSTR(vtDst)) ) ||
|
|
( (vtDst == (DBTYPE_BYREF | DBTYPE_WSTR) ) &&
|
|
(IsLPWSTR(vt) || vt == VT_BSTR) ) ||
|
|
( (vtDst == (DBTYPE_BYREF | DBTYPE_STR) ) &&
|
|
(IsLPSTR(vt)) ) )
|
|
{
|
|
Win4Assert ((vtDst & VT_VECTOR) == 0 &&
|
|
cbDstBuf == sizeof LPWSTR);
|
|
|
|
BYTE* pbDest = (BYTE *) rPool.CopyTo(cbSrc,(BYTE *) pszVal);
|
|
|
|
// ADO gives us 1 byte aligned buffers sometimes. Sigh.
|
|
// Happens for vt_lpwstr => dbtype_byref|dbtype_wstr
|
|
|
|
// Win4Assert( 0 == ( (ULONG_PTR) pbDstBuf % sizeof(ULONG_PTR) ) );
|
|
|
|
*(ULONG_PTR UNALIGNED *) pbDstBuf = rPool.PointerToOffset(pbDest);
|
|
rcbDstLen = (vtDst == VT_BSTR) ? sizeof (BSTR) :
|
|
(vtDst == VT_LPWSTR || vtDst == (DBTYPE_BYREF|DBTYPE_WSTR)) ?
|
|
cbSrc - sizeof (WCHAR) : cbSrc - sizeof (char);
|
|
}
|
|
else if (((vtDst == DBTYPE_WSTR) &&
|
|
(IsLPWSTR(vt) || vt == VT_BSTR)) ||
|
|
((vtDst == DBTYPE_STR) &&
|
|
(IsLPSTR(vt))))
|
|
{
|
|
// In-line, compatible data types
|
|
if (cbDstBuf >= cbSrc)
|
|
{
|
|
RtlCopyMemory(pbDstBuf, pszVal, cbSrc);
|
|
rcbDstLen = cbSrc - ((vtDst == DBTYPE_WSTR) ?
|
|
sizeof (WCHAR) : sizeof (char));
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(pbDstBuf, pszVal, cbDstBuf);
|
|
DstStatus = DBSTATUS_S_TRUNCATED;
|
|
rcbDstLen = cbDstBuf;
|
|
}
|
|
}
|
|
else if ((vtDst == DBTYPE_STR) && (IsLPWSTR(vt) || vt == VT_BSTR))
|
|
{
|
|
// if they want fancy composed chars, they can bind to the
|
|
// proper data type and do the coercion themselves.
|
|
|
|
int cb = WideCharToMultiByte(ulCoercionCodePage,0,pwszVal,-1,
|
|
0,0,0,0);
|
|
if (0 == cb)
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE; // something odd...
|
|
else
|
|
{
|
|
if (cb > (int) cbDstBuf)
|
|
{
|
|
DstStatus = DBSTATUS_S_TRUNCATED;
|
|
rcbDstLen = cbDstBuf;
|
|
}
|
|
else
|
|
rcbDstLen = cb - sizeof (char);
|
|
|
|
WideCharToMultiByte(ulCoercionCodePage,0,pwszVal,-1,
|
|
(char *) pbDstBuf,(ULONG) cbDstBuf,0,0);
|
|
}
|
|
}
|
|
else if ((vtDst == DBTYPE_WSTR) && (IsLPSTR(vt)))
|
|
{
|
|
// if they want fancy composed chars, they can bind to the
|
|
// proper data type and do the coercion themselves.
|
|
|
|
int cwcDst = (int) ( cbDstBuf / sizeof WCHAR );
|
|
|
|
int cwc = MultiByteToWideChar(ulCoercionCodePage,0,
|
|
pszVal,-1,0,0);
|
|
if (0 == cwc)
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE; // something odd...
|
|
else
|
|
{
|
|
if (cwc > cwcDst)
|
|
{
|
|
DstStatus = DBSTATUS_S_TRUNCATED;
|
|
rcbDstLen = (cwcDst) * sizeof (WCHAR);
|
|
}
|
|
else
|
|
rcbDstLen = (cwc-1) * sizeof (WCHAR);
|
|
|
|
MultiByteToWideChar(ulCoercionCodePage,0,
|
|
pszVal,-1,(WCHAR *) pbDstBuf,cwcDst);
|
|
}
|
|
}
|
|
else if (vtDst == VT_BSTR)
|
|
{
|
|
Win4Assert(vt != VT_BSTR && vt != DBTYPE_STR && vt != DBTYPE_WSTR);
|
|
rcbDstLen = sizeof (BSTR);
|
|
|
|
if (IsLPWSTR(vt))
|
|
{
|
|
BSTR bstrDest = (BSTR) rPool.CopyBSTR( cbSrc - sizeof (OLECHAR),
|
|
pwszVal );
|
|
*(ULONG_PTR*) pbDstBuf = rPool.PointerToOffset(bstrDest);
|
|
}
|
|
else
|
|
{
|
|
Win4Assert(IsLPSTR(vt));
|
|
int cwc = MultiByteToWideChar(ulCoercionCodePage,0,
|
|
pszVal,-1,0,0);
|
|
if (0 == cwc)
|
|
{
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE; // something odd...
|
|
*(BSTR*) pbDstBuf = 0;
|
|
rcbDstLen = 0;
|
|
}
|
|
else
|
|
{
|
|
XArray<WCHAR> wcsDest( cwc );
|
|
|
|
MultiByteToWideChar(ulCoercionCodePage, 0,
|
|
pszVal, -1, wcsDest.Get(), cwc);
|
|
|
|
BSTR bstrDest = (BSTR) rPool.CopyBSTR((cwc-1)*sizeof (OLECHAR),
|
|
wcsDest.Get());
|
|
*(ULONG_PTR*) pbDstBuf = rPool.PointerToOffset(bstrDest);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
rcbDstLen = 0;
|
|
}
|
|
|
|
return DstStatus;
|
|
} //_StoreString
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::CopyOrCoerce, public
|
|
//
|
|
// Synopsis: Copy table data between a variant structure and
|
|
// a fixed width field. This is used both for copying
|
|
// data into a window, and out to an output destination.
|
|
//
|
|
// Arguments: [pbDstBuf] -- pointer to area to be filled in
|
|
// [cbDstBuf] -- size in bytes of storage area
|
|
// [vtDst] -- VARTYPE of the destination
|
|
// [rcbDstLen] -- on return, length of destination data
|
|
// [rPool] -- pool to use for destination buffers
|
|
//
|
|
// Returns: status for copy
|
|
//
|
|
// Notes: This function(and class) now deals only with PROPVARIANTs.
|
|
// If conversion is needed for OLE-DB/Automation types, use the
|
|
// COLEDBVariant class.
|
|
// The [rcbDstLen] is computed according to OLE-DB's (somewhat
|
|
// arbitrary) rules.
|
|
//
|
|
// History: 09 Jan 1998 VikasMan Modified the function to deal ONLY
|
|
// with PROPVARIANTs
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DBSTATUS CTableVariant::CopyOrCoerce(
|
|
BYTE * pbDstBuf,
|
|
DBLENGTH cbDstBuf,
|
|
VARTYPE vtDst,
|
|
DBLENGTH & rcbDstLen,
|
|
PVarAllocator & rPool) const
|
|
{
|
|
DBSTATUS DstStatus = DBSTATUS_S_OK;
|
|
|
|
Win4Assert( (vt & VT_BYREF) == 0 );
|
|
|
|
if ( ( vtDst == vt ) && IsSimpleType( vt ) && ! IsVectorOrArray( vt ) )
|
|
{
|
|
if (vt == VT_DECIMAL)
|
|
{
|
|
Win4Assert( cbDstBuf == sizeof (DECIMAL) );
|
|
RtlCopyMemory(pbDstBuf, this, cbDstBuf);
|
|
}
|
|
else
|
|
{
|
|
Win4Assert( cbDstBuf &&
|
|
cbDstBuf <= sizeof (LONGLONG) );
|
|
RtlCopyMemory(pbDstBuf, &iVal, cbDstBuf);
|
|
}
|
|
rcbDstLen = cbDstBuf;
|
|
}
|
|
else if ( VT_VARIANT == vtDst )
|
|
{
|
|
Win4Assert(cbDstBuf == sizeof PROPVARIANT);
|
|
|
|
Copy( (CTableVariant*) pbDstBuf, rPool, (USHORT) VarDataSize() );
|
|
|
|
if ( VT_EMPTY == vt )
|
|
DstStatus = DBSTATUS_S_ISNULL;
|
|
rcbDstLen = sizeof (PROPVARIANT);
|
|
}
|
|
else if ( VT_EMPTY == vt )
|
|
{
|
|
RtlZeroMemory( pbDstBuf, cbDstBuf );
|
|
DstStatus = DBSTATUS_S_ISNULL;
|
|
rcbDstLen = 0;
|
|
}
|
|
else if ( ( IsLPWSTR( vtDst ) ) || ( IsLPSTR( vtDst ) ) )
|
|
{
|
|
if ( VT_LPSTR == vt || VT_LPWSTR == vt || VT_BSTR == vt )
|
|
{
|
|
DstStatus = _StoreString( pbDstBuf,
|
|
cbDstBuf,
|
|
vtDst,
|
|
rcbDstLen,
|
|
rPool );
|
|
}
|
|
else
|
|
{
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
rcbDstLen = 0;
|
|
}
|
|
}
|
|
else if ( vtDst == vt )
|
|
{
|
|
if ( VT_CLSID == vtDst )
|
|
{
|
|
// UUID is the one case of a fixed size indirect
|
|
// reference in DBVARIANT.
|
|
|
|
Win4Assert(cbDstBuf == sizeof GUID );
|
|
RtlCopyMemory(pbDstBuf,puuid,sizeof GUID);
|
|
rcbDstLen = sizeof (GUID);
|
|
}
|
|
else
|
|
{
|
|
// Must be a vector or a blob or a bstr
|
|
|
|
unsigned cbSrcVar = VarDataSize();
|
|
|
|
Win4Assert(vtDst == VT_BSTR ||
|
|
((vtDst & VT_VECTOR) != 0 &&
|
|
vtDst != (VT_VARIANT|VT_VECTOR) &&
|
|
vtDst != (VT_LPWSTR|VT_VECTOR) &&
|
|
vtDst != (VT_LPSTR|VT_VECTOR)));
|
|
|
|
BYTE* pTmpBuf = (BYTE *) CopyData(rPool,(USHORT) cbSrcVar);
|
|
|
|
if (VariantPointerInFirstWord()) // BSTR case
|
|
{
|
|
Win4Assert(cbDstBuf == sizeof (BYTE *));
|
|
|
|
*(ULONG_PTR *) pbDstBuf = rPool.PointerToOffset(pTmpBuf);
|
|
rcbDstLen = sizeof (BSTR);
|
|
}
|
|
else
|
|
{
|
|
Win4Assert(VariantPointerInSecondWord() &&
|
|
(cbDstBuf == sizeof (BLOB) ||
|
|
cbDstBuf == sizeof (DBVECTOR)));
|
|
if (vtDst == VT_BLOB)
|
|
{
|
|
((BLOB *) pbDstBuf)->pBlobData = (BYTE *) rPool.PointerToOffset(pTmpBuf);
|
|
((BLOB *) pbDstBuf)->cbSize = blob.cbSize;
|
|
rcbDstLen = sizeof (BLOB);
|
|
}
|
|
else
|
|
{
|
|
((DBVECTOR *) pbDstBuf)->ptr = (BYTE *) rPool.PointerToOffset(pTmpBuf);
|
|
((DBVECTOR *) pbDstBuf)->size =cai.cElems;
|
|
rcbDstLen = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Coercion required. Only a very limited set of coercions
|
|
// are done. These are between various types of integers,
|
|
// and between two types of strings (both direct and by reference).
|
|
|
|
switch (vtDst)
|
|
{
|
|
case VT_LPWSTR:
|
|
case VT_LPSTR:
|
|
case VT_BSTR:
|
|
|
|
case (DBTYPE_STR | DBTYPE_BYREF):
|
|
case (DBTYPE_WSTR | DBTYPE_BYREF):
|
|
case DBTYPE_STR:
|
|
case DBTYPE_WSTR:
|
|
// case DBTYPE_BYTES:
|
|
if ( VT_LPSTR == vt || VT_LPWSTR == vt || VT_BSTR == vt )
|
|
{
|
|
DstStatus = _StoreString(pbDstBuf,
|
|
cbDstBuf,
|
|
vtDst,
|
|
rcbDstLen,
|
|
rPool);
|
|
}
|
|
else
|
|
{
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
}
|
|
break;
|
|
|
|
case VT_R4:
|
|
if (VT_R8 == vt)
|
|
{
|
|
if (dblVal > FLT_MAX ||
|
|
dblVal < FLT_MIN)
|
|
DstStatus = DBSTATUS_S_TRUNCATED;
|
|
|
|
* (float *) pbDstBuf = (float) dblVal;
|
|
rcbDstLen = sizeof (float);
|
|
}
|
|
else
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
|
|
case VT_R8:
|
|
// since DATE is stored as a double, someone may want
|
|
// this odd coercion.
|
|
|
|
if (VT_R4 == vt)
|
|
* (double *) pbDstBuf = (double) fltVal;
|
|
if (VT_DATE == vt)
|
|
* (double *) pbDstBuf = (double) date;
|
|
else
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
|
|
rcbDstLen = sizeof (double);
|
|
break;
|
|
|
|
case VT_HRESULT:
|
|
case VT_ERROR:
|
|
// allow coercions from some 4-byte quantities
|
|
|
|
if (VT_ERROR == vt || VT_HRESULT == vt ||
|
|
VT_I4 == vt || VT_UI4 == vt)
|
|
* (ULONG *) pbDstBuf = lVal;
|
|
else
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
|
|
rcbDstLen = sizeof (SCODE);
|
|
break;
|
|
|
|
case VT_CY:
|
|
// allow coercions from I8 and UI8
|
|
|
|
if (VT_I8 == vt || VT_UI8 == vt)
|
|
* (LONGLONG *) pbDstBuf = hVal.QuadPart;
|
|
else
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
|
|
rcbDstLen = sizeof (LONGLONG);
|
|
break;
|
|
|
|
case VT_I1:
|
|
case VT_UI1:
|
|
case VT_I2:
|
|
case VT_UI2:
|
|
case VT_I4:
|
|
case VT_UI4:
|
|
case VT_BOOL:
|
|
case VT_I8:
|
|
case VT_UI8:
|
|
if ( vt == VT_I1 ||
|
|
vt == VT_UI1 ||
|
|
vt == VT_I2 ||
|
|
vt == VT_UI2 ||
|
|
vt == VT_I4 ||
|
|
vt == VT_UI4 ||
|
|
vt == VT_I8 ||
|
|
vt == VT_UI8 ||
|
|
vt == VT_BOOL ||
|
|
vt == VT_ERROR ||
|
|
vt == VT_HRESULT ||
|
|
vt == VT_FILETIME ||
|
|
vt == VT_EMPTY ) // empty if object is deleted
|
|
{
|
|
DstStatus = _StoreInteger( vtDst, pbDstBuf );
|
|
|
|
if (DstStatus != DBSTATUS_E_CANTCONVERTVALUE)
|
|
rcbDstLen = cbDstBuf;
|
|
#if DBG
|
|
USHORT cbSize, cbAllign, rgFlags;
|
|
VartypeInfo( vtDst, cbSize, cbAllign, rgFlags );
|
|
// this fires for all conversions to VT_BOOL
|
|
// Win4Assert( rcbDstLen == cbSize );
|
|
Win4Assert( DstStatus != DBSTATUS_S_TRUNCATED );
|
|
#endif // DBG
|
|
}
|
|
else
|
|
{
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
}
|
|
break;
|
|
|
|
case VT_CLSID:
|
|
// VT_CLSID is given with VT_BYREF in the row buffer
|
|
|
|
if (vt == (VT_CLSID | VT_BYREF))
|
|
RtlCopyMemory(pbDstBuf,puuid,sizeof (GUID *));
|
|
else
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
break;
|
|
|
|
case VT_DATE:
|
|
case VT_FILETIME:
|
|
case DBTYPE_DBDATE:
|
|
case DBTYPE_DBTIME:
|
|
case DBTYPE_DBTIMESTAMP:
|
|
// CTableVariant class does not handle date conversions any longer.
|
|
// These get handled by its derived class - COLEDBVariant now
|
|
tbDebugOut(( DEB_IWARN,
|
|
"CTableVariant does not handle date conversions.\n" ));
|
|
//Win4Assert( !"Invalid switch case in CopyOrCoerce!" );
|
|
|
|
// FALL through
|
|
default:
|
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
|
tbDebugOut(( DEB_ITRACE,
|
|
"Unexpected dest storage type %4x\n"
|
|
"\tsource storage type %4x\n",
|
|
vtDst, vt));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (DstStatus == DBSTATUS_E_CANTCONVERTVALUE)
|
|
rcbDstLen = 0;
|
|
|
|
Win4Assert( rcbDstLen < 0x01000000 );
|
|
return DstStatus;
|
|
} //CopyOrCoerce
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CTableVariant::Free, public, static
|
|
//
|
|
// Synopsis: Frees data associated with a variant or a variant type
|
|
//
|
|
// Arguments: [pbData] -- pointer to area to be freed
|
|
// [vtData] -- VARTYPE of the data
|
|
// [rPool] -- pool to free from if necessary
|
|
//
|
|
// History: 18 Jan 1995 dlee Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CTableVariant::Free(
|
|
BYTE * pbData,
|
|
VARTYPE vtData,
|
|
PVarAllocator & rPool)
|
|
{
|
|
switch ( vtData )
|
|
{
|
|
case DBTYPE_BYREF|DBTYPE_PROPVARIANT:
|
|
Win4Assert( !"DBTYPE_BYREF|DBTYPE_PROPVARIANT free" );
|
|
{
|
|
CTableVariant *pvar = *((CTableVariant **) pbData);
|
|
Free( (BYTE *) & ( pvar->lVal ), pvar->vt, rPool );
|
|
break;
|
|
}
|
|
|
|
case VT_VARIANT :
|
|
{
|
|
CTableVariant *pvar = (CTableVariant *) pbData;
|
|
Free( (BYTE *) & ( pvar->lVal ), pvar->vt, rPool );
|
|
break;
|
|
}
|
|
|
|
case VT_EMPTY:
|
|
case VT_NULL:
|
|
case VT_I1:
|
|
case VT_I2:
|
|
case VT_I4:
|
|
case VT_I8:
|
|
case VT_UI1:
|
|
case VT_UI2:
|
|
case VT_UI4:
|
|
case VT_UI8:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
case VT_R4:
|
|
case VT_R8:
|
|
case VT_BOOL:
|
|
case VT_CY:
|
|
case VT_DATE:
|
|
case VT_DECIMAL:
|
|
case VT_FILETIME:
|
|
case VT_ERROR:
|
|
case DBTYPE_WSTR:
|
|
case DBTYPE_STR:
|
|
case DBTYPE_HCHAPTER:
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
{
|
|
BSTR * pBstr = (BSTR *) pbData;
|
|
rPool.FreeBSTR( *pBstr );
|
|
break;
|
|
}
|
|
|
|
case VT_LPWSTR:
|
|
case VT_LPSTR:
|
|
case DBTYPE_STR | DBTYPE_BYREF:
|
|
case DBTYPE_WSTR | DBTYPE_BYREF:
|
|
case VT_CLSID:
|
|
{
|
|
rPool.Free( * (LPWSTR *) pbData );
|
|
break;
|
|
}
|
|
|
|
case VT_BLOB:
|
|
{
|
|
BLOB * p = (BLOB *) pbData;
|
|
|
|
if ( 0 != p->cbSize )
|
|
rPool.Free( p->pBlobData );
|
|
break;
|
|
}
|
|
|
|
case (VT_VECTOR | VT_I1):
|
|
case (VT_VECTOR | VT_I2):
|
|
case (VT_VECTOR | VT_I4):
|
|
case (VT_VECTOR | VT_I8):
|
|
case (VT_VECTOR | VT_UI1):
|
|
case (VT_VECTOR | VT_UI2):
|
|
case (VT_VECTOR | VT_UI4):
|
|
case (VT_VECTOR | VT_UI8):
|
|
case (VT_VECTOR | VT_R4):
|
|
case (VT_VECTOR | VT_R8):
|
|
case (VT_VECTOR | VT_BOOL):
|
|
case (VT_VECTOR | VT_CY):
|
|
case (VT_VECTOR | VT_DATE):
|
|
case (VT_VECTOR | VT_FILETIME):
|
|
case (VT_VECTOR | VT_CLSID):
|
|
{
|
|
CAUL * p = (CAUL *) pbData;
|
|
|
|
tbDebugOut(( DEB_ITRACE, "calling free on vector type %x, # %x, pb %x\n",
|
|
vtData, p->cElems, p->pElems ));
|
|
|
|
if ( 0 != p->cElems )
|
|
rPool.Free( p->pElems );
|
|
|
|
break;
|
|
}
|
|
|
|
case (VT_VECTOR | VT_LPSTR):
|
|
case (VT_VECTOR | VT_LPWSTR):
|
|
case (VT_VECTOR | DBTYPE_STR | DBTYPE_BYREF): // SPECDEVIATION vector/byref mutually exclusive
|
|
case (VT_VECTOR | DBTYPE_WSTR | DBTYPE_BYREF):
|
|
{
|
|
CALPWSTR * p = (CALPWSTR *) pbData;
|
|
if ( 0 != p->cElems )
|
|
{
|
|
for ( unsigned x = 0; x < p->cElems; x++ )
|
|
rPool.Free( p->pElems[ x ] );
|
|
|
|
rPool.Free( p->pElems );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (VT_VECTOR | VT_BSTR):
|
|
{
|
|
CABSTR * p = (CABSTR *) pbData;
|
|
if ( 0 != p->cElems )
|
|
{
|
|
for ( unsigned x = 0; x < p->cElems; x++ )
|
|
rPool.FreeBSTR( p->pElems[ x ] );
|
|
|
|
rPool.Free( p->pElems );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (VT_VECTOR | VT_VARIANT):
|
|
{
|
|
CAPROPVARIANT * p = (CAPROPVARIANT *) pbData;
|
|
|
|
if ( 0 != p->cElems )
|
|
{
|
|
for ( unsigned x = 0; x < p->cElems; x++ )
|
|
Free( (BYTE *) & (p->pElems[ x ]), VT_VARIANT, rPool );
|
|
|
|
rPool.Free( p->pElems );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case VT_ARRAY|VT_I1:
|
|
case VT_ARRAY|VT_I2:
|
|
case VT_ARRAY|VT_I4:
|
|
case VT_ARRAY|VT_I8:
|
|
case VT_ARRAY|VT_UI1:
|
|
case VT_ARRAY|VT_UI2:
|
|
case VT_ARRAY|VT_UI4:
|
|
case VT_ARRAY|VT_UI8:
|
|
case VT_ARRAY|VT_INT:
|
|
case VT_ARRAY|VT_UINT:
|
|
case VT_ARRAY|VT_R4:
|
|
case VT_ARRAY|VT_R8:
|
|
case VT_ARRAY|VT_BOOL:
|
|
case VT_ARRAY|VT_CY:
|
|
case VT_ARRAY|VT_DATE:
|
|
case VT_ARRAY|VT_DECIMAL:
|
|
{
|
|
SAFEARRAY * p = *(SAFEARRAY **)pbData;
|
|
|
|
tbDebugOut(( DEB_ITRACE, "calling free on array type %x, # %x, pb %x\n",
|
|
vtData, p, p->pvData ));
|
|
|
|
rPool.Free( p->pvData );
|
|
rPool.Free( p );
|
|
|
|
break;
|
|
}
|
|
|
|
case VT_ARRAY|VT_BSTR:
|
|
{
|
|
SAFEARRAY * p = *(SAFEARRAY **)pbData;
|
|
|
|
tbDebugOut(( DEB_ITRACE, "calling free on array type %x, # %x, pb %x\n",
|
|
vtData, p, p->pvData ));
|
|
|
|
ULONG cElements = SaCountElements(*p);
|
|
BSTR *apBstr = (BSTR *)p->pvData;
|
|
|
|
for (unsigned x = 0; x < cElements; x++)
|
|
{
|
|
rPool.FreeBSTR( apBstr[ x ] );
|
|
}
|
|
|
|
rPool.Free( apBstr );
|
|
rPool.Free( p );
|
|
|
|
break;
|
|
}
|
|
|
|
case VT_ARRAY|VT_VARIANT:
|
|
{
|
|
SAFEARRAY * p = *(SAFEARRAY **)pbData;
|
|
|
|
tbDebugOut(( DEB_ITRACE, "calling free on array type %x, # %x, pb %x\n",
|
|
vtData, p, p->pvData ));
|
|
|
|
ULONG cElements = SaCountElements(*p);
|
|
VARIANT *apVarnt = (VARIANT *)p->pvData;
|
|
|
|
for (unsigned x = 0; x < cElements; x++)
|
|
{
|
|
Free( (BYTE *) & (apVarnt[ x ]), VT_VARIANT, rPool );
|
|
}
|
|
|
|
rPool.Free( apVarnt );
|
|
rPool.Free( p );
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case VT_CF:
|
|
{
|
|
CLIPDATA * * ppClipData = (CLIPDATA **) pbData;
|
|
if ( 0 != ppClipData )
|
|
{
|
|
rPool.Free( (*ppClipData)->pClipData );
|
|
rPool.Free( *ppClipData );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case (VT_VECTOR | VT_CF):
|
|
{
|
|
CACLIPDATA * p = (CACLIPDATA *) pbData;
|
|
|
|
if ( 0 != p )
|
|
{
|
|
for ( ULONG i = 0; i < p->cElems; i++ )
|
|
rPool.Free( p->pElems[i].pClipData );
|
|
rPool.Free( p->pElems );
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
tbDebugOut(( DEB_WARN, "tblvarnt free of unknown type %x\n",
|
|
vtData ));
|
|
break;
|
|
}
|
|
}
|
|
} //Free
|