📄 ctable.cpp
字号:
break;
default: //DBSTATUS_S_OK
{
//Set STATUS
BINDING_STATUS(*pBinding, pData) = DBSTATUS_S_OK;
//We have a problem if the user has entered a value (string) longer than
//the buffer we have allocated. If the length is greater than
//cbMaxLen we need to truncate it and inform the user...
ULONG cbBytes = strlen(pszValue);
switch(pBinding->wType)
{
case DBTYPE_STR:
cbBytes = (cbBytes + 1)*sizeof(CHAR);
break;
case DBTYPE_WSTR:
case DBTYPE_BSTR:
cbBytes = (cbBytes + 1)*sizeof(WCHAR);
break;
case DBTYPE_BYTES:
cbBytes = cbBytes >> 1;
break;
};
if(cbBytes > pBinding->cbMaxLen &&
pBinding->wType != DBTYPE_VARIANT)
{
//Truncate the Value
if(pBinding->wType == DBTYPE_WSTR || pBinding->wType == DBTYPE_BSTR)
pszValue[pBinding->cbMaxLen/2-1] = EOL;
else if (pBinding->wType == DBTYPE_STR)
pszValue[pBinding->cbMaxLen-1] = EOL;
else if (pBinding->wType == DBTYPE_BYTES)
pszValue[pBinding->cbMaxLen<<1] = EOL;
//Inform user of Truncation...
wMessageBox(
m_pCMDIChild->m_hWnd, MB_TASKMODAL | MB_ICONHAND | MB_OK | MB_DEFBUTTON1,
wsz_ERROR,
L"You have entered a value for column %d of %d bytes\n\n"
L"The cbMaxSize of this column is %d.\n"
L"Your value will be truncated to\n"
L"(%S)",
pBinding->iOrdinal,
cbBytes,
pBinding->cbMaxLen,
pszValue
);
}
//Set LENGTH and VALUE
//We may have bound this column in the accessor differently...
switch(pBinding->wType)
{
case DBTYPE_WSTR:
ConvertToWCHAR(pszValue, wszBuffer, MAX_COL_SIZE);
BINDING_LENGTH(*pBinding, pData) = cbBytes-sizeof(WCHAR);
wcscpy((WCHAR*)&BINDING_VALUE(*pBinding, pData), wszBuffer);
break;
case DBTYPE_STR:
BINDING_LENGTH(*pBinding, pData) = cbBytes-sizeof(CHAR);
strcpy((CHAR*)&BINDING_VALUE(*pBinding, pData), pszValue);
break;
case DBTYPE_VARIANT:
ConvertToWCHAR(pszValue, wszBuffer, MAX_COL_SIZE);
V_VT(&vVariant) = VT_BSTR;
V_BSTR(&vVariant) = SysAllocString(wszBuffer);
BINDING_LENGTH(*pBinding, pData) = sizeof(VARIANT);
memcpy(&BINDING_VALUE(*pBinding, pData), &vVariant, sizeof(VARIANT));
break;
case DBTYPE_BYTES:
XTESTC(m_pCMDIChild->m_hWnd, hr = StringToBYTES(pszValue, (BYTE*)&BINDING_VALUE(*pBinding, pData), cbBytes, &BINDING_LENGTH(*pBinding, pData)));
break;
case DBTYPE_IUNKNOWN:
//TODO
//This is kind of a pain for SetData. Since I'm going to
//have to implement each object in order to pass it to the
//provider. We might also be able to try the STGM_CREATE
//which is supposed to return an empty implemented object
//that we could "pump" our data into...
//For now, the value is just set to NULL
break;
default:
ASSERT(!"Unhandled Type!");
break;
}
break;
}
}
CLEANUP:
return hr;
}
////////////////////////////////////////////////////////////////
// CRowset::GetColumnData
//
/////////////////////////////////////////////////////////////////
HRESULT CRowset::GetColumnData(DBBINDING* pBinding, void* pData, DBSTATUS* pdwStatus, ULONG* pdwLength, DBTYPE* pwSubType, CHAR* pszValue, ULONG ulMaxSize, DWORD dwFlags, DBTYPE wBaseType)
{
ASSERT(pBinding);
ASSERT(pData);
ASSERT(pszValue);
HRESULT hr = S_OK;
//STATUS
DBSTATUS dwStatus = BINDING_STATUS(*pBinding, pData);
//LENGTH
DWORD dwLength = BINDING_LENGTH(*pBinding, pData);
//SUB-DBTYPE
DBTYPE wSubType = wBaseType == DBTYPE_VARIANT ? DBTYPE_EMPTY : wBaseType;
//LENGTH is the Actual (Untruncated) length of the string
//We we need to make sure all operations are off of cbMaxLen and not LENGTH bound
ULONG dwActualLength = min(pBinding->cbMaxLen-1, dwLength);
ASSERT(pBinding->cbMaxLen <= ulMaxSize);
//VALUE
pszValue[0] = EOL;
switch(dwStatus)
{
case DBSTATUS_S_ISNULL:
break;
//Let this case "fall" through to the S_OK case...
case DBSTATUS_S_TRUNCATED:
hr = DB_S_ERRORSOCCURRED;
case DBSTATUS_S_OK:
case DBSTATUS_S_DEFAULT:
{
switch(pBinding->wType)
{
case DBTYPE_WSTR:
{
WCHAR* pwszData = (WCHAR*)&BINDING_VALUE(*pBinding, pData);
ConvertToMBCS(pwszData, pszValue, ulMaxSize);
break;
}
case DBTYPE_STR:
{
CHAR* pszData = (CHAR*)&BINDING_VALUE(*pBinding, pData);
strncpy(pszValue, pszData, dwActualLength);
pszValue[dwActualLength] = EOL;
break;
}
case DBTYPE_BYTES:
{
//Otherwise treat it as a stream of BYTES
BYTE* pbData = (BYTE*)&BINDING_VALUE(*pBinding, pData);
BYTESToString(pbData, pszValue, dwActualLength, &dwLength);
break;
}
case DBTYPE_VARIANT:
{
VARIANT* pVariant = (VARIANT*)&BINDING_VALUE(*pBinding, pData);
if(pVariant)
{
wSubType = V_VT(pVariant);
hr = VariantToString(pVariant, pszValue, ulMaxSize, dwFlags);
}
break;
}
case DBTYPE_IUNKNOWN:
{
//This is required for ColumnsRowset IUnknown column
//IUnknown is not a required conversion to string (WSTR)
IUnknown* pIUnknown = (IUnknown*)BINDING_VALUE(*pBinding, pData);
REFIID iid = pBinding->pObject ? pBinding->pObject->iid : IID_NULL;
WCHAR wszBuffer[MAX_QUERY_LEN] = {0};
void* pvBuffer = pszValue;
dwLength = 0;
//Need to handle WIDE streams...
if(wBaseType == DBTYPE_BYTES || wBaseType == DBTYPE_WSTR || wBaseType == DBTYPE_BSTR)
pvBuffer = wszBuffer;
if(pIUnknown == NULL)
{
//I have no clue what type of object this is.
//So just display the pointer
sprintf(pszValue, "0x%08x", pIUnknown);
}
else if(iid == IID_ISequentialStream)
{
//Read the Data into our buffer
ISequentialStream* pISeqStream = (ISequentialStream*)pIUnknown;
XTESTC(NULL, hr = pISeqStream->Read(pvBuffer, ulMaxSize, &dwLength));
}
else if(iid == IID_ILockBytes)
{
//Read the Data into our buffer
ULARGE_INTEGER ulOffset = {0};
ILockBytes* pILockBytes = (ILockBytes*)pIUnknown;
XTESTC(NULL, hr = pILockBytes->ReadAt(ulOffset, pvBuffer, ulMaxSize, &dwLength));
}
else if(iid == IID_IStream)
{
//Read the Data into our buffer
IStream* pIStream = (IStream*)pIUnknown;
XTESTC(NULL, hr = pIStream->Read(pvBuffer, ulMaxSize, &dwLength));
}
//TODO else if(iid == IID_IStorage)
// {
// }
else
{
//I have no clue what type of object this is.
//So just display the pointer
sprintf(pszValue, "0x%08x", pIUnknown);
}
//Deal with the data returned...
if(dwLength)
{
switch(wBaseType)
{
case DBTYPE_BSTR:
case DBTYPE_WSTR:
//Need to convert the stream to CHAR for display
ConvertToMBCS(wszBuffer, pszValue, min(dwLength, ulMaxSize-1));
break;
case DBTYPE_STR:
break;
default:
//Otherwise treat it as a stream of BYTES
BYTESToString((BYTE*)pvBuffer, pszValue, min(dwLength, ulMaxSize-1), &dwLength);
break;
}
//Need to NULL terminate the stream, since its just a stream
//of bytes returned from the provider with no termination
pszValue[min(dwLength, ulMaxSize-1)] = EOL;
}
SAFE_RELEASE(pIUnknown);
break;
}
default:
ASSERT(!"Unhandled Type!");
hr = E_FAIL;
break;
}
break;
}
default:
//Error Status code...
hr = E_FAIL;
break;
}
//PostProcessing
if(SUCCEEDED(hr))
{
//Hexadecimal
if(dwFlags & CONV_HEX)
{
switch(wSubType)
{
case DBTYPE_I1:
case DBTYPE_UI1:
case DBTYPE_I2:
case DBTYPE_UI2:
case DBTYPE_I4:
case DBTYPE_UI4:
ConvertString(pszValue, ulMaxSize, dwFlags);
break;
}
}
}
CLEANUP:
//Output Params
if(pdwStatus)
*pdwStatus = dwStatus;
if(pdwLength)
*pdwLength = dwLength;
if(pwSubType)
*pwSubType = wSubType;
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CRowset::CreateAccessors
//
/////////////////////////////////////////////////////////////////
HRESULT CRowset::CreateAccessors(BOOL fBindBookmark)
{
HRESULT hr = S_OK;
HRESULT hrOptional = S_OK;
ULONG cbRowSize = 0;
//Release Previous Accessors
ReleaseAccessor(&m_hAccessor);
FreeBindings(&m_cBindings, &m_rgBindings);
SAFE_FREE(m_pData);
ReleaseAccessor(&m_hBmkAccessor);
FreeBindings(&m_cBmkBindings, &m_rgBmkBindings);
//Delegate
TESTC(hr = SetupBindings(fBindBookmark ? BIND_ALLCOLS : BIND_ALLCOLSEXPECTBOOKMARK, &m_cBindings, &m_rgBindings, &cbRowSize));
TESTC(hr = CreateAccessor(DBACCESSOR_ROWDATA, m_cBindings, m_rgBindings, cbRowSize, &m_hAccessor));
//Allocate pData
SAFE_ALLOC(m_pData, BYTE, cbRowSize);
//Create Bookmark Accessor (if bookmark is included)
if(m_fContainsBmk)
{
TESTC(hrOptional = SetupBindings(BIND_BOOKMARKONLY, &m_cBmkBindings, &m_rgBmkBindings, &cbRowSize));
TESTC(hrOptional = CreateAccessor(DBACCESSOR_ROWDATA, m_cBmkBindings, m_rgBmkBindings, cbRowSize, &m_hBmkAccessor));
}
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CRowset::SetupBindings
//
/////////////////////////////////////////////////////////////////
HRESULT CRowset::SetupBindings(BINDCOLS eBindCols, ULONG* pcBindings, DBBINDING** prgBindings, ULONG* pcRowSize, BOOL* pbOutofLine)
{
HRESULT hr = S_OK;
HWND hWnd = m_pCMDIChild->m_hWnd;
CListBox* pCListBox = m_pCMDIChild->m_pCListBox;
ULONG dwOffset = 0;
ULONG i,cBindings = 0;
DBBINDING* rgBindings = NULL;
ULONG cStorageObjects = 0;
//Only capable of the Following Converions (for Display)
DBTYPE wBindingType = (DBTYPE)GetOptionsObj()->m_dwBindingType;
DWORD dwRowsetOpts = GetOptionsObj()->m_dwRowsetOpts;
//Special Handling for Bookmark only accessor
if(eBindCols == BIND_BOOKMARKONLY)
wBindingType = DBTYPE_BYTES;
else if(m_eRowsetSource == ROWSET_FROMCOMMANDDATASET)
wBindingType = DBTYPE_VARIANT; // MSOLAP supports only variants
//Alloc the space to hold the Bindings
SAFE_ALLOC(rgBindings, DBBINDING, m_cColumns);
cBindings = 0;
for(i=0; i<m_cColumns; i++)
{
ASSERT(m_rgColumnInfo);
//Setup the Bindings
rgBindings[cBindings].iOrdinal = m_rgColumnInfo[i].iOrdinal;
rgBindings[cBindings].obStatus = dwOffset;
rgBindings[cBindings].obLength = dwOffset + sizeof(DBSTATUS);
rgBindings[cBindings].obValue = dwOffset + sizeof(DBSTATUS) + sizeof(ULONG);
rgBindings[cBindings].pTypeInfo = NULL;
rgBindings[cBindings].pBindExt = NULL;
rgBindings[cBindings].dwPart = DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS;
rgBindings[cBindings].dwMemOwner= DBMEMOWNER_CLIENTOWNED;
rgBindings[cBindings].eParamIO = DBPARAMIO_NOTPARAM;
rgBindings[cBindings].dwFlags = 0;
rgBindings[cBindings].bPrecision= m_rgColumnInfo[i].bPrecision;
rgBindings[cBindings].bScale = m_rgColumnInfo[i].bScale;
rgBindings[cBindings].pObject = NULL;
rgBindings[cBindings].wType = wBindingType;
rgBindings[cBindings].cbMaxLen = 0;
//May need to adjust the MaxLen, depending upon what the BindingType is
switch(wBindingType)
{
case DBTYPE_VARIANT:
rgBindings[cBindings].cbMaxLen = sizeof(VARIANT);
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -