1368 lines
43 KiB
C++
1368 lines
43 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
|