//+------------------------------------------------------------------------- // // 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 #include #include #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 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 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