2025-11-28 00:35:46 +09:00

482 lines
14 KiB
C++

//-----------------------------------------------------------------------------
// Microsoft OLE DB RowsetViewer
// Copyright (C) 1994 - 1999 By Microsoft Corporation.
//
// @doc
//
// @module CCOMMAND.CPP
//
//-----------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////
// Includes
//
/////////////////////////////////////////////////////////////////
#include "Headers.h"
/////////////////////////////////////////////////////////////////
// CCommand::CCommand
//
/////////////////////////////////////////////////////////////////
CCommand::CCommand(CMainWindow* pCMainWindow, CMDIChild* pCMDIChild)
: CDataAccess(eCCommand, pCMainWindow, pCMDIChild)
{
//OLE DB Interfaces
m_pICommand = NULL; //Command interface
m_pICommandProperties = NULL; //Command interface
m_pICommandText = NULL; //Command interface
m_pICommandStream = NULL; //Command interface
m_pICommandPrepare = NULL; //Command interface
m_pICommandPersist = NULL; //Command interface
m_pICommandWithParameters = NULL; //Command interface
//Data
m_guidDialect = DBGUID_DEFAULT;
}
/////////////////////////////////////////////////////////////////
// CCommand::~CCommand
//
/////////////////////////////////////////////////////////////////
CCommand::~CCommand()
{
ReleaseObject(0);
}
/////////////////////////////////////////////////////////////////
// IUnknown** CCommand::GetInterfaceAddress
//
/////////////////////////////////////////////////////////////////
IUnknown** CCommand::GetInterfaceAddress(REFIID riid)
{
HANDLE_GETINTERFACE(ICommand);
HANDLE_GETINTERFACE(ICommandProperties);
HANDLE_GETINTERFACE(ICommandText);
HANDLE_GETINTERFACE(ICommandStream);
HANDLE_GETINTERFACE(ICommandPrepare);
HANDLE_GETINTERFACE(ICommandPersist);
HANDLE_GETINTERFACE(ICommandWithParameters);
//Otherwise delegate
return CDataAccess::GetInterfaceAddress(riid);
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::AutoRelease
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::AutoRelease()
{
ReleaseAccessor(&m_Parameters.GetParams().hAccessor);
m_Parameters.RemoveAll();
//Command
RELEASE_INTERFACE(IAccessor);
RELEASE_INTERFACE(IColumnsInfo);
RELEASE_INTERFACE(ICommand);
RELEASE_INTERFACE(ICommandProperties);
RELEASE_INTERFACE(ICommandText);
RELEASE_INTERFACE(ICommandStream);
RELEASE_INTERFACE(IConvertType);
RELEASE_INTERFACE(ICommandPrepare);
RELEASE_INTERFACE(ICommandPersist);
RELEASE_INTERFACE(ICommandWithParameters);
//Delegate
return CDataAccess::AutoRelease();
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::AutoQI
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::AutoQI(DWORD dwCreateOpts)
{
//Delegate First so we have base interfaces
CDataAccess::AutoQI(dwCreateOpts);
//[MANDATORY]
if(dwCreateOpts & CREATE_QI_MANDATORY)
{
OBTAIN_INTERFACE(ICommand);
OBTAIN_INTERFACE(ICommandText);
}
//[OPTIONAL]
if(dwCreateOpts & CREATE_QI_OPTIONAL)
{
//[OPTIONAL]
OBTAIN_INTERFACE(ICommandStream);
OBTAIN_INTERFACE(ICommandProperties);
OBTAIN_INTERFACE(ICommandPrepare);
OBTAIN_INTERFACE(ICommandPersist);
OBTAIN_INTERFACE(ICommandWithParameters);
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::SetProperties
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::SetProperties(ULONG cPropSets, DBPROPSET* rgPropSets)
{
HRESULT hr = E_FAIL;
//Initally setup up some rowset properties that are very useful functionality
//These are mainly to have the most common operations on the rowset and to
//be able to obtain blob columns...
if(m_pICommandProperties)
{
//ICommandProperties::SetProperties
XTEST_(hr = m_pICommandProperties->SetProperties(cPropSets, rgPropSets),S_OK);
TRACE_METHOD(hr, L"ICommandProperties::SetProperties(%d, 0x%p)", cPropSets, rgPropSets);
//Display property errors
TESTC(hr = DisplayPropErrors(hr, cPropSets, rgPropSets));
}
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::GetCurrentCommand
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::GetCurrentCommand(DBID** ppCommandID)
{
HRESULT hr = E_FAIL;
if(m_pICommandPersist)
{
WCHAR wszCommandID[MAX_NAME_LEN] = {0};
//ICommandPersist::GetCurrentCommand
hr = m_pICommandPersist->GetCurrentCommand(ppCommandID);
//Format the resultant DBID into something the user can look at...
DBIDToString(ppCommandID ? *ppCommandID : NULL, wszCommandID, MAX_NAME_LEN);
TESTC(TRACE_METHOD(hr, L"ICommandPersist::GetCurrentCommand({\"%s\"})", wszCommandID));
}
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::CreateParamAccessor
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::CreateParamAccessor(DB_UPARAMS cParams, DBPARAMINFO* rgParamInfo, DB_UPARAMS cParamSets)
{
HRESULT hr = S_OK;
DBCOUNTITEM cBindings = 0;
DBBINDING* rgBindings = NULL;
HACCESSOR hAccessor = NULL;
DBLENGTH cbRowSize = 0;
//Release Previous Accessor
ReleaseAccessor(&m_Parameters.GetParams().hAccessor);
m_Parameters.RemoveAll();
//Setup the Bindings
TESTC(hr = SetupBindings(cParams, rgParamInfo, &cBindings, &rgBindings, &cbRowSize));
//Create the Accessor
TESTC(hr = CreateAccessor(DBACCESSOR_PARAMETERDATA, cBindings, rgBindings, cbRowSize, &hAccessor));
//Attach our object...
TESTC(hr = m_Parameters.Attach(cParamSets, hAccessor, cbRowSize));
m_Parameters.GetBindings().Attach(cBindings, rgBindings);
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::SetupBindings
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::SetupBindings(DB_UPARAMS cParams, DBPARAMINFO* rgParamInfo, DBCOUNTITEM* pcBindings, DBBINDING** prgBindings, DBLENGTH* pcRowSize)
{
ASSERT(pcBindings);
ASSERT(prgBindings);
HRESULT hr = S_OK;
DBLENGTH dwOffset = 0;
DBCOUNTITEM i,cBindings = 0;
DBBINDING* rgBindings = NULL;
//Only capable of the Following Converions (for Display)
DWORD dwMaxLength = GetOptions()->m_dwMaxLength;
DWORD dwAccessorOpts = GetOptions()->m_dwAccessorOpts;
//Alloc the space to hold the Bindings and Accessors
SAFE_ALLOC(rgBindings, DBBINDING, cParams);
cBindings = 0;
for(i=0; i<cParams; i++)
{
ASSERT(rgParamInfo);
//SetUp the Bindings
rgBindings[cBindings].iOrdinal = rgParamInfo[i].iOrdinal;
rgBindings[cBindings].obStatus = dwOffset;
dwOffset += ROUNDUP(sizeof(DBSTATUS));
rgBindings[cBindings].obLength = dwOffset;
dwOffset += ROUNDUP(sizeof(DBLENGTH));
rgBindings[cBindings].obValue = dwOffset;
rgBindings[cBindings].pTypeInfo = NULL;
rgBindings[cBindings].pBindExt = NULL;
rgBindings[cBindings].dwPart = dwAccessorOpts & (DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS);
rgBindings[cBindings].dwMemOwner= (dwAccessorOpts & ACCESSOR_OWNED_PROVIDER) ? DBMEMOWNER_PROVIDEROWNED : DBMEMOWNER_CLIENTOWNED;
rgBindings[cBindings].eParamIO = DBPARAMIO_NOTPARAM;
if(rgParamInfo[i].dwFlags & DBPARAMFLAGS_ISINPUT)
rgBindings[cBindings].eParamIO |= DBPARAMIO_INPUT;
if(rgParamInfo[i].dwFlags & DBPARAMFLAGS_ISOUTPUT)
rgBindings[cBindings].eParamIO |= DBPARAMIO_OUTPUT;
rgBindings[cBindings].dwFlags = 0;
rgBindings[cBindings].bPrecision= rgParamInfo[i].bPrecision;
rgBindings[cBindings].bScale = rgParamInfo[i].bScale;
rgBindings[cBindings].pObject = NULL;
rgBindings[cBindings].wType = GetOptions()->GetBindingType(rgParamInfo[i].wType);
//MAX_LENGTH
rgBindings[cBindings].cbMaxLen = GetMaxDisplaySize(rgBindings[cBindings].wType, rgParamInfo[i].wType, rgParamInfo[i].ulParamSize, dwMaxLength);
dwOffset += rgBindings[cBindings].cbMaxLen;
dwOffset = ROUNDUP( dwOffset );
cBindings++;
}
//Size for pData
if(pcRowSize)
*pcRowSize = dwOffset;
CLEANUP:
//Accessors
*pcBindings = cBindings;
*prgBindings = rgBindings;
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::Prepare
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::Prepare(ULONG cExpectedRuns)
{
HRESULT hr = S_OK;
//Prepare
if(m_pICommandPrepare)
{
//ICommandPrepare::Prepare
hr = m_pICommandPrepare->Prepare(0);
TRACE_METHOD(hr, L"ICommandPrepare::Prepare(%d)", cExpectedRuns);
}
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::GetParameterInfo
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::GetParameterInfo(DB_UPARAMS* pcParams, DBPARAMINFO** prgParamInfo, OLECHAR** ppwszNamesBuffer)
{
HRESULT hr = S_OK;
if(m_pICommandWithParameters)
{
//ICommandWithParameters::GetParameterInfo
hr = m_pICommandWithParameters->GetParameterInfo(pcParams, prgParamInfo, ppwszNamesBuffer);
TRACE_METHOD(hr, L"ICommandWithParameters::GetParameterInfo(&%lu, &0x%p, &0x%p)", pcParams ? *pcParams : 0, prgParamInfo ? *prgParamInfo : NULL, ppwszNamesBuffer ? *ppwszNamesBuffer : NULL);
}
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::SetCommandText
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::SetCommandText(WCHAR* pwszText, GUID* pGuidDialect)
{
HRESULT hr = E_NOINTERFACE;
GUID guidDialect = pGuidDialect ? *pGuidDialect : m_guidDialect;
//Set CommandText
if(m_pICommandText)
{
XTEST(hr = m_pICommandText->SetCommandText(guidDialect, pwszText));
TESTC(TRACE_METHOD(hr, L"ICommandText::SetCommandText(%s, \"%s\")", GetDialectName(guidDialect), pwszText));
//Save the Command Text on Success...
if(pGuidDialect)
m_guidDialect = *pGuidDialect;
}
CLEANUP:
return hr;
}
////////////////////////////////////////////////////////////////
// HRESULT CCommand::SetCommandStream
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::SetCommandStream(WCHAR* pwszText, REFIID riid, GUID* pGuidDialect, BOOL fUnicode)
{
HRESULT hr = E_NOINTERFACE;
GUID guidDialect = pGuidDialect ? *pGuidDialect : m_guidDialect;
CStorageBuffer* pCStream = NULL;
//Set CommandStream
if(m_pICommandStream)
{
//Create a stream object over the specified text.
pCStream = new CStorageBuffer;
if(pwszText)
{
ULONG cbWritten = 0;
if(fUnicode)
{
//UNICODE-Stream:
//We need to place the BOM mark to indicate its a Unicode stream...
TESTC(pCStream->WriteBuffer(0, &UNICODE_BYTE_ORDER_MARK, sizeof(UNICODE_BYTE_ORDER_MARK), &cbWritten));
TESTC(pCStream->WriteBuffer(cbWritten, pwszText, (ULONG)wcslen(pwszText)*sizeof(WCHAR), NULL));
}
else
{
//MBCS-Stream:
//First convert the Unicode stream to MBCS
CHAR* pszText = ConvertToMBCS(pwszText);
TESTC(pCStream->WriteBuffer(cbWritten, pszText, (ULONG)(strlen(pszText)*sizeof(CHAR)), NULL));
SAFE_FREE(pszText);
}
}
//ICommandStream::SetCommandStream
//NOTE: The provider has to validate that the object passed in actually supports the interface
//requested, so we can just blindly pass in the IUnknown and it will do the QI, not us...
XTEST(hr = m_pICommandStream->SetCommandStream(riid, guidDialect, (IStream*)pCStream));
TESTC(TRACE_METHOD(hr, L"ICommandStream::SetCommandStream(%s, %s, \"%s\")", GetInterfaceName(riid), GetDialectName(guidDialect), pwszText));
//Save the Command Text on Success...
if(pGuidDialect)
m_guidDialect = *pGuidDialect;
}
CLEANUP:
SAFE_RELEASE(pCStream);
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CCommand::Execute
//
/////////////////////////////////////////////////////////////////
HRESULT CCommand::Execute(CAggregate* pCAggregate, WCHAR* pwszCommandText, REFIID riid, BOOL fUseParams, DBROWCOUNT* pcRowsAffected, IUnknown** ppIUnknown, BOOL fCommandStream)
{
HRESULT hr = S_OK;
DBROWCOUNT cRowsAffected = DB_COUNTUNAVAILABLE;
//Execute
if(m_pICommand)
{
//SetCommandText (if user requested new text)
if(pwszCommandText)
{
//Clear previous object (if requested and really need to...)
if(GetOptions()->m_dwCommandOpts & COMMAND_RELEASE_OPENOBJECTS)
{
//Release all child objects of the command.
//NOTE: This includes: Rowset, Row, DataSet, Stream, etc...
ReleaseChildren();
}
//SetCommandText...
if(fCommandStream)
{
TESTC(hr = SetCommandStream(pwszCommandText));
}
else
{
TESTC(hr = SetCommandText(pwszCommandText));
}
}
//Execute
XTEST_(hr = m_pICommand->Execute(
pCAggregate, // pUnkOuter
riid, // refiid
fUseParams ? &m_Parameters.GetParams() : NULL, // params
&cRowsAffected, // rows affected
ppIUnknown),S_OK); // IRowset pointer
TRACE_METHOD(hr, L"ICommand::Execute(0x%p, %s, 0x%p, &%Id, &0x%p)", pCAggregate, GetInterfaceName(riid), fUseParams ? &m_Parameters.GetParams() : NULL, cRowsAffected, ppIUnknown ? *ppIUnknown : NULL);
//Display Property Errors
TESTC(hr = DisplayPropErrors(hr, IID_ICommandProperties, m_pICommand));
//ParameterBinding Errors
if(fUseParams)
{
//Loop through the parameter sets (if any)
for(ULONG iParamSet=0; iParamSet<m_Parameters.GetParams().cParamSets; iParamSet++)
TESTC(hr = DisplayBindingErrors(hr, m_Parameters.GetBindings().GetCount(), m_Parameters.GetBindings().GetElements(), m_Parameters.GetData(iParamSet)));
}
//Handle Aggregation
if(pCAggregate)
TESTC(hr = pCAggregate->HandleAggregation(riid, ppIUnknown));
//Display RowsAffected - (if desired)
if(!pcRowsAffected)
{
if(!ppIUnknown || !*ppIUnknown)
{
if(cRowsAffected==DB_COUNTUNAVAILABLE)
wMessageBox(GetFocus(), MB_TASKMODAL | MB_ICONWARNING | MB_OK, wsz_INFO,
L"RowsAffected = %s, No Rowset returned", L"DB_COUNTUNAVAILABLE");
else
wMessageBox(GetFocus(), MB_TASKMODAL | MB_ICONWARNING | MB_OK, wsz_INFO,
L"RowsAffected = %Id, No Rowset returned", cRowsAffected );
}
}
}
CLEANUP:
if(pcRowsAffected)
*pcRowsAffected = cRowsAffected;
return hr;
}