|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000.
//
// File: svcproxy.cxx
//
// Contents: Proxy to cisvc encapsulating all the context for a
// running query, including the query execution context, the
// cached query results, and all cursors over the results.
//
// Classes: CSvcQueryProxy
//
// History: 13 Sept 96 dlee created (mostly copied) from queryprx.cxx
// 22 Aug 99 KLam Win64->Win32 support
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <query.hxx>
#include <pickle.hxx>
#include <memser.hxx>
#include <sizeser.hxx>
#include <propvar.h>
#include <proxymsg.hxx>
#include <tblvarnt.hxx>
#include <tgrow.hxx>
#include <pmalloc.hxx>
#include "tabledbg.hxx"
#include "rowseek.hxx"
//+---------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::CSvcQueryProxy, public
//
// Synopsis: Creates a locally accessible Query
//
// Arguments: [client] - Proxy for talking to remote process
// [cols] - Columns that may be bound to
// [rst] - Query restriction
// [pso] - Sort order of the query
// [pcateg] - Categorization specification
// [RstProp] - Rowset properties for rowset(s) created
// [pidmap] - Property ID mapper
// [cCursors] - count of cursors expected to be created
// [aCursors] - returns handles to cursors created
//
// History: 13 Sept 96 dlee created
//
//----------------------------------------------------------------------------
CSvcQueryProxy::CSvcQueryProxy( CRequestClient & client, CColumnSet const & cols, CRestriction const & rst, CSortSet const * pso, CCategorizationSet const * pcateg, CRowsetProperties const & RstProp, CPidMapper const & pidmap , ULONG cCursors, ULONG * aCursors ) : _ref( 0 ), _client( client ), _fTrueSequential( FALSE ), _fWorkIdUnique( FALSE ), _xQuery( ), _xBindings( ) { tbDebugOut(( DEB_PROXY, "CSvcQueryProxy\n" ));
// DSO property IDs change with version 5
if ( _client.GetServerVersion() < 5 ) THROW( CException( STATUS_INVALID_PARAMETER_MIX ) );
_aCursors.Init( cCursors );
ULONG cbIn = PickledSize( _client.GetServerVersion(), &cols, &rst, pso, pcateg, &RstProp, &pidmap ); cbIn = AlignBlock( cbIn, sizeof ULONG ); XArray<BYTE> xQuery( cbIn + sizeof CPMCreateQueryIn ); BYTE * pbPickledQuery = xQuery.GetPointer() + sizeof CPMCreateQueryIn; Pickle( _client.GetServerVersion(), &cols, &rst, pso, pcateg, &RstProp, &pidmap, pbPickledQuery, cbIn );
CPMCreateQueryIn & request = * ( new( xQuery.Get() ) CPMCreateQueryIn );
request.SetCheckSum( xQuery.SizeOf() );
const unsigned cbCursors = sizeof ULONG * cCursors; const unsigned cbReply = sizeof CPMCreateQueryOut + cbCursors; XGrowable<BYTE, 200> xReply( cbReply ); CPMCreateQueryOut * pReply = new( xReply.Get() ) CPMCreateQueryOut();
ULONG cbRead; _client.DataWriteRead( &request, xQuery.SizeOf(), pReply, cbReply, cbRead );
// DataWriteRead throws both connection problems and request problems
Win4Assert( SUCCEEDED( pReply->GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || cbReply == cbRead );
_fTrueSequential = pReply->IsTrueSequential(); _fWorkIdUnique = pReply->IsWorkIdUnique(); _ulServerCookie = pReply->GetServerCookie();
RtlCopyMemory( aCursors, pReply->GetCursors(), cbCursors );
//
// Preserve xQuery for RestartPosition on sequential queries
//
if ( _fTrueSequential ) { unsigned cElems = xQuery.Count(); _xQuery.Set( cElems, xQuery.Acquire() );
// The assumption here is that for a seq query the cursor does not
// change. If this becomes different at a later date, the rowset
// will have an old cursor after RestartPosition.
RtlCopyMemory( _aCursors.Get(), aCursors, cbCursors ); }
#if CIDBG == 1
for ( ULONG i = 0; i < cCursors; i++ ) Win4Assert( 0 != aCursors[i] ); #endif // CIDBG == 1
AddRef(); } //CSvcQueryProxy
//+---------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::~CSvcQueryProxy, public
//
// Synopsis: Destroy the query. Nothing to do -- all of the cursors
// have been freed by now.
//
// History: 13 Sept 96 dlee created
//
//----------------------------------------------------------------------------
CSvcQueryProxy::~CSvcQueryProxy() { tbDebugOut(( DEB_PROXY, "~CSvcQueryProxy\n\n" )); Win4Assert( 0 == _ref );
// don't _client.Disconnect() here -- keep it open for more queries
} //~CSvcQueryProxy
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::AddRef, public
//
// Synopsis: Reference the query.
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
ULONG CSvcQueryProxy::AddRef() { return InterlockedIncrement( & _ref ); } //AddRef
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::Release, public
//
// Synopsis: De-Reference the query.
//
// Effects: If the ref count goes to 0 then the query is deleted.
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
ULONG CSvcQueryProxy::Release() { long l = InterlockedDecrement( & _ref );
if ( l <= 0 ) { tbDebugOut(( DEB_PROXY, "CSvcQueryProxy unreferenced. Deleting.\n" )); delete this; return 0; }
return l; } //Release
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::FreeCursor, public
//
// Synopsis: Free a handle to a CTableCursor
//
// Arguments: [hCursor] - handle to the cursor to be freed
//
// Returns: # of cursors remaining
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
unsigned CSvcQueryProxy::FreeCursor( ULONG hCursor ) { tbDebugOut(( DEB_PROXY, "FreeCursor\n" )); Win4Assert( 0 != hCursor );
// If FreeCursor fails (likely because the system is out of memory),
// terminate the connection with cisvc so query resources are freed.
TRY { CPMFreeCursorIn request( hCursor ); CPMFreeCursorOut reply; ULONG cbRead; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
return reply.CursorsRemaining(); } CATCH( CException, e ) { prxDebugOut(( DEB_IWARN, "freecursor failed 0x%x, rudely terminating connection\n", e.GetErrorCode() ));
_client.TerminateRudelyNoThrow();
RETHROW(); } END_CATCH
return 0; } //FreeCursor
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::GetRows, public
//
// Synopsis: Retrieve row data for a table cursor
//
// Arguments: [hCursor] - the handle of the cursor to fetch data for
// [rSeekDesc] - row seek operation to be done before fetch
// [pGetRowsParams] - row fetch parameters and buffer pointers
// [pSeekDescOut] - row seek description for restart
//
// Returns: SCODE - the status of the operation.
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
SCODE CSvcQueryProxy::GetRows( ULONG hCursor, const CRowSeekDescription & rSeekDesc, CGetRowsParams & rGetRowsParams, XPtr<CRowSeekDescription> & pSeekDescOut) { tbDebugOut(( DEB_PROXY, "GetRows 0x%x\n", rGetRowsParams.RowsToTransfer() ));
unsigned cbSeek = rSeekDesc.MarshalledSize(); unsigned cbInput = sizeof CPMGetRowsIn + cbSeek; unsigned cbReserved = AlignBlock( sizeof CPMGetRowsOut + cbSeek, sizeof LONGLONG ); XArray<BYTE> xIn( cbInput ); CPMGetRowsIn *pRequest = new( xIn.Get() ) CPMGetRowsIn( hCursor, rGetRowsParams.RowsToTransfer(), rGetRowsParams.GetFwdFetch(), rGetRowsParams.GetRowWidth(), cbSeek, cbReserved ); // serialize the seek description
CMemSerStream stmMem( pRequest->GetDesc(), cbSeek ); rSeekDesc.Marshall( stmMem );
// Make an allocator for the output. Scale the buffer size based
// on the # of rows to be retrieved (just a heuristic). Large buffers
// are more expensive since the entire buffer must be sent over the
// pipe (since var data grows down from the end of the buffer).
// For 10 rows in a typical web query, it takes about 7-10k. Any way
// to squeeze it so it always fits in 8k? Eg:
// filename,size,characterization,vpath,doctitle,write
// filename -- 20
// abstract -- 640
// props+variants -- 16*6
// vpath -- 100
// title -- 80
// total: 936 * 10 rows = 9360 bytes
const unsigned cbGetRowsGranularity = 512; const unsigned cbBigRow = 1000; const unsigned cbNormalRow = 300; unsigned cbOut = rGetRowsParams.RowsToTransfer() * cbBigRow; cbOut = __max( rGetRowsParams.GetRowWidth(), cbOut ); cbOut = __min( cbOut, cbMaxProxyBuffer ); XArray<BYTE> xOut;
// loop until at least 1 row fits in a buffer
CPMGetRowsOut *pReply = 0; NTSTATUS Status = 0; DWORD cbRead; do { cbOut = AlignBlock( cbOut, cbGetRowsGranularity ); Win4Assert( cbOut <= cbMaxProxyBuffer ); xOut.ReSize( cbOut );
pReply = (CPMGetRowsOut *) xOut.GetPointer(); pRequest->SetReadBufferSize( cbOut );
#ifdef _WIN64
//
// If a Win64 client is talking to a Win32 server set the base in the sent
// buffer to 0 so that the values returned are offsets and remember what the
// real pointer is.
// Otherwise, be sure to set the reply base pointer to zero to indicate to the
// rowset that no munging has to be done.
//
if ( !_client.IsServer64() ) { pRequest->SetClientBase ( 0 ); rGetRowsParams.SetReplyBase ( (BYTE *) pReply ); } else { pRequest->SetClientBase( (ULONG_PTR) pReply ); } #else
pRequest->SetClientBase( (ULONG_PTR) pReply ); #endif
pRequest->SetCheckSum( cbInput );
TRY { _client.DataWriteRead( pRequest, cbInput, pReply, cbOut, cbRead );
Status = pReply->GetStatus(); } CATCH( CException, e ) { Status = e.GetErrorCode(); } END_CATCH; } while ( ( Status == STATUS_BUFFER_TOO_SMALL ) && ( cbOut++ < cbMaxProxyBuffer ) );
prxDebugOut(( DEB_ITRACE, "Status at end of getrows: 0x%x\n", Status )); Win4Assert( pReply == (CPMGetRowsOut *) xOut.GetPointer() );
SCODE scResult = 0;
if ( NT_SUCCESS( Status ) ) { rGetRowsParams.SetRowsTransferred( pReply->RowsReturned() );
CMemDeSerStream stmDeser( pReply->GetSeekDesc(), cbReserved ); UnmarshallRowSeekDescription( stmDeser, _client.GetServerVersion(), pSeekDescOut, TRUE );
// Hand off the block to the allocator made in CRowset
Win4Assert( pReply == (CPMGetRowsOut *) xOut.GetPointer() ); PFixedVarAllocator & rAlloc = rGetRowsParams.GetFixedVarAllocator(); rAlloc.ReInit( TRUE, cbReserved, xOut.Acquire(), cbOut );
// we have pointers already, not offsets
rAlloc.SetBase( 0 );
scResult = Status; // ok, endOfRowset, blockLimitedRows, etc.
} else { if ( DB_E_BADRATIO != Status && DB_E_BADSTARTPOSITION != Status) { prxDebugOut(( DEB_ERROR, "GetRows returned 0x%x\n", Status )); }
if ( NT_WARNING( Status ) ) scResult = Status; // presumably, status is an SCODE
else scResult = E_FAIL; }
return scResult; } //GetRows
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::ReExecuteSequentialQuery, private
//
// Synopsis: Simulates re-execution of a sequential query by shutting down
// the query object on the server, recreating it and setting up
// the bindings from cached values
//
// Arguments:
//
// History: 02-28-98 danleg Created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::ReExecuteSequentialQuery() { tbDebugOut(( DEB_PROXY, "ReExecuteSequentialQuery\n" ));
// SPECDEVIATION: if we have heirarchical rowsets, all current positions
// will be reset.
//
// Shutdown the existing PQuery on the server first
//
for ( unsigned i=0; i<_aCursors.Count(); i++ ) FreeCursor( _aCursors[i] );
//
// Recreate PQuery on the server
//
CPMCreateQueryIn * pCreateReq = (CPMCreateQueryIn *) _xQuery.Get();
const unsigned cbCursors = sizeof ULONG * _aCursors.Count(); const unsigned cbReply = sizeof CPMCreateQueryOut + cbCursors;
XGrowable<BYTE, 200> xReply( cbReply ); CPMCreateQueryOut * pReply = new( xReply.Get() ) CPMCreateQueryOut();
ULONG cbRead; _client.DataWriteRead( pCreateReq, _xQuery.SizeOf(), pReply, cbReply, cbRead );
// DataWriteRead throws both connection problems and request problems
Win4Assert( SUCCEEDED( pReply->GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || cbReply == cbRead );
_fTrueSequential = pReply->IsTrueSequential(); _fWorkIdUnique = pReply->IsWorkIdUnique(); _ulServerCookie = pReply->GetServerCookie();
RtlCopyMemory( _aCursors.Get(), pReply->GetCursors(), _aCursors.Count() );
//
// Recreate bindings
//
CProxyMessage reply; CPMSetBindingsIn *pBindReq = (CPMSetBindingsIn *) _xBindings.Get();
ULONG cbRequest = sizeof CPMSetBindingsIn + pBindReq->GetBindingDescLength(); cbRequest = AlignBlock( cbRequest, sizeof ULONG );
_client.DataWriteRead( pBindReq, cbRequest, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
} // ReExecuteSequentialQuery
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::RestartPosition, public
//
// Synopsis: Reset the fetch position for the chapter back to the start
//
// Arguments: [hCursor] - handle of the cursor
// [chapt] - chapter
//
// History: 17 Apr 97 emilyb created
// 02-01-98 danleg restart for seq queries
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::RestartPosition( ULONG hCursor, CI_TBL_CHAPT chapt ) { tbDebugOut(( DEB_PROXY, "RestartPosition\n" ));
//
// If sequential, re-execute the query
//
if ( _fTrueSequential ) ReExecuteSequentialQuery(); else { CPMRestartPositionIn request( hCursor, chapt ); CProxyMessage reply; DWORD cbRead; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead ); } } //RestartPosition
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::StopAsync, public
//
// Synopsis: Stop processing of async rowset
//
// Arguments: [hCursor] - handle of the cursor
//
// History: 17 Apr 97 emilyb created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::StopAsynch( ULONG hCursor ) { tbDebugOut(( DEB_PROXY, "Stop\n" ));
CPMStopAsynchIn request( hCursor ); CProxyMessage reply; DWORD cbRead; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead ); } //StopAsynch
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::StartWatching, public
//
// Synopsis: Start watch all behavior for rowset
//
// Arguments: [hCursor] - handle of the cursor
//
// History: 17 Apr 97 emilyb created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::StartWatching( ULONG hCursor ) { tbDebugOut(( DEB_PROXY, "StartWatching\n" ));
CPMStartWatchingIn request( hCursor ); CProxyMessage reply; DWORD cbRead; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead ); } //StartWatching
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::StopWatching, public
//
// Synopsis: Stop watch all behavior for rowset
//
// Arguments: [hCursor] - handle of the cursor
//
// History: 17 Apr 97 emilyb created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::StopWatching( ULONG hCursor ) { tbDebugOut(( DEB_PROXY, "StopWatching\n" ));
CPMStopWatchingIn request( hCursor ); CProxyMessage reply; DWORD cbRead; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead ); } //StopWatching
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::RatioFinished, public
//
// Synopsis: Return the completion status as a fraction
//
// Arguments: [hCursor] - handle of the cursor to check
// [rulDenominator] - on return, denominator of fraction
// [rulNumerator] - on return, numerator of fraction
// [rcRows] - on return, number of rows in cursor
// [rfNewRows] - on return, TRUE if new rows available
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::RatioFinished( ULONG hCursor, DBCOUNTITEM & rulDenominator, DBCOUNTITEM & rulNumerator, DBCOUNTITEM & rcRows, BOOL & rfNewRows ) { tbDebugOut(( DEB_PROXY, "RatioFinished\n" )); SCODE sc = S_OK;
CPMRatioFinishedIn request( hCursor, TRUE ); CPMRatioFinishedOut reply; DWORD cbReply; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbReply );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbReply );
rulDenominator = reply.Denominator(); rulNumerator = reply.Numerator(); rcRows = reply.RowCount(); rfNewRows = reply.NewRows();
// the values must be good by now or we would have thrown
Win4Assert( 0 != rulDenominator ); Win4Assert( rulDenominator >= rulNumerator ); } //RatioFinished
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::RatioFinished, public
//
// Synopsis: Return the completion status as a fraction
//
// Arguments: [rSync] - notification synchronization info
// [hCursor] - handle of the cursor to check
// [rulDenominator] - on return, denominator of fraction
// [rulNumerator] - on return, numerator of fraction
// [rcRows] - on return, number of rows in cursor
// [rfNewRows] - on return, TRUE if new rows available
//
// Returns: S_OK or STATUS_CANCELLED if rSync's cancel event signalled.
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
SCODE CSvcQueryProxy::RatioFinished( CNotificationSync & rSync, ULONG hCursor, DBCOUNTITEM & rulDenominator, DBCOUNTITEM & rulNumerator, DBCOUNTITEM & rcRows, BOOL & rfNewRows ) { tbDebugOut(( DEB_PROXY, "RatioFinished\n" )); SCODE sc = S_OK;
CPMRatioFinishedIn request( hCursor, TRUE ); CPMRatioFinishedOut reply; DWORD cbReply; if ( _client.NotifyWriteRead( rSync.GetCancelEvent(), &request, sizeof request, &reply, sizeof reply, cbReply ) ) sc = STATUS_CANCELLED; else { Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbReply );
rulDenominator = reply.Denominator(); rulNumerator = reply.Numerator(); rcRows = reply.RowCount(); rfNewRows = reply.NewRows();
// the values must be good by now or we would have thrown
Win4Assert( 0 != rulDenominator ); Win4Assert( rulDenominator >= rulNumerator ); } return sc; } //RatioFinished (notify version)
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::Compare, public
//
// Synopsis: Return the approximate current position as a fraction
//
// Arguments: [hCursor] - handle of the cursor used to compare
// [chapt] - chapter of bookmarks
// [bmkFirst] - First bookmark to compare
// [bmkSecond] - Second bookmark to compare
// [rdwComparison] - on return, comparison value
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::Compare( ULONG hCursor, CI_TBL_CHAPT chapt, CI_TBL_BMK bmkFirst, CI_TBL_BMK bmkSecond, DWORD & rdwComparison ) { tbDebugOut(( DEB_PROXY, "Compare\n" ));
CPMCompareBmkIn request( hCursor, chapt, bmkFirst, bmkSecond ); CPMCompareBmkOut reply;
DWORD cbRead; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
rdwComparison = reply.Comparison(); } //Compare
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::GetApproximatePosition, public
//
// Synopsis: Return the approximate current position as a fraction
//
// Arguments: [hCursor] - cursor handle used to retrieve info
// [chapt] - chapter requested
// [bmk] - table bookmark for position
// [pulNumerator] - on return, numerator of fraction
// [pulDenominator] - on return, denominator of fraction
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::GetApproximatePosition( ULONG hCursor, CI_TBL_CHAPT chapt, CI_TBL_BMK bmk, DBCOUNTITEM * pulNumerator, DBCOUNTITEM * pulDenominator ) { tbDebugOut(( DEB_PROXY, "GAP\n" ));
CPMGetApproximatePositionIn request( hCursor, chapt, bmk ); CPMGetApproximatePositionOut reply;
DWORD cbRead; _client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
*pulNumerator = reply.Numerator(); *pulDenominator = reply.Denominator(); } //GetApproximatePosition
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::SetBindings, public
//
// Synopsis: Set column bindings into a cursor
//
// Arguments: [hCursor] - handle of the cursor to set bindings on
// [cbRowLength] - the width of an output row
// [cols] - a description of column bindings to be set
// [pids] - a PID mapper which maps fake pids in cols to
// column IDs.
//
// History: 13 Sept 96 dlee created
// 22 Aug 99 klam Win64 client -> Win32 server
// 09 Feb 2000 KLam Win64: Reset variant size when done
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::SetBindings( ULONG hCursor, ULONG cbRowLength, CTableColumnSet & cols, CPidMapper & pids ) { tbDebugOut(( DEB_PROXY, "SetBindings\n" ));
#ifdef _WIN64
// WIN64 client and servers mark the low bit of the hi-word of the
// version to indicate it is a 64 bit machine.
if ( !_client.IsServer64() ) { tbDebugOut(( DEB_PROXY, "64bit client querying 32bit server!\n" ));
// If there is a PROPVARIANT stored, adjust its size
for (unsigned i = 0; i < cols.Count(); i++) { CTableColumn *pColumn = cols.Get(i); tbDebugOut(( DEB_PROXY, "\tFound type: %d width: %d\n",pColumn->GetStoredType(), pColumn->GetValueSize())); if ( VT_VARIANT == pColumn->GetStoredType() ) { pColumn->SetValueField( VT_VARIANT, pColumn->GetValueOffset(), SizeOfWin32PROPVARIANT );
tbDebugOut(( DEB_PROXY, "\tReplacing variant with size %d and offset 0x%x \n", SizeOfWin32PROPVARIANT, pColumn->GetValueOffset() )); } } }
#endif
// determine the size of the serialized column set
CSizeSerStream stmSize; cols.Marshall( stmSize, pids ); ULONG cbRequest = sizeof CPMSetBindingsIn + stmSize.Size(); cbRequest = AlignBlock( cbRequest, sizeof ULONG );
XArray<BYTE> xIn( cbRequest ); CPMSetBindingsIn *pRequest = new( xIn.Get() ) CPMSetBindingsIn( hCursor, cbRowLength, stmSize.Size() );
// serialize the column set
CMemSerStream stmMem( pRequest->GetDescription(), stmSize.Size() ); cols.Marshall( stmMem, pids );
pRequest->SetCheckSum( cbRequest );
CProxyMessage reply; DWORD cbRead;
_client.DataWriteRead( pRequest, cbRequest, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
#ifdef _WIN64
if ( !IsCi64(_client.GetServerVersion()) ) { tbDebugOut(( DEB_PROXY, "...64bit client finished querying 32bit server.\n" ));
//
// If there is a PROPVARIANT stored, readjust its size back to its original size
//
for (unsigned i = 0; i < cols.Count(); i++) { CTableColumn *pColumn = cols.Get(i); tbDebugOut(( DEB_PROXY, "\tFound type: %d width: %d\n",pColumn->GetStoredType(), pColumn->GetValueSize())); if ( VT_VARIANT == pColumn->GetStoredType() ) { pColumn->SetValueField( VT_VARIANT, pColumn->GetValueOffset(), sizeof ( PROPVARIANT ) );
tbDebugOut(( DEB_PROXY, "\tReseting variant with size %d and offset 0x%x \n", sizeof ( PROPVARIANT ), pColumn->GetValueOffset() )); } } }
#endif
//
// Preserve binding stream if sequential for RestartPosition
//
if ( _fTrueSequential ) { unsigned cElems = xIn.Count(); _xBindings.Set( cElems, xIn.Acquire() ); }
} //SetBindings
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::GetNotifications, public
//
// Synopsis: Gets notification information, when available.
//
// Arguments: [rSync] -- notification synchronization info
// [changeType] -- returns notification data info
//
// Returns: S_OK or STATUS_CANCELLED if rSync's cancel event signalled.
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
SCODE CSvcQueryProxy::GetNotifications( CNotificationSync & rSync, DBWATCHNOTIFY & changeType) { tbDebugOut(( DEB_PROXY, "GetNotifications\n" )); SCODE sc = S_OK;
CProxyMessage request( pmGetNotify ); CPMSendNotifyOut reply(0); DWORD cbReply;
if ( _client.NotifyWriteRead( rSync.GetCancelEvent(), &request, sizeof request, &reply, sizeof reply, cbReply ) ) sc = STATUS_CANCELLED; else changeType = reply.WatchNotify();
tbDebugOut(( DEB_PROXY, "GetNotifications %d, sc %lx\n", changeType, sc )); return sc; } //GetNotifications
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::SetWatchMode
//
// Synopsis: Stub implementation
//
// Arguments: [phRegion] - in/out region handle
// [mode] - watch mode
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::SetWatchMode( HWATCHREGION * phRegion, ULONG mode ) { tbDebugOut (( DEB_PROXY, "Calling SetWatchMode\n" ));
CPMSetWatchModeIn request( *phRegion, mode ); CPMSetWatchModeOut reply; DWORD cbRead;
_client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
*phRegion = reply.Region(); } //SetWatchMode
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::GetWatchInfo
//
// Synopsis: Stub implementation
//
// Arguments: [hRegion] -- handle to watch region
// [pMode] -- watch mode
// [pChapter] -- chapter
// [pBookmark] -- bookmark
// [pcRows] -- number of rows
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::GetWatchInfo ( HWATCHREGION hRegion, ULONG * pMode, CI_TBL_CHAPT * pChapter, CI_TBL_BMK * pBookmark, DBCOUNTITEM * pcRows) { tbDebugOut (( DEB_PROXY, "Calling GetWatchInfo\n" ));
// prepare for failure
*pBookmark = 0; *pChapter = 0; *pMode = 0; *pcRows = 0;
CPMGetWatchInfoIn request( hRegion ); CPMGetWatchInfoOut reply; DWORD cbRead;
_client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
*pMode = reply.Mode(); *pChapter = reply.Chapter(); *pBookmark = reply.Bookmark(); *pcRows = reply.RowCount(); } //GetWatchInfo
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::ShrinkWatchRegion
//
// Synopsis: Stub implementation
//
// Arguments: [hRegion] -- handle to watch region
// [chapter] -- chapter
// [bookmark] -- size of bookmark
// [cRows] -- number of rows
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::ShrinkWatchRegion ( HWATCHREGION hRegion, CI_TBL_CHAPT chapter, CI_TBL_BMK bookmark, LONG cRows ) { tbDebugOut (( DEB_PROXY, " Calling ShrinkWatchRegion\n" ));
CPMShrinkWatchRegionIn request( hRegion, chapter, bookmark, cRows ); CProxyMessage reply; DWORD cbRead;
_client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead ); } //ShrinkWatchRegion
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::Refresh
//
// Synopsis: Stub implementation
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::Refresh() { tbDebugOut(( DEB_PROXY, "Refresh\n" ));
CProxyMessage request( pmRefresh ); CProxyMessage reply; DWORD cbRead;
_client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead ); tbDebugOut(( DEB_PROXY, "Refresh (end)\n" )); } //Refresh
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::GetQueryStatus, public
//
// Synopsis: Return the query status
//
// Arguments: [hCursor] - handle of the cursor to check
// [rdwStatus] - on return, the query status
//
// History: 13 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::GetQueryStatus( ULONG hCursor, DWORD & rdwStatus ) { tbDebugOut(( DEB_PROXY, "GetQueryStatus\n" ));
CPMGetQueryStatusIn request( hCursor ); CPMGetQueryStatusOut reply; DWORD cbRead;
_client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
rdwStatus = reply.QueryStatus(); } //GetQueryStatus
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::GetQueryStatusEx, public
//
// Synopsis: Return the query status plus bonus information. It's kind
// of an odd assortment of info, but it saves net trips.
//
// Arguments: [hCursor] - handle of the cursor to check completion for
// [rdwStatus] - returns the query status
// [rcFilteredDocuments] - returns # of filtered docs
// [rcDocumentsToFilter] - returns # of docs to filter
// [rdwRatioFinishedDenominator] - ratio finished denom
// [rdwRatioFinishedNumerator] - ratio finished num
// [bmk] - bmk to find
// [riRowBmk] - index of bmk row
// [rcRowsTotal] - # of rows in table
//
// History: Nov-9-96 dlee Created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::GetQueryStatusEx( ULONG hCursor, DWORD & rdwStatus, DWORD & rcFilteredDocuments, DWORD & rcDocumentsToFilter, DBCOUNTITEM & rdwRatioFinishedDenominator, DBCOUNTITEM & rdwRatioFinishedNumerator, CI_TBL_BMK bmk, DBCOUNTITEM & riRowBmk, DBCOUNTITEM & rcRowsTotal ) { tbDebugOut(( DEB_PROXY, "GetQueryStatusEx\n" ));
CPMGetQueryStatusExIn request( hCursor, bmk ); CPMGetQueryStatusExOut reply; DWORD cbRead;
_client.DataWriteRead( &request, sizeof request, &reply, sizeof reply, cbRead );
Win4Assert( SUCCEEDED( reply.GetStatus() ) ); Win4Assert( _client.IsPipeTracingEnabled() || sizeof reply == cbRead );
rdwStatus = reply.QueryStatus(); rcFilteredDocuments = reply.FilteredDocuments(); rcDocumentsToFilter = reply.DocumentsToFilter(); rdwRatioFinishedDenominator = reply.RatioFinishedDenominator(); rdwRatioFinishedNumerator = reply.RatioFinishedNumerator(); riRowBmk = reply.RowBmk(); rcRowsTotal = reply.RowsTotal(); } //GetQueryStatusEx
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::FetchDeferredValue, public
//
// Synopsis: Returns a property value for a workid from the property cache
//
// Arguments: [wid] - workid for which property value is retrieved
// [ps]] - prop spec identifying value to be retrieved
// [var] - returns the value if available
//
// Returns: TRUE if a value was retrieved or FALSE otherwise
//
// History: 30 Sept 96 dlee created
//
//--------------------------------------------------------------------------
BOOL CSvcQueryProxy::FetchDeferredValue( WORKID wid, CFullPropSpec const & ps, PROPVARIANT & var ) { tbDebugOut(( DEB_PROXY, "FetchValue\n" )); CLock lock( _mutexFetchValue );
XArray<BYTE> xValue; XArray<BYTE> xResult( cbMaxProxyBuffer );
// cbChunk is the size of the output buffer including CPMFetchValueOut
const DWORD cbChunk = cbMaxProxyBuffer;
// Since the value might be large and each proxy buffer is limited to
// cbMaxProxyBuffer, iterate until the entire value is retrieved.
do { // only send the propspec once
DWORD cbPropSpec = 0; if ( 0 == xValue.SizeOf() ) { CSizeSerStream stmSize; ps.Marshall( stmSize ); cbPropSpec = stmSize.Size(); }
ULONG cbRequest = AlignBlock( sizeof CPMFetchValueIn + cbPropSpec, sizeof ULONG ); XArray<BYTE> xRequest( cbRequest ); CPMFetchValueIn *pRequest = new( xRequest.Get() ) CPMFetchValueIn( wid, xValue.SizeOf(), cbPropSpec, cbChunk );
if ( 0 == xValue.SizeOf() ) { CMemSerStream stmMem( pRequest->GetPS(), cbPropSpec ); ps.Marshall( stmMem ); }
pRequest->SetCheckSum( xRequest.SizeOf() );
DWORD cbReply; _client.DataWriteRead( pRequest, xRequest.SizeOf(), xResult.Get(), xResult.SizeOf(), cbReply ); CPMFetchValueOut &result = * (CPMFetchValueOut *) xResult.Get();
if ( !result.ValueExists() ) return FALSE;
// append the next portion of the value
DWORD cbOld = xValue.SizeOf(); Win4Assert( 0 != result.ValueSize() ); xValue.ReSize( cbOld + result.ValueSize() ); RtlCopyMemory( xValue.Get() + cbOld, result.Value(), result.ValueSize() );
// all done?
if ( !result.MoreExists() ) break; } while ( TRUE );
CCoTaskMemAllocator tbaAlloc;
StgConvertPropertyToVariant( (SERIALIZEDPROPERTYVALUE *) xValue.Get(), CP_WINUNICODE, &var, &tbaAlloc ); Win4Assert( (var.vt & 0x0fff) <= VT_CLSID );
return TRUE; } //FetchValue
//+-------------------------------------------------------------------------
//
// Member: CSvcQueryProxy::WorkIdToPath, public
//
// Synopsis: Converts a wid to a path
//
// Arguments: [wid] -- wid to convert
// [funnyPath] -- resulting path
//
// History: 30 Sept 96 dlee created
//
//--------------------------------------------------------------------------
void CSvcQueryProxy::WorkIdToPath( WORKID wid, CFunnyPath & funnyPath ) { tbDebugOut(( DEB_PROXY, "WorkIdToPath\n" ));
CPMWorkIdToPathIn request( wid ); XArray<WCHAR> xReply( cbMaxProxyBuffer ); CPMWorkIdToPathOut &reply = * (CPMWorkIdToPathOut *) xReply.Get();
DWORD cbRead; _client.DataWriteRead( &request, sizeof request, &reply, cbMaxProxyBuffer, cbRead ); Win4Assert( SUCCEEDED( reply.GetStatus() ) );
if ( reply.Any() ) { funnyPath.SetPath( reply.Path() ); } } //WorkIdToPath
|