Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1684 lines
39 KiB

//+=======================================================================
//
// File: CMoniker.cxx
//
// Purpose: Define the CMoniker class.
//
// This class provides for all handling of monikers in
// the CreateFileMonikerEx DRT. Not only does it maintain
// a file moniker, it also maintains the represented link
// source file, and a bind context.
//
//+=======================================================================
// --------
// Includes
// --------
#define _DCOM_ // Allow DCOM extensions (e.g., CoInitializeEx).
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <wtypes.h>
#include <oaidl.h>
#include <dsys.h>
#include <olecairo.h>
#include "CFMEx.hxx"
#include "CMoniker.hxx"
//+-------------------------------------------------------------------------
//
// Function: CMoniker::CMoniker
//
// Synopsis: Simply initialize all member variables.
//
// Inputs: None.
//
// Outputs: N/A
//
// Effects: Members are defaulted/initialized.
//
//+-------------------------------------------------------------------------
CMoniker::CMoniker()
{
*m_wszSystemTempPath = L'\0';
*m_wszTemporaryStorage = L'\0';
m_pIMoniker = NULL;
m_pIBindCtx = NULL;
m_pIStorage = NULL;
*m_wszErrorMessage = L'\0';
m_dwTrackFlags = 0L;
m_hkeyLinkTracking = NULL;
m_hr = 0L;
m_bSuppressErrorMessages = FALSE;
m_pcDirectoryOriginal = NULL;
m_pcDirectoryFinal = NULL;
return;
} // CMoniker::CMoniker()
//+--------------------------------------------------------------------------
//
// Function: CMoniker::~CMoniker
//
// Synopsis: Release any COM objects.
//
// Inputs: N/A
//
// Outputs: N/A
//
// Effects: All COM objects are released.
//
//+--------------------------------------------------------------------------
CMoniker::~CMoniker()
{
if( m_pIMoniker )
{
m_pIMoniker->Release();
m_pIMoniker = NULL;
}
if( m_pIBindCtx )
{
m_pIBindCtx->Release();
m_pIBindCtx = NULL;
}
if( m_pIStorage )
{
m_pIStorage->Release();
m_pIStorage = NULL;
}
return;
} // CMoniker::~CMoniker()
//+-----------------------------------------------------------------------
//
// Function: CMoniker::Initialize
//
// Synopsis: Keep pointers to the CDirectory objects passed in.
//
// Inputs: A CDirectory object for the original link source file location
// A CDirectory object for the final location
//
// Outputs: TRUE if successful, FALSE otherwise.
//
// Effects: The member CDirectory objects are set.
//
//+-----------------------------------------------------------------------
BOOL CMoniker::Initialize( const CDirectory& cDirectoryOriginal,
const CDirectory& cDirectoryFinal )
{
m_hr = S_OK;
m_pcDirectoryOriginal = &cDirectoryOriginal;
m_pcDirectoryFinal = &cDirectoryFinal;
return( TRUE ); // Success
} // CMoniker::Initialize()
//+-----------------------------------------------------------------------------
//
// Function: CMoniker::CreateFileMonikerEx
//
// Synopsis: Create a tracking file moniker. But before doing so, initialize
// the Bind Context, and create a link source file.
//
// Inputs: Track Flags (from the TRACK_FLAGS defines)
//
// Outputs: TRUE if successful, FALSE otherwise.
//
// Effects: The member bind context is initialized, and a link
// source file is created.
//
//+-----------------------------------------------------------------------------
BOOL CMoniker::CreateFileMonikerEx( DWORD dwTrackFlags )
{
// ---------------
// Local Variables
// ---------------
// Assume failure
BOOL bSuccess = FALSE;
// -----
// Begin
// -----
// Initialize the error code.
m_hr = S_OK;
// Free any existing IMoniker.
if( m_pIMoniker )
{
m_pIMoniker->Release();
m_pIMoniker = NULL;
}
// Initialize the bind context.
if( !InitializeBindContext() )
EXIT( L"Could not initialize the bind context" );
// Create a root storage for use as a link source.
if( !CreateTemporaryStorage() )
EXIT( L"Could not create temporary Storage" );
// Create a tracking File Moniker on that root storage.
m_hr = ::CreateFileMonikerEx( dwTrackFlags, m_wszTemporaryStorage, &m_pIMoniker );
EXIT_ON_FAILED( L"Failed CreateFileMonikerEx" );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
DisplayErrors( bSuccess, L"CMoniker::CreateFileMonikerEx" );
return( bSuccess );
} // CMoniker::CreateFileMonikerEx()
//+---------------------------------------------------------------------
//
// Function: CMoniker::SaveDeleteLoad
//
// Synopsis: This function exercises a moniker's IPersistStream interface.
// It creates saves the member moniker's persistent state to
// a stream, deletes the moniker, and then re-creates it
// using CreateFileMoniker (no Ex, so it's not a tracking
// file moniker). It then re-loads the original moniker's
// persistent state.
//
// Inputs: None.
//
// Outputs: TRUE if successful, FALSE otherwise.
//
// Effects: The member moniker is deleted, re-created, and re-loaded.
//
//+---------------------------------------------------------------------
BOOL CMoniker::SaveDeleteLoad()
{
// ---------------
// Local Variables
// ---------------
// Assume failure
BOOL bSuccess = FALSE;
HRESULT hr = E_FAIL;
IStream* pStream = NULL;
IPersistStream* pIPersistStream = NULL;
LARGE_INTEGER li;
ULARGE_INTEGER uli;
// -----
// Begin
// -----
// Initialize the error code.
m_hr = S_OK;
// Verify that we have a member moniker.
if( !m_pIMoniker )
EXIT( L"Attempt to run SaveDeleteLoad test without an existing file moniker" );
// ------------------------
// Save the moniker's state
// ------------------------
// Get the moniker's IPersistStream interface
m_hr = m_pIMoniker->QueryInterface( IID_IPersistStream, (void **) &pIPersistStream );
EXIT_ON_FAILED( L"Failed 1st IMoniker::QueryInterface(IPersistStream)" );
// Create a stream
hr = CreateStreamOnHGlobal( NULL, // Auto alloc
TRUE, // Delete on release
&pStream );
EXIT_ON_FAILED( L"Failed CreateStreamOnHGlobal()" );
// Save the moniker's state to this stream.
hr = pIPersistStream->Save( pStream, TRUE /* Clear dirty*/ );
EXIT_ON_FAILED( L"Failed IPersistStream::Save()" );
// ------------------
// Delete the moniker
// ------------------
// Release all interfaces for the moniker.
m_pIMoniker->Release();
pIPersistStream->Release();
m_pIMoniker = NULL;
pIPersistStream = NULL;
// --------------------
// Create a new moniker
// --------------------
// Create a new moniker, using the non-Ex version of the function.
m_hr = ::CreateFileMoniker( m_wszTemporaryStorage, &m_pIMoniker );
EXIT_ON_FAILED( L"Failed CreateFileMoniker()" );
// --------------------
// Load the new moniker
// --------------------
// Get the IPersisStream interface
m_hr = m_pIMoniker->QueryInterface( IID_IPersistStream, (void **) &pIPersistStream );
EXIT_ON_FAILED( L"Failed 2nd IMoniker::QueryInterface(IPersistStream)" );
// Re-seek the stream to the beginning.
li.LowPart = li.HighPart = 0L;
hr = pStream->Seek( li, STREAM_SEEK_SET, &uli );
EXIT_ON_FAILED( L"Failed IStream::Seek()" );
if( uli.LowPart || uli.HighPart ) EXIT( L"Incorrect IStream::Seek()" );
// Re-load the moniker from the stream.
m_hr = pIPersistStream->Load( pStream );
EXIT_ON_FAILED( L"Failed IPersistStream::Load()" );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
// Clean up the stream and the IPersistStream interface.
if( pStream )
pStream->Release;
if( pIPersistStream )
pIPersistStream->Release();
DisplayErrors( bSuccess, L"CMoniker::SaveDeleteLoad()" );
return( bSuccess );
} // CMoniker::SaveDeleteLoad()
//+------------------------------------------------------------------
//
// Function: CMoniker::ComposeWith
//
// Synopsis: Compose a tracking moniker with a non-tracking moniker
// on the right. (The resulting moniker should be tracking,
// but this is not relevant to this function; that is, whether
// or not the composed moniker is tracking, this function will
// succeed.)
//
// Inputs: None.
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: The member moniker is deleted, then recreated.
//
//+------------------------------------------------------------------
BOOL CMoniker::ComposeWith()
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
IMoniker* pmkrFirst = NULL;
IMoniker* pmkrSecond = NULL;
HRESULT hr = E_FAIL;
WCHAR wszDirectoryName[ MAX_PATH + sizeof( L'\0' ) ];
WCHAR* wszFileName = NULL;
// -----
// Begin
// -----
// Initiailize the error code.
m_hr = S_OK;
// If we have a moniker already, delete it.
if( m_pIMoniker )
{
m_pIMoniker->Release();
m_pIMoniker = NULL;
}
// Verify we already have a link source file created.
if( !wcslen( m_wszTemporaryStorage ) )
EXIT( L"Attempt to use ComposeWith without first creating a link source.\n" );
// -----------------------------------------------
// Create a tracking and non-tracking file moniker
// -----------------------------------------------
// Parse the storage's filename into a path and a file ...
// for example, "C:\Temp\file.tmp" would become
// "C:\Temp" and "file.tmp".
//
// First, make a copy of the storage's complete path name,
// then replace the last '\\' with a '\0', thus creating two
// strings.
wcscpy( wszDirectoryName, m_wszTemporaryStorage );
wszFileName = wcsrchr( wszDirectoryName, L'\\' );
*wszFileName = L'\0';
wszFileName++;
// Create a tracking file moniker using the directory name.
m_hr = ::CreateFileMonikerEx( 0L, wszDirectoryName, &pmkrFirst );
EXIT_ON_FAILED( L"Failed 1st CreateFileMoniker()" );
// Create a non-tracking file moniker using the file name.
m_hr = ::CreateFileMoniker( wszFileName, &pmkrSecond );
EXIT_ON_FAILED( L"Failed 2nd CreateFileMoniker()" );
// -------
// Compose
// -------
// Compose the directory name moniker (on the left) with the file name moniker
// (on the right). Put the result in the member moniker.
m_hr = pmkrFirst->ComposeWith( pmkrSecond, TRUE, &m_pIMoniker );
EXIT_ON_FAILED( L"Failed IMoniker::ComposeWith" );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
// Clean up the intermediary monikers.
if( pmkrFirst )
pmkrFirst->Release();
if( pmkrSecond )
pmkrSecond->Release();
DisplayErrors( bSuccess, L"CMoniker::ComposeWith()" );
return( bSuccess );
} // CMoniker::ComposeWith()
//+--------------------------------------------------------------------
//
// Function: CMoniker::CreateTemporaryStorage
//
// Synopsis: This function creates a Structured Storage
// in the directory identified by m_cDirectoryOriginal.
// The name of the file is randomly generated by the system,
// but begins with "MKR" and has the extension ".tmp".
//
// Inputs: None.
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: Stores the Structure Storage's name in
// m_wszTemporaryStorageName, and releases m_pIStorage if
// it is currently set.
//
//+--------------------------------------------------------------------
BOOL CMoniker::CreateTemporaryStorage()
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
DWORD dwError = 0L;
UINT nError = 0;
// -----
// Begin
// -----
m_hr = S_OK;
// Delete any existing storage.
if( wcslen( m_wszTemporaryStorage ))
{
if( !DeleteTemporaryStorage() )
EXIT( L"Could not delete the existing temporary storage" );
}
// Generate a temporary filename.
nError = GetTempFileName( m_pcDirectoryOriginal->GetDirectoryName(),
L"MKR", // Prefix string.
0, // Generate random number,
m_wszTemporaryStorage );
if( nError == 0 )
{
m_hr = (HRESULT) GetLastError();
EXIT( L"Failed GetTempFileName()" );
}
// Create a root Storage.
m_hr = StgCreateDocfile( m_wszTemporaryStorage,
STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT,
0L, // Reserved
&m_pIStorage );
EXIT_ON_FAILED( L"Failed StgCreateDocfile()" );
// Release the storage.
m_pIStorage->Release();
m_pIStorage = NULL;
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
DisplayErrors( bSuccess, L"CMoniker::CreateTemporaryStorage()" );
return( bSuccess );
} // CMoniker::CreateTemporaryStorage()
//+-------------------------------------------------------------------------
//
// Function: CMoniker::RenameTemporaryStorage
//
// Synopsis: Rename the link source file (who's name is in m_wszTemporaryStorage)
// to the m_cDirectoryFinal directory, with a new name.
// The current name is "MKR#.tmp" (where "#" is a random number
// generated by the system), and the new name is "RKM#.tmp" (where
// "#" is the same random number). (We must rename the base file
// name, rather than its extension, because otherwise the default
// link-tracking would fail (it would only score the renamed file
// a 32 - by matching the file extension the score is 40.)
//
// Inputs: None.
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: The link source file is renamed, and it's new name is
// put into m_wszTemporaryStorage.
//
//+-------------------------------------------------------------------------
BOOL CMoniker::RenameTemporaryStorage()
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
int nError = 0;
WCHAR wszNewName[ MAX_PATH + sizeof( L'\0' ) ];
WCHAR* wszOldFileName;
WCHAR wszNewFileName[ MAX_PATH + sizeof( L'\0' ) ];
char szOldName[ MAX_PATH + sizeof( L'\0' ) ];
char szNewName[ MAX_PATH + sizeof( L'\0' ) ];
// -----
// Begin
// -----
m_hr = S_OK;
// Verify that we already have a link source created.
if( !wcslen( m_wszTemporaryStorage ))
EXIT( L"No temporary storage to rename." );
// Locate the file name within the complete path.
// (E.g., find the "foo.txt" in "C:\TEMP\foot.txt".)
wszOldFileName = wcsrchr( m_wszTemporaryStorage, L'\\' );
if( !wszOldFileName )
EXIT( L"Could not extract old file name from temporary storage name\n" );
wszOldFileName++; // Get past the '\\'
// Generate the new file name (change "MKR" to "RKM").
wcscpy( wszNewFileName, wszOldFileName );
wszNewFileName[0] = L'R';
wszNewFileName[1] = L'K';
wszNewFileName[2] = L'M';
// Generate the complete path spec of the new file.
wcscpy( wszNewName, m_pcDirectoryFinal->GetDirectoryName() );
wcscat( wszNewName, wszNewFileName );
// Convert the new and old file names to ANSI.
if( m_hr = UnicodeToAnsi( m_wszTemporaryStorage, szOldName, sizeof( szOldName )) )
{
EXIT( L"Could not convert convert Unicode to Ansi for old name" );
}
if( m_hr = UnicodeToAnsi( wszNewName, szNewName, sizeof( szNewName )) )
{
EXIT( L"Could not convert convert Unicode to Ansi for new name" );
}
// Rename the file.
nError = rename( szOldName, szNewName );
if( nError )
{
m_hr = (HRESULT) errno;
EXIT( L"Failed rename()" );
}
// Record the new name.
wcscpy( m_wszTemporaryStorage, wszNewName );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
DisplayErrors( bSuccess, L"CMoniker::RenameTemporaryStorage()" );
return( bSuccess );
} // CMoniker::RenameTemporaryStorage()
//+--------------------------------------------------------------------
//
// Function: CMoniker::DeleteTemporaryStorage
//
// Synopsis: Delete the temporary storage that this object uses
// as a link source for the moniker. The name of the
// storage is in m_wszTemporaryStorage.
//
// Inputs: None.
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: The link source file is deleted, and m_wszTemporaryStorage
// is set to a NULL string.
//
//+--------------------------------------------------------------------
BOOL CMoniker::DeleteTemporaryStorage()
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
int nError = 0;
CHAR szTemporaryStorage[ MAX_PATH + sizeof( '\0' ) ];
// -----
// Begin
// -----
m_hr = S_OK;
// Don't do anything if we have no file (don't report an
// error either; the caller wants the file deleted, and it's
// already not there).
if( wcslen( m_wszTemporaryStorage ))
{
// Get the file name in ANSI.
if( m_hr = UnicodeToAnsi( m_wszTemporaryStorage, szTemporaryStorage, sizeof( szTemporaryStorage )))
EXIT( L"Could not convert unicode path to ANSI path" );
// Delete the file.
nError = unlink( szTemporaryStorage );
if( nError )
{
m_hr = (HRESULT) errno;
EXIT( L"Failed unlink()" );
}
// Clear the file name.
wcscpy( m_wszTemporaryStorage, L"" );
}
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
DisplayErrors( bSuccess, L"CMoniker::DeleteTemporaryStorage()" );
return( bSuccess );
} // CMoniker::DeleteTemporaryStorage()
//+-----------------------------------------------------------------
//
// Function: CMoniker::Reduce
//
// Synopsis: Perform a IMoniker::Reduce on the member moniker.
//
// Inputs: - Number of ticks until the deadline for completion of
// the operation.
// - A buffer into which to put the reduced IMoniker*
// (may be NULL).
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: None.
//
//+-----------------------------------------------------------------
BOOL CMoniker::Reduce( DWORD dwDelay, IMoniker** ppmkReturn )
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
IMoniker* pmkReduced = NULL;
BIND_OPTS2 bind_opts;
bind_opts.cbStruct = sizeof( BIND_OPTS2 );
// -----
// Begin
// -----
m_hr = S_OK;
// ----------
// Initialize
// ----------
// Initialize the return buffer, if extant.
if( ppmkReturn )
*ppmkReturn = NULL;
// Validate our state.
if( !m_pIMoniker )
EXIT( L"No moniker exists to be reduced" );
// ----------------
// Set the deadline
// ----------------
// Get the BIND_OPTS from the bind context.
m_hr = m_pIBindCtx->GetBindOptions( (LPBIND_OPTS) &bind_opts );
EXIT_ON_FAILED( L"Failed IBindCtx::GetBindOptions" );
// Determine what the tick count of the deadline is.
if( dwDelay == INFINITE )
{
bind_opts.dwTickCountDeadline = 0;
}
else
{
bind_opts.dwTickCountDeadline = GetTickCount() + dwDelay;
// Make sure the resulting tick count is not 0 (indicating no
// deadline).
if( bind_opts.dwTickCountDeadline == 0 )
bind_opts.dwTickCountDeadline++;
}
// Put the resulting BIND_OPTS back into the bind context.
m_hr = m_pIBindCtx->SetBindOptions( (LPBIND_OPTS) &bind_opts );
EXIT_ON_FAILED( L"Failed IBindCtx::SetBindOptions" );
// ------------------
// Reduce the Moniker
// ------------------
m_hr = m_pIMoniker->Reduce( m_pIBindCtx,
MKRREDUCE_ALL,
NULL,
&pmkReduced );
EXIT_ON_FAILED( L"Failed IMoniker::Reduce" );
// Return the reduced moniker to the caller (if so requested).
if( ppmkReturn )
{
// Transfer responsibility for the release to the caller.
*ppmkReturn = pmkReduced;
pmkReduced = NULL;
}
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
DisplayErrors( bSuccess, L"CMoniker::Reduce()" );
if( pmkReduced )
pmkReduced->Release();
return( bSuccess );
} // CMoniker::Reduce()
//+----------------------------------------------------------------------
//
// Function: CMoniker::GetDisplayName
//
// Synopsis: Get the moniker's display name.
//
// Inputs: A Unicode buffer for the display name, and (optionally)
// a moniker from which to get the display name. If such
// a moniker is not provided by the caller, then the member
// moniker is used.
//
// The unicode buffer must be long enough for MAX_PATH characters
// and a terminating NULL.
//
// Outputs: TRUE if successful, FALSE otherwise.
//
// Effects: None.
//
//+----------------------------------------------------------------------
BOOL CMoniker::GetDisplayName( WCHAR * wszDisplayName, IMoniker* pmnkCaller )
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
WCHAR* wszReturnedDisplayName = NULL;
IMoniker* pmnk = NULL;
// -----
// Begin
// -----
m_hr = NOERROR;
// Determine which moniker to use, the caller-specified one or
// the member one.
if( pmnkCaller != NULL )
pmnk = pmnkCaller;
else
pmnk = m_pIMoniker;
if( !pmnk )
EXIT( L"Attempt to GetDisplayName on NULL moniker" );
// Get the display name from the moniker.
m_hr = pmnk->GetDisplayName( m_pIBindCtx,
NULL,
&wszReturnedDisplayName );
EXIT_ON_FAILED( L"Failed IMoniker::GetDisplayName()" );
if( wcslen( wszReturnedDisplayName ) > MAX_UNICODE_PATH )
EXIT( L"IMoniker::GetDisplayName() returned a path which was too long" );
// Copy the display name into the caller's buffer, and free it.
wcscpy( wszDisplayName, wszReturnedDisplayName );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
if( wszReturnedDisplayName )
{
CoTaskMemFree( wszReturnedDisplayName );
wszReturnedDisplayName = NULL;
}
DisplayErrors( bSuccess, L"CMoniker::GetDisplayName()" );
return( bSuccess );
} // CMoniker::GetDisplayName()
//+-------------------------------------------------------------
//
// Function: CMoniker::InitializeBindContext
//
// Synopsis: Create a new bind context, and store it
// in a member pointer.
//
// Inputs: None.
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: Updates m_pIBindCtx.
//
//+-------------------------------------------------------------
BOOL CMoniker::InitializeBindContext( )
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
// -----
// Begin
// -----
m_hr = S_OK;
// Release the old bind context if we have one.
if( m_pIBindCtx )
m_pIBindCtx->Release();
// Create the new bind context.
m_hr = CreateBindCtx( 0L, &m_pIBindCtx );
EXIT_ON_FAILED( L"Failed CreateBindCtx()" );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
DisplayErrors( bSuccess, L"CMoniker::InitializeBindContext()" );
return( bSuccess );
} // CMoniker::InitializeBindContext()
//+----------------------------------------------------------------
//
// Function: CMoniker::GetTimeOfLastChange
//
// Synopsis: Request the time-of-last-change from our member
// moniker.
//
// Inputs: A buffer into which to put the FILETIME.
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: None.
//
//+----------------------------------------------------------------
BOOL CMoniker::GetTimeOfLastChange( FILETIME* pft )
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
// -----
// Begin
// -----
m_hr = S_OK;
// Validate our state.
if( !m_pIMoniker )
EXIT( L"Cannot GetTimeOfLastChange on a NULL moniker" );
// Get the time from the moniker.
m_hr = m_pIMoniker->GetTimeOfLastChange( m_pIBindCtx,
NULL,
pft );
EXIT_ON_FAILED( L"Failed IMoniker::GetTimeOfLastChange()" );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
DisplayErrors( bSuccess, L"CMoniker::GetTimeOfLastChange()" );
return( bSuccess );
} // CMoniker::GetTimeOfLastChange()
//+------------------------------------------------------------------------
//
// Function: CMoniker::BindToStorage
//
// Synopsis: Bind our member moniker to its Structured Storage object.
//
// Inputs: None.
//
// Outputs: TRUE if successful, FALSE otherwise.
//
// Effects: None.
//
//+------------------------------------------------------------------------
BOOL CMoniker::BindToStorage()
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
BIND_OPTS2 bind_opts;
bind_opts.cbStruct = sizeof( BIND_OPTS2 );
// -----
// Begin
// -----
m_hr = S_OK;
// Validate our state.
if( !m_pIMoniker )
EXIT( L"Cannot GetTimeOfLastChange on a NULL moniker" );
// Release the IStorage interface if we have one.
if( m_pIStorage )
{
m_pIStorage->Release();
m_pIStorage = NULL;
}
// Get the bind_opts and set the flags for StgOpenStorage.
m_hr = m_pIBindCtx->GetBindOptions( (LPBIND_OPTS) &bind_opts );
EXIT_ON_FAILED( L"Failed IBindCtx::GetBindOptions" );
bind_opts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT;
m_hr = m_pIBindCtx->SetBindOptions( (LPBIND_OPTS) &bind_opts );
EXIT_ON_FAILED( L"Failed IBindCtx::SetBindOptions" );
// Bind to the storage.
m_hr = m_pIMoniker->BindToStorage( m_pIBindCtx,
NULL,
IID_IStorage,
(void **) &m_pIStorage );
EXIT_ON_FAILED( L"Failed IMoniker::BindToStorage()" );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
// Release the Storage if we got it.
if( m_pIStorage )
{
m_pIStorage->Release();
m_pIStorage = NULL;
}
DisplayErrors( bSuccess, L"CMoniker::BindToStorage()" );
return( bSuccess );
} // CMoniker::BindToStorage()
//+-------------------------------------------------------------------
//
// Function: CMoniker::BindToObject
//
// Synopsis: Bind to our member moniker's object.
//
// Inputs: None.
//
// Outputs: TRUE if successful, FALSE otherwise.
//
// Effects: None.
//
// Notes: Since the member moniker represents a storage with no
// associated server, BindToObject will fail. We will
// consider it a success if the failure is do to an
// object-related problem, rather than a Storage-related
// problem.
//
//+-------------------------------------------------------------------
BOOL CMoniker::BindToObject()
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
IUnknown* pUnk = NULL;
// -----
// Begin
// -----
m_hr = S_OK;
// Validate our state.
if( !m_pIMoniker )
EXIT( L"Cannot bind to an object with a NULL moniker" );
// Bind to the object.
m_hr = m_pIMoniker->BindToObject( m_pIBindCtx,
NULL,
IID_IUnknown,
(void **) &pUnk );
// If the bind succeeded, or failed for a valid reason,
// then return Success to the caller.
if( SUCCEEDED( m_hr )
||
( m_hr = MK_E_INVALIDEXTENSION ) // No handler for ".tmp" files.
)
{
bSuccess = TRUE;
}
else
{
EXIT( L"Failed BindToObject" );
}
// ----
// Exit
// ----
Exit:
// If we got an IUnknown interface on the Bind, release it.
if( pUnk )
{
pUnk->Release();
pUnk = NULL;
}
DisplayErrors( bSuccess, L"CMoniker::BindToObject()" );
return( bSuccess );
} // CMoniker::BindToObject()
//+-------------------------------------------------------------------
//
// Function: CMoniker::GetTemporaryStorageTime
//
// Synopsis: Get the time from the link source file
// (identified by m_wszTemporaryStorage).
//
// Inputs: A buffer in which to put the FILETIME structure.
//
// Outputs: TRUE if successful, FALSE otherwise.
//
// Effects: None.
//
//+-------------------------------------------------------------------
BOOL CMoniker::GetTemporaryStorageTime( FILETIME * pft)
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
HANDLE hFile = NULL;
// -----
// Begin
// -----
m_hr = NOERROR;
// Get a handle to the file.
hFile = CreateFile( m_wszTemporaryStorage, // File name
GENERIC_READ, // Desired access
FILE_SHARE_READ, // Share mode
NULL, // Security attributes
OPEN_EXISTING, // Creation distribution
0L, // Flags & Attributes
NULL ); // hTemplateFile
if( hFile == NULL )
{
m_hr = (HRESULT) GetLastError();
EXIT( L"Failed call to CreateFile()" );
}
// Get the time on the file.
if( !GetFileTime( hFile, // File to check
NULL, // Create Time
NULL, // Access Time
pft ) // Write Time
)
{
m_hr = (HRESULT) GetLastError();
EXIT( L"Failed call to GetFileTime()" );
}
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
// Close the file if we opened it.
if( hFile )
{
CloseHandle( hFile );
hFile = NULL;
}
DisplayErrors( bSuccess, L"CMoniker::GetTemporaryStorageTime()" );
return( bSuccess );
} // CMoniker::GetTemporaryStorageTime()
//+------------------------------------------------------------------------
//
// Function: CMoniker::TouchTemporaryStorage
//
// Synopsis: Set the Access time on the link source file.
//
// Inputs: None.
//
// Output: TRUE if successful, FALSE otherwise.
//
// Effects: The link source file (identified by m_wszTemporaryStorage)
// has its Access time set to the current time.
//
//+------------------------------------------------------------------------
BOOL CMoniker::TouchTemporaryStorage( )
{
// ---------------
// Local Variables
// ---------------
BOOL bSuccess = FALSE;
HANDLE hFile = NULL;
STATSTG statStorage;
FILETIME ftNow;
// -----
// Begin
// -----
m_hr = NOERROR;
// Open the root Storage.
m_hr = StgOpenStorage( m_wszTemporaryStorage,
NULL,
STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT,
NULL,
0L,
&m_pIStorage );
EXIT_ON_FAILED( L"Failed StgOpenStorage()" );
// Get the current time.
m_hr = CoFileTimeNow( &ftNow );
EXIT_ON_FAILED( L"Failed CoFileTimeNow()" );
// Set the access time
m_pIStorage->SetElementTimes( NULL, // Set the storage itself
NULL, // Create time
NULL, // Access time
&ftNow );
EXIT_ON_FAILED( L"Failed IStorage::SetTimes()" );
bSuccess = TRUE;
// ----
// Exit
// ----
Exit:
// If we got the storage, release it.
if( m_pIStorage )
{
m_pIStorage->Release();
m_pIStorage = NULL;
}
DisplayErrors( bSuccess, L"CMoniker::TouchTemporaryStorage()" );
return( bSuccess );
} // CMoniker::TouchTemporaryStorage()
#ifdef _FUTURE_
/*
BOOL CMoniker::OpenLinkTrackingRegistryKey()
{
BOOL bSuccess = FALSE;
DWORD dwDisposition = 0L;
long lResult = 0L;
m_hr = S_OK;
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
OLETRACKING_KEY,
0L,
KEY_ALL_ACCESS,
&m_hkeyLinkTracking
);
if( lResult != ERROR_SUCCESS
&&
lResult != ERROR_FILE_NOT_FOUND
)
{
m_hr = (HRESULT) lResult;
EXIT( L"Failed RegOpenKeyEx()" );
}
bSuccess = TRUE;
Exit:
DisplayErrors( bSuccess, L"CMoniker::OpenLinkTrackingRegistryKey()" );
return( bSuccess );
} // CMoniker::OpenLinkTrackingRegistryKey()
BOOL CMoniker::CreateLinkTrackingRegistryKey()
{
BOOL bSuccess = FALSE;
HKEY hkey = NULL;
DWORD dwDisposition = 0L;
long lResult = 0L;
m_hr = S_OK;
if( m_hkeyLinkTracking )
CloseLinkTrackingRegistryKey();
lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
OLETRACKING_KEY,
0L,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&m_hkeyLinkTracking,
&dwDisposition
);
if( lResult != ERROR_SUCCESS )
{
m_hr = (HRESULT) lResult;
EXIT( L"Failed RegCreateKeyEx()" );
}
bSuccess = TRUE;
Exit:
DisplayErrors( bSuccess, L"CMoniker::CreateLinkTrackingRegistryKey()" );
return( bSuccess );
} // CMoniker::CreateLinkTrackingRegistryKey()
BOOL CMoniker::CloseLinkTrackingRegistryKey()
{
m_hr = S_OK;
if( m_hkeyLinkTracking )
RegCloseKey( m_hkeyLinkTracking );
m_hkeyLinkTracking = NULL;
return TRUE;
} // CMoniker::CloseLinkTrackingRegistryKey()
BOOL CMoniker::SaveRegistryTrackFlags()
{
BOOL bSuccess = FALSE;
long lResult = 0L;
DWORD dwType = 0L;
DWORD dwcbData = sizeof( m_dwTrackFlags );
m_hr = S_OK;
if( !OpenLinkTrackingRegistryKey() )
EXIT( L"Could not open the registry" );
lResult = RegQueryValueEx( m_hkeyLinkTracking,
OLETRACKING_FILEMONIKER_VALUE,
NULL,
&dwType,
(LPBYTE) &m_dwTrackFlags,
&dwcbData );
if( lResult != ERROR_SUCCESS )
{
CloseLinkTrackingRegistryKey();
if( lResult != ERROR_FILE_NOT_FOUND )
{
m_hr = (HRESULT) lResult;
EXIT( L"Failed RegQueryValueEx()" );
}
}
bSuccess = TRUE;
Exit:
DisplayErrors( bSuccess, L"CMoniker::SaveRegistryTrackFlags()" );
return( bSuccess );
} // CMoniker::SaveRegistryTrackFlags()
BOOL CMoniker::DeleteRegistryTrackFlags()
{
BOOL bSuccess = FALSE;
long lResult = 0L;
DWORD dwType = 0L;
DWORD dwcbData = sizeof( m_dwTrackFlags );
m_hr = S_OK;
if( !CreateLinkTrackingRegistryKey() )
EXIT( L"Could not open the registry" );
lResult = RegDeleteValue( m_hkeyLinkTracking,
OLETRACKING_FILEMONIKER_VALUE );
if( lResult != ERROR_SUCCESS
&&
lResult != ERROR_FILE_NOT_FOUND
)
{
if( lResult != ERROR_FILE_NOT_FOUND )
{
m_hr = (HRESULT) lResult;
EXIT( L"Failed RegDeleteValue()" );
}
}
bSuccess = TRUE;
Exit:
CloseLinkTrackingRegistryKey();
DisplayErrors( bSuccess, L"CMoniker::DeleteRegistryTrackFlags()" );
return( bSuccess );
} // CMoniker::DeleteRegistryTrackFlags()
BOOL CMoniker::RestoreRegistryTrackFlags()
{
BOOL bSuccess = FALSE;
long lResult = 0L;
m_hr = S_OK;
// If the registry key doesn't exist, then there's no flags
// to restore.
if( m_hkeyLinkTracking )
{
lResult = RegSetValueEx( m_hkeyLinkTracking,
OLETRACKING_FILEMONIKER_VALUE,
0L,
REG_DWORD,
(LPBYTE) &m_dwTrackFlags,
sizeof( m_dwTrackFlags )
);
if( lResult != ERROR_SUCCESS )
{
m_hr = (HRESULT) lResult;
EXIT( L"Failed RegSetValueEx()" );
}
CloseLinkTrackingRegistryKey();
}
bSuccess = TRUE;
Exit:
DisplayErrors( bSuccess, L"CMoniker::RestoreRegistryTrackFlags()" );
return( bSuccess );
} // CMoniker::RestoreRegistryTrackFlags()
CMoniker::SetTrackFlagsInRegistry( DWORD dwTrackFlags )
{
BOOL bSuccess = FALSE;
long lResult = 0L;
HKEY hkey = NULL;
m_hr = S_OK;
if( !CreateLinkTrackingRegistryKey() )
EXIT( L"Could not create registry key" );
lResult = RegSetValueEx( m_hkeyLinkTracking,
OLETRACKING_FILEMONIKER_VALUE,
0L,
REG_DWORD,
(LPBYTE) &dwTrackFlags,
sizeof( dwTrackFlags )
);
if( lResult != ERROR_SUCCESS )
{
m_hr = (HRESULT) lResult;
EXIT( L"Failed RegSetValueEx()" );
}
bSuccess = TRUE;
Exit:
DisplayErrors( bSuccess, L"CMoniker::SetTrackFlagsInRegistry()" );
return( bSuccess );
} // CMoniker::SetTrackFlagsInRegistry()
BOOL CMoniker::CreateFileMoniker()
{
BOOL bSuccess = FALSE;
m_hr = S_OK;
// Free any existing IMoniker.
if( m_pIMoniker )
{
m_pIMoniker->Release();
m_pIMoniker = NULL;
}
// Create a root storage.
if( !CreateTemporaryStorage() )
EXIT( L"Could not create a temporary storage" );
// Create a default File Moniker on that root storage.
m_hr = ::CreateFileMoniker( m_wszTemporaryStorage, &m_pIMoniker );
EXIT_ON_FAILED( L"Failed CreateFileMoniker" );
bSuccess = TRUE;
Exit:
DisplayErrors( bSuccess, L"CMoniker::CreateFileMoniker" );
return( bSuccess );
} // CMoniker::CreateFileMoniker()
*/
#endif // _FUTURE_