|
|
#include <pch.cxx>
#pragma hdrstop
#define TRKDATA_ALLOCATE
#include "trkcom.hxx"
#include "trklib.hxx"
#if !defined(_UNICODE) || defined(OLE2ANSI)
#error This ILinkTrack implementation is only compatible on a Unicode build
#endif
//+----------------------------------------------------------------------------
//
// Method: CTrackFile/~CTrackFile
//
// Synopsis: Construction/Destruction
//
// Arguments: None
//
// Returns: None
//
//+----------------------------------------------------------------------------
CTrackFile::CTrackFile() { _cRefs = 0; _fDirty = FALSE; _fLoaded = FALSE; memset( &_PersistentState, 0, sizeof(_PersistentState) ); }
CTrackFile::~CTrackFile() { }
//+----------------------------------------------------------------------------
//
// Method: IUnknown methods
//
// Synopsis: IUnknown
//
//+----------------------------------------------------------------------------
ULONG CTrackFile::AddRef() { long cNew; cNew = InterlockedIncrement( &_cRefs ); return( cNew ); }
ULONG CTrackFile::Release() { long cNew; cNew = InterlockedDecrement( &_cRefs ); if( 0 == cNew ) delete this;
return( cNew >= 0 ? cNew : 0 ); }
HRESULT CTrackFile::QueryInterface( REFIID iid, void ** ppvObject ) { HRESULT hr = E_NOINTERFACE;
// Parameter validation
if( NULL == ppvObject ) { hr = E_INVALIDARG; goto Exit; }
*ppvObject = NULL;
if( IID_IUnknown == iid || IID_ITrackFile == iid ) { AddRef(); *ppvObject = (void*) (IUnknown*) (ITrackFile*) this; hr = S_OK; } else if( IID_ITrackFileRestricted == iid ) { AddRef(); *ppvObject = (void*) (ITrackFileRestricted*) this; hr = S_OK; } else if( IID_IPersistMemory == iid ) { AddRef(); *ppvObject = (void*) (IPersistMemory*) this; hr = S_OK; } else if( IID_IPersistStreamInit == iid ) { AddRef(); *ppvObject = (void*) (IPersistStreamInit*) this; hr = S_OK; }
Exit:
return( hr );
}
//+----------------------------------------------------------------------------
//
// Method: CreateFromPath (ITrack*)
//
// Synopsis: Create a link client for a link source file.
//
// Arguments: [poszPath] (in)
// The file to which to link.
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
HRESULT CTrackFile::CreateFromPath( const OLECHAR * poszPath ) { HRESULT hr = S_OK; NTSTATUS status = STATUS_SUCCESS; CDomainRelativeObjId droidCurrent, droidBirth;
// Parameter validation
if( NULL == poszPath ) { hr = E_INVALIDARG; goto Exit; }
__try { status = GetDroids( poszPath, &droidCurrent, &droidBirth, RGO_GET_OBJECTID ); if( !NT_SUCCESS(status) ) { hr = HRESULT_FROM_NT(status); goto Exit; } } __except( BreakOnDebuggableException() ) { hr = GetExceptionCode(); } if( FAILED(hr) ) goto Exit;
_fLoaded = FALSE; InitNew();
_fDirty = TRUE; _PersistentState.droidCurrent = droidCurrent; _PersistentState.droidBirth = droidBirth;
Exit:
if( SUCCEEDED(hr) ) TrkLog(( TRKDBG_CREATE, TEXT("Link created to %s"), poszPath ));
hr = MapTR2HR( hr );
return( hr ); }
//+----------------------------------------------------------------------------
//
// Method: Resolve (ITrack*)
//
// Synopsis: Determine the current path of a link source.
//
// Arguments: [pcbPath] (in/out)
// In: The size of the poszPath buffer
// Out: The actual path length (including the null terminator)
// [poszPath] (out)
// The link source's current path.
// [dwMillisecondTimeout] (in)
// A suggestion as to when this method should give up
// and return if it hasn't yet found the file.
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
// BUGBUG P1: Optionally return the GetFileAttributesEx info, so that the
// shell doesn't have to re-open the file.
HRESULT CTrackFile::Resolve( DWORD *pcbPath, OLECHAR * poszPath, DWORD dwMillisecondTimeout ) { return( Resolve( pcbPath, poszPath, dwMillisecondTimeout, TRK_MEND_DEFAULT )); }
HRESULT CTrackFile::Resolve( DWORD *pcbPath, OLECHAR * poszPath, DWORD dwMillisecondTimeout, DWORD Restrictions ) { HRESULT hr = E_FAIL; CMachineId mcidLocal( MCID_LOCAL ); CRpcClientBinding rc; CDomainRelativeObjId droidNew; CDomainRelativeObjId droidBirth; CDomainRelativeObjId droidCurrent; OLECHAR oszPathActual[ MAX_PATH + 1 ]; DWORD cbPathActual = 0; CFILETIME cftDue;
// Parameter validation
if( NULL == pcbPath || NULL == poszPath ) { hr = E_INVALIDARG; goto Exit; } else if( !_fLoaded ) { hr = E_UNEXPECTED; goto Exit; }
__try { cftDue.IncrementMilliseconds( dwMillisecondTimeout );
droidBirth = _PersistentState.droidBirth; droidCurrent = _PersistentState.droidCurrent;
rc.RcInitialize( mcidLocal, s_tszTrkWksLocalRpcProtocol, s_tszTrkWksLocalRpcEndPoint );
RpcTryExcept { CMachineId mcidLast, mcidCurrent; ULONG cbFileName = (MAX_PATH + 1) * sizeof(TCHAR); CDomainRelativeObjId droidBirthNew;
hr = LnkMendLink( rc, cftDue, Restrictions, &droidBirth, &droidCurrent, &mcidLast, &droidBirthNew, &droidNew, &mcidCurrent, &cbFileName, oszPathActual ); } RpcExcept( BreakOnDebuggableException() ) { hr = HRESULT_FROM_WIN32( RpcExceptionCode() ); } RpcEndExcept;
if( FAILED(hr) ) goto Exit;
// Compare droidBirth and droidCurrent with the ones in _PersistentState.
// If the same, do not set _fDirty.
if(droidBirth != _PersistentState.droidBirth) { _PersistentState.droidBirth = droidBirth; _fDirty = TRUE; } if(droidNew != _PersistentState.droidCurrent) { _PersistentState.droidCurrent = droidNew; _fDirty = TRUE; }
cbPathActual = ( ocslen(oszPathActual) + 1 ) * sizeof(OLECHAR); if( cbPathActual > *pcbPath ) hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); else ocscpy( poszPath, oszPathActual );
*pcbPath = cbPathActual; if( FAILED(hr) ) goto Exit; } __except( EXCEPTION_EXECUTE_HANDLER ) { hr = GetExceptionCode(); goto Exit; }
Exit:
return( hr );
}
//+----------------------------------------------------------------------------
//
// Method: Open (ITrackFile)
//
// Synopsis: Open the referent file ensure that its object ID is
// correct. If the object ID is not correct, or the
// file could not be found, then perform a Resolve.
//
// Arguments: [pcbPathHint] (in/out)
// In: The size of the poszPathHint buffer
// Out: The actual path length (including the null terminator)
// [poszPathHint] (in/out)
// The suggested path to the file. If the path turns out not
// to be correct, an updated path is returned.
// [dwMillisecondTimeout] (in)
// A suggestion as to when this method should give up
// and return if it hasn't yet found the file.
// [dwDesiredAccess] (in)
// Access mode for the open file (see Win32 CreateFile)
// [dwShareMode] (in)
// Sharing for the open file (see Win32 CreateFile)
// [dwFlags] (in)
// Specifies the flags for the file (see the FILE_FLAG_*
// values in the Win32 CreateFile).
// [phFile] (out)
// The open file handle. It is because of this parameter
// That the ITrackFile interface is [local].
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::Open( /*in, out*/ DWORD * pcbPathHint, /*in, out, size_is(*pcbPathHint), string*/ OLECHAR * poszPathHint, /*in*/ DWORD dwMillisecondTimeout, /*in*/ DWORD dwDesiredAccess, // access (read-write) mode
/*in*/ DWORD dwShareMode, // share mode
/*in*/ DWORD dwFlags, /*out*/ HANDLE * phFile ) { return E_NOTIMPL;
/*
HRESULT hr = S_OK; BOOL fTimeout = TRUE; NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = INVALID_HANDLE_VALUE; FILE_OBJECTID_BUFFER fobOID; IO_STATUS_BLOCK Iosb; CObjId cobjidFile; DWORD dwTickCountTimeout, dwTickCountNow;
// ----------
// Initialize
// ----------
*phFile = INVALID_HANDLE_VALUE;
// Ensure we have an ObjectID to check against.
if( !_fLoaded ) { hr = E_UNEXPECTED; goto Exit; }
// Calculate the absolute deadline.
dwTickCountNow = GetTickCount(); dwTickCountTimeout = dwTickCountNow + dwMillisecondTimeout; if( dwTickCountTimeout < dwTickCountNow ) { // Bad dwMillisecondTimeout value
hr = E_INVALIDARG; goto Exit; }
// -------------
// Open the File
// -------------
do { // Open the file
hFile = CreateFile( poszPathHint, dwDesiredAccess, dwShareMode, NULL, OPEN_EXISTING, dwFlags, NULL ); if( INVALID_HANDLE_VALUE == hFile ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Exit; }
// Get the object ID
status = NtFsControlFile( hFile, NULL, NULL, NULL, &Iosb, FSCTL_GET_OBJECT_ID, NULL, // In buffer
0, // In buffer size
&fobOID, // Out buffer
sizeof(fobOID) ); // Out buffer size
if( !NT_SUCCESS(status) ) { hr = HRESULT_FROM_NT( status ); goto Exit; }
// Verify the object ID
cobjidFile.Load( fobOID, LINK_TYPE_FILE );
if( cobjidFile == _PersistentState.droidCurrent.GetObjId() ) { // We found a good file and we're done.
fTimeout = FALSE; break; } else { // Try to find the correct file.
hr = Resolve( pcbPathHint, poszPathHint, dwTickCountTimeout - GetTickCount() ); if( FAILED(hr) ) goto Exit; } } while( GetTickCount() < dwTickCountTimeout );
// Did the previous loop end because of a timeout?
if( fTimeout ) { hr = HRESULT_FROM_WIN32( ERROR_TIMEOUT ); goto Exit; }
// We completed successfully.
*phFile = hFile; hFile = INVALID_HANDLE_VALUE; hr = S_OK;
// ----
// Exit
// ----
Exit:
if( INVALID_HANDLE_VALUE != hFile ) CloseHandle( hFile );
return( hr ); */ } // CTrackFile::Open()
//+----------------------------------------------------------------------------
//
// Method: GetClassID (IPersistMemory & IPersistStreamInit)
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::GetClassID( CLSID *pClassID ) { if(NULL == pClassID) { return E_POINTER; } *pClassID = IID_ITrackFile; return( S_OK ); }
//+----------------------------------------------------------------------------
//
// Method: IsDirty (IPersistMemory & IPersistStreamInit)
//
// Returns: HRESULT
// S_OK => Dirty, S_FALSE => clean
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::IsDirty() { return( _fDirty ? S_OK : S_FALSE ); }
//+----------------------------------------------------------------------------
//
// Method: Load (IPersistMemory)
//
// Synopsis: Load the TrackFile object from persistent state.
//
// Arguments: [pvMem]
// Points to the serialization buffer.
// [cbSize]
// Size of the serialization buffer.
//
// Returns: None
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::Load( void * pvMem, ULONG cbSize ) { LinkTrackPersistentState PersistentState;
if( NULL == pvMem ) return( E_POINTER );
else if( _fLoaded ) return( E_UNEXPECTED );
else if( sizeof(_PersistentState) > cbSize ) return( E_INVALIDARG );
else if( ( (LinkTrackPersistentState*) pvMem )->clsid != IID_ITrackFile ) return( E_INVALIDARG );
else if( ( (LinkTrackPersistentState*) pvMem )->cbSize < sizeof(_PersistentState) ) return( E_INVALIDARG );
else { _PersistentState = *(LinkTrackPersistentState*) pvMem; _fLoaded = TRUE; return( S_OK ); } }
//+----------------------------------------------------------------------------
//
// Method: Save(IPersistMemory)
//
// Synopsis: Save the persistent state to a memory buffer.
//
// Arguments: [pvMem]
// The buffer to which we'll save.
// [fClearDirty]
// TRUE => we'll set _fDirty to FALSE on a successful save.
// [cbSize]
// The available buffer in pvMem.
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::Save( void* pvMem, BOOL fClearDirty, ULONG cbSize ) { if( NULL == pvMem ) return( E_POINTER );
else if( !_fLoaded ) return( E_UNEXPECTED );
else if( sizeof(_PersistentState) > cbSize ) return( E_INVALIDARG );
else { *(LinkTrackPersistentState*) pvMem = _PersistentState;
if( fClearDirty ) _fDirty = FALSE;
return( S_OK ); } }
//+----------------------------------------------------------------------------
//
// Method: InitNew
//
// Synopsis: Initialize the TrackFile object.
//
// Arguments: None
//
// Returns: None
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::InitNew() { if( _fLoaded ) return( E_UNEXPECTED ); else { memset( &_PersistentState, 0, sizeof(_PersistentState) ); _PersistentState.cbSize = sizeof(_PersistentState); _PersistentState.clsid = IID_ITrackFile; _fLoaded = TRUE; return( S_OK ); } }
//+----------------------------------------------------------------------------
//
// Method: GetSizeMax (IPersistMemory)
//
// Synopsis: Returns the size necessary to pass to IPersist:Save
//
// Arguments: [pcbSize]
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::GetSizeMax( ULONG *pcbSize ) { if( NULL == pcbSize ) return( E_POINTER ); else { *pcbSize = sizeof(_PersistentState); return( S_OK ); } }
//+----------------------------------------------------------------------------
//
// Method: GetSizeMax (IPersistStreamInit)
//
// Synopsis: Returns the size necessary.
//
// Arguments: [pcbSize]
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::GetSizeMax( ULARGE_INTEGER* pcbSize ) { if( NULL == pcbSize ) return( E_POINTER ); else { pcbSize->QuadPart = sizeof(_PersistentState); return( S_OK ); } }
//+----------------------------------------------------------------------------
//
// Method: Load (IPersistStreamInit)
//
// Synopsis: Load the TrackFile object from a stream.
//
// Arguments: [pStm]
// Points to the IStream interface.
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::Load(IStream* pStm) { HRESULT hr; // return value
LinkTrackPersistentState PersistentState; // tmp storage
ULONG cbRead; // # of bytes read
LARGE_INTEGER cbOffset; // = -cbRead
ULONG cbSize = sizeof(_PersistentState);
if(NULL == pStm) return(E_POINTER);
else if(_fLoaded) return(E_UNEXPECTED);
// Read _PersistentState from the stream and check if the read is
// successful. If not, revert back the seek pointer in pStm, and
// return the HRESULT.
hr = pStm->Read((byte*)&PersistentState, cbSize, &cbRead); if(FAILED(hr) || cbSize != cbRead) { cbOffset.QuadPart = -static_cast<LONGLONG>(cbRead); goto Exit; }
// So now we successfully read the _PersistentState into memory, check to
// see if we read garbage. If so, revert and return the error.
// xxx What error message should be returned for this?
if(PersistentState.clsid != IID_ITrackFile) { cbOffset.QuadPart = -static_cast<LONGLONG>(cbRead); hr = E_FAIL; goto Exit; }
// Everything went well. Now we can copy _PersistentState from its
// temporary storage to its real storage.
_PersistentState = PersistentState; _fLoaded = TRUE; return(S_OK);
Exit: pStm->Seek(cbOffset, STREAM_SEEK_CUR, NULL); return(hr); }
//+----------------------------------------------------------------------------
//
// Method: Save (IPersistStreamInit)
//
// Synopsis: Save the persistent state to a stream.
//
// Arguments: [pStm]
// The IStream interface we use to save.
// [fClearDirty]
// TRUE => we'll set _fDirty to FALSE on a successful save.
//
// Returns: HRESULT
//
//+----------------------------------------------------------------------------
STDMETHODIMP CTrackFile::Save(IStream* pStm, BOOL fClearDirty) { HRESULT hr; ULONG cbSize = sizeof(_PersistentState); ULONG cbWritten; // # of bytes written
LARGE_INTEGER cbOffset; // same as cbWritten
if(NULL == pStm) return(E_POINTER);
else if( !_fLoaded ) return(E_UNEXPECTED);
else { // Write the _PersistentState to the stream and check the return value.
// If failed, revert the changes in IStream and return the HRESULT.
hr = pStm->Write((byte*)&_PersistentState, cbSize, &cbWritten); if(FAILED(hr)) { cbOffset.QuadPart = -static_cast<LONGLONG>(cbWritten); pStm->Seek(cbOffset, STREAM_SEEK_CUR, NULL); return hr; }
if(fClearDirty) _fDirty = FALSE;
return(S_OK); } }
|