From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/oleutest/cfmex/cdir.cxx | 418 +++++++++ private/oleutest/cfmex/cdir.hxx | 161 ++++ private/oleutest/cfmex/cfmex.cxx | 449 ++++++++++ private/oleutest/cfmex/cfmex.hxx | 31 + private/oleutest/cfmex/cmoniker.cxx | 1684 +++++++++++++++++++++++++++++++++++ private/oleutest/cfmex/cmoniker.hxx | 178 ++++ private/oleutest/cfmex/ctest.cxx | 1283 ++++++++++++++++++++++++++ private/oleutest/cfmex/ctest.hxx | 118 +++ private/oleutest/cfmex/makefile | 6 + private/oleutest/cfmex/sources | 35 + 10 files changed, 4363 insertions(+) create mode 100644 private/oleutest/cfmex/cdir.cxx create mode 100644 private/oleutest/cfmex/cdir.hxx create mode 100644 private/oleutest/cfmex/cfmex.cxx create mode 100644 private/oleutest/cfmex/cfmex.hxx create mode 100644 private/oleutest/cfmex/cmoniker.cxx create mode 100644 private/oleutest/cfmex/cmoniker.hxx create mode 100644 private/oleutest/cfmex/ctest.cxx create mode 100644 private/oleutest/cfmex/ctest.hxx create mode 100644 private/oleutest/cfmex/makefile create mode 100644 private/oleutest/cfmex/sources (limited to 'private/oleutest/cfmex') diff --git a/private/oleutest/cfmex/cdir.cxx b/private/oleutest/cfmex/cdir.cxx new file mode 100644 index 000000000..250404676 --- /dev/null +++ b/private/oleutest/cfmex/cdir.cxx @@ -0,0 +1,418 @@ + +//+========================================================================== +// +// File: CDir.cxx +// +// Purpose: Define the CDirectory class. +// +// This class is used to represent a directory name. +// Along with maintaining the name, it can determine +// the type of FileSystem. +// +//+========================================================================== + + +// -------- +// Includes +// -------- + +#include +#include +#include +#include +#include + +#include "CFMEx.hxx" +#include "CDir.hxx" + + +//+------------------------------------------------------------------------------ +// +// Function: CDirectory::Initialize (no arguments) +// +// Synopsis: Generate a directory name, using the TEMP environment +// variable, and use it to initialize this object. +// +// Inputs: None. +// +// Outputs: TRUE if the function succeeds, FALSE otherwise. +// +//+------------------------------------------------------------------------------ + +BOOL CDirectory::Initialize() +{ + // --------------- + // Local Variables + // --------------- + + // Assume failure for now. + BOOL bSuccess = FALSE; + + // The TEMP environment variable. + WCHAR wszSystemTempPath[ MAX_PATH + sizeof( L'\0' )]; + + // Reset the error code. + m_lError = 0L; + + // ---------- + // Get %TEMP% + // ---------- + + if( !GetTempPath( MAX_PATH, + wszSystemTempPath ) + ) + { + m_lError = GetLastError(); + EXIT( L"GetTempPath() failed (%d)" ); + } + + // ---------------------- + // Initialize this object + // ---------------------- + + // Initialize using the temporary path. We must never pass a NULL here, + // or we'll cause an infinite recursion. + + if( wszSystemTempPath == NULL ) + EXIT( L"Invalid temporary path" ); + bSuccess = Initialize( wszSystemTempPath ); + + // ---- + // Exit + // ---- + +Exit: + + return( bSuccess ); + +} + +//+----------------------------------------------------------------------- +// +// Function: CDirectory::Initialize (with an ANSI string) +// +// Synopsis: This function converts the ANSI string to a Unicode +// string, then initializes the object with it. +// +// Inputs: A Unicode string. +// +// Outputs: TRUE if the function succeeds, FALSE otherwise. +// +//+----------------------------------------------------------------------- + +BOOL CDirectory::Initialize( LPCSTR szDirectory ) +{ + // --------------- + // Local Variables + // --------------- + + // Assume failure. + BOOL bSuccess = FALSE; + + // A buffer for the Unicode path + WCHAR wszDirectory[ MAX_UNICODE_PATH + sizeof( L'\0' )]; + + // ----- + // Begin + // ----- + + // Initialize the error code. + m_lError = 0L; + + + // If we were givin a NULL path, use the version of Initialize + // that requires no path. + + if( szDirectory == NULL ) + { + bSuccess = Initialize(); + goto Exit; + } + + // Convert the Ansi name to Unicode. + + if( m_lError = (long) AnsiToUnicode( szDirectory, + wszDirectory, + strlen( szDirectory ) + ) + ) + { + EXIT( L"Unable to convert directory to Unicode" ); + } + + // Initialize using the temporary path. We must never pass a NULL here, + // or we'll cause an infinite recursion. + + if( wszDirectory == NULL ) + EXIT( L"Invalid Directory (internal error)" ); + bSuccess = Initialize( wszDirectory ); + + // ---- + // Exit + // ---- + +Exit: + + return( bSuccess ); + +} + + +//+----------------------------------------------------------------------- +// +// Function: CDirectory::Initialize (with a Unicode string) +// +// Synopsis: This function is the only form of Initialize +// (there are several variations of the Initialize member) +// which really initializes the object. It stores the +// directory name, and determines the type of filesystem +// on which it resides. +// +// Inputs: A Unicode string. +// +// Outputs: TRUE if the function succeeds, FALSE otherwise. +// +//+----------------------------------------------------------------------- + +BOOL CDirectory::Initialize( LPCWSTR wszDirectory ) +{ + + // --------------- + // Local Variables + // --------------- + + // Assume failure. + BOOL bSuccess = FALSE; + + // Buffers for the root of the path and for the volume name. + WCHAR wszDirectoryRoot[ MAX_PATH + sizeof( L'\0' )]; + WCHAR wszVolumeName[ MAX_PATH + sizeof( L'\0' )]; + + // Parameters to GetVolumeInformation which we won't use. + DWORD dwMaxComponentLength = 0L; + DWORD dwFileSystemFlags = 0L; + + // ----- + // Begin + // ----- + + // Initialize the error code. + m_lError = 0L; + + // If we were given a NULL path, use the variation of Initialization() + // which does not require one. Note that we will then be called again, + // but this time with a path. + + if( wszDirectory == NULL ) + { + bSuccess = Initialize(); + goto Exit; + } + + // Validate the path. + + if( wcslen( wszDirectory ) > MAX_PATH ) + { + m_lError = wcslen( wszDirectory ); + EXIT( L"Input path is too long (%d)\n" ); + } + + // Save the path to our member buffer + + wcscpy( m_wszDirectory, wszDirectory ); + + + // ------------------------ + // Get the file system name + // ------------------------ + + // Get the root path to the directory. + + wcscpy( wszDirectoryRoot, wszDirectory ); + MakeRoot( wszDirectoryRoot ); + + // Get the volume information, which will include the filesystem name. + + if( !GetVolumeInformation( wszDirectoryRoot, // Root path name. + wszVolumeName, // Buffer for volume name + MAX_PATH, // Length of the above buffer + NULL, // Buffer for serial number + // Longest filename length. + &dwMaxComponentLength, + &dwFileSystemFlags, // Compression, etc. + m_wszFileSystemName,// Buffer for the FS name. + MAX_PATH ) // Length of above buffer + ) + { + m_lError = GetLastError(); + EXIT( L"GetVolumeInformation() failed" ); + } + + + // Determine the file system type from the name. + + if( !wcscmp( m_wszFileSystemName, L"FAT" )) + m_FileSystemType = fstFAT; + + else if( !wcscmp( m_wszFileSystemName, L"NTFS" )) + m_FileSystemType = fstNTFS; + + else if( !wcscmp( m_wszFileSystemName, L"OFS" )) + m_FileSystemType = fstOFS; + + else + m_FileSystemType = fstUnknown; + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + DisplayErrors( bSuccess, L"CDirectory::Initialize( wszDirectory )" ); + return( bSuccess ); + +} + + + +// +// GetRootLength +// +// This routine was simply copied from private\windows\shell\shelldll\tracker.cxx, +// and should not be modified here. +// + +unsigned +CDirectory::GetRootLength(const WCHAR *pwszPath) +{ + ULONG cwcRoot = 0; + m_lError = 0L; + + if (pwszPath == 0) + pwszPath = L""; + + if (*pwszPath == L'\\') + { + // If the first character is a path separator (backslash), this + // must be a UNC drive designator which must be of the form: + // (+) + // (+) + // + // This covers drives like these: \\worf\scratch\ and + // \\savik\win4dev\. + // + pwszPath++; + cwcRoot++; + + BOOL fMachine = FALSE; + BOOL fShare = FALSE; + + if (*pwszPath == L'\\') + { + cwcRoot++; + pwszPath++; + + while (*pwszPath != '\0' && *pwszPath != L'\\') + { + cwcRoot++; + pwszPath++; + + fMachine = TRUE; + } + + if (*pwszPath == L'\\') + { + cwcRoot++; + pwszPath++; + + while (*pwszPath != '\0' && *pwszPath != L'\\') + { + cwcRoot++; + pwszPath++; + + fShare = TRUE; + } + + // If there weren't any characters in the machine or + // share portions of the UNC name, then the drive + // designator is bogus. + // + if (!fMachine || !fShare) + { + cwcRoot = 0; + } + } + else + { + cwcRoot = 0; + } + } + else + { + cwcRoot = 0; + } + } + else + if (iswalpha(*pwszPath)) + { + // If the first character is an alphanumeric, we must have + // a drive designator of this form: + // ()+ + // + // This covers drives like these: a:\, c:\, etc + // + + pwszPath++; + cwcRoot++; + + if (*pwszPath == L':') + { + cwcRoot++; + pwszPath++; + } + else + { + cwcRoot = 0; + } + } + + // If we have counted one or more characters in the root and these + // are followed by a component separator, we need to add the separator + // to the root length. Otherwise this is not a valid root and we need + // to return a length of zero. + // + if ((cwcRoot > 0) && (*pwszPath == L'\\')) + { + cwcRoot++; + } + else + { + cwcRoot = 0; + } + + return (cwcRoot); +} + +// +// MakeRoot +// +// This routine was simply copied from private\windows\shell\shelldll\tracker.cxx, +// and should not be modified here. +// + + +VOID +CDirectory::MakeRoot(WCHAR *pwszPath) +{ + unsigned rootlength = GetRootLength(pwszPath); + m_lError = 0L; + + if (rootlength) + { + pwszPath[rootlength] = L'\0'; + } +} + diff --git a/private/oleutest/cfmex/cdir.hxx b/private/oleutest/cfmex/cdir.hxx new file mode 100644 index 000000000..7feaf8851 --- /dev/null +++ b/private/oleutest/cfmex/cdir.hxx @@ -0,0 +1,161 @@ + + +//+----------------------------------------------------------------------- +// +// File: CDir.hxx +// +// Purpose: Declare the CDirectory class. Objects of this class +// are used to represent a directory, and provide additional +// information about it. +// +//+----------------------------------------------------------------------- + + +#ifndef _C_DIR_HXX_ +#define _C_DIR_HXX_ + +// -------- +// Includes +// -------- + +#include "CFMEx.hxx" + + +// -------- +// Typedefs +// -------- + +// An enumeration of the possible file system types. + +typedef enum +{ + fstFAT, + fstNTFS, + fstOFS, + fstUnknown +} enumFileSystemType; + + +// ---------- +// CDirectory +// ---------- + +class CDirectory +{ + +// Construction/Deconstruction + +public: + + CDirectory(); + ~CDirectory(); + +// Public Member Functions + +public: + + BOOL Initialize(); // Defaulted input + BOOL Initialize( LPCWSTR wszDirectory ); // Unicode input + BOOL Initialize( LPCSTR szDirectory ); // ANSI input + + enumFileSystemType GetFileSystemType() const; + LPCWSTR GetFileSystemName() const; + LPCWSTR GetDirectoryName() const; + + +// Private Member Functions + +private: + + void DisplayErrors( BOOL bSuccess, LPCWSTR wszFunctionName ); + VOID MakeRoot(WCHAR *pwszPath); + unsigned GetRootLength(const WCHAR *pwszPath); + + +// Member Data + +private: + + WCHAR m_wszDirectory[ MAX_UNICODE_PATH + sizeof( L'\0' )]; + WCHAR m_wszFileSystemName[ MAX_UNICODE_PATH + sizeof( L'\0' )]; + enumFileSystemType m_FileSystemType; + + WCHAR m_wszErrorMessage[ 200 ]; + long m_lError; + +}; + + +// ---------------- +// Inline Functions +// ---------------- + + +// CDirectory::CDirectory + +inline CDirectory::CDirectory() +{ + wcscpy( m_wszDirectory, L"" ); + wcscpy( m_wszFileSystemName, L"" ); + wcscpy( m_wszErrorMessage, L"" ); + m_lError = 0; + m_FileSystemType = fstUnknown; + +} + +// CDirectory::~CDirectory + +inline CDirectory::~CDirectory() +{ +} + +// CDirectory::GetFileSystemType + +inline enumFileSystemType CDirectory::GetFileSystemType() const +{ + return m_FileSystemType; +} + +// CDirectory::GetFileSystemName + +inline LPCWSTR CDirectory::GetFileSystemName() const +{ + return m_wszFileSystemName; +} + +// CDirectory::GetDirectoryName + +inline LPCWSTR CDirectory::GetDirectoryName() const +{ + return m_wszDirectory; +} + + +// CDirectory::DisplayErrors + +inline void CDirectory::DisplayErrors( BOOL bSuccess, LPCWSTR wszFunctionName ) +{ + if( !bSuccess ) + { + wprintf( L"Error in %s (%08x)\n %s\n", + wszFunctionName, m_lError, m_wszErrorMessage ); + } +} + + +// ------ +// Macros +// ------ + +// Early-exit macro. + +#undef EXIT +#define EXIT( error ) \ + {\ + wcscpy( m_wszErrorMessage, ##error );\ + goto Exit;\ + } + + + +#endif // _C_DIR_HXX_ diff --git a/private/oleutest/cfmex/cfmex.cxx b/private/oleutest/cfmex/cfmex.cxx new file mode 100644 index 000000000..37e8c08ed --- /dev/null +++ b/private/oleutest/cfmex/cfmex.cxx @@ -0,0 +1,449 @@ + +//+=============================================================== +// +// File: CFMEx.cxx +// +// Purpose: This file provides the main() and global functions +// for the CreateFileMonikerEx (CFMEx) DRT. +// This DRT tests the CreateFileMonikerEx API (new to +// Cairo), as well as related changes to BIND_OPTS +// (use of the BIND_OPTS2 structure). +// +// All moniker activity is performed in the CMoniker +// object (such as creating a bind context, creating +// a link source file, moving it, binding it, etc.). +// +// The test engine is in the CTest object. When a link +// source file is moved to test link-tracking, the +// original and final location of the file may be +// specified by the user (on the command-line). CTest +// is aware of the filesystem type (FAT, NTFS, OFS) +// of these locations, and is aware of how that will +// effect the results. +// +// This file also provides global functions (not associated +// with an object). +// +// Usage: cfmex [-o] [-f] +// +// -o specifies the original directory for link sources +// -f specifies the final directory for link sources +// +// Examples: cfmex +// cfmex -oC:\ -fC:\ +// +//+=============================================================== + + +// ---- +// TODO: +// ---- +// +// - Replace CRT calls with Win32 calls. +// - Validate the directory in CDirectory. +// - Add a flag to CDirectory to indicate "indexed". +// - Add a flag to CDirectory to indicate local vs remote. +// - Add a test to verify that the moniker returned from Reduce is +// not a tracking moniker. +// + + +// ------------- +// Include Files +// ------------- + + +#define _DCOM_ // Allow DCOM extensions (e.g., CoInitializeEx). + +#include +#include +#include +#include +#include +#include +#include +#include +#include "CFMEx.hxx" +#include "CMoniker.hxx" +#include "CTest.hxx" +#include "CDir.hxx" + + +// ------ +// Macros +// ------ + +// Early-exit macro: put the error message in a global array, +// and jump to Exit + +WCHAR wszErrorMessage[ 512 ]; + +#undef EXIT +#define EXIT( error ) \ + {\ + wcscpy( wszErrorMessage, ##error );\ + goto Exit;\ + } + + + +// Run a Test: Display a new paragraph on the screen, run a test, +// and update stats. + +#define RUN_TEST( testID ) \ + {\ + nTotalTests++; \ + wprintf( L"----------------------------------------------\n" ); \ + wprintf( L"Test %d: ", nTotalTests ); \ + if( cTest.##testID ) \ + wprintf( L"Passed\n" ); \ + else \ + nTestsFailed++; \ + } + + +//+--------------------------------------------------------------------------------------- +// +// Function: DisplayHelp +// +// Synopsis: Display a help screen with usage information. +// +// Inputs: None. +// +// Outputs: None. +// +// Effects: None +// +//+--------------------------------------------------------------------------------------- + + +void DisplayHelp( void ) +{ + + wprintf( L"This DRT tests the CreateFileMonikerEx API, and related changes.\n" + L"Most of these tests create a link source file, create a moniker\n" + L"representing that file, then move the file. You can specify the\n" + L"original and/or final locations of the link source, or let those\n" + L"locations default to the \%TEMP\% directory\n" + L"\n" + L"Usage: cfmex [-o] [-f]\n" + L"\n" + L"Where: -o specifies the original directory for link sources\n" + L" -f specifies the final directory for link sources\n" + L"\n" + L"Note: If an original or final directory is specified on the command-\n" + L" line, that directory must already exist. If one of these locations\n" + L" is not specified, the TEMP environment variable must be defined\n" + L" and it must specify an extant directory.\n" + L"\n" + L"E.g.: cfmex\n" + L" cfmex -oC:\\\n" + L" cfmex -oE:\\ -fF:\\temp\n" + L"\n" ); + return; +} + + + +//+--------------------------------------------------------------------------------------- +// +// Function: UnicodeToAnsi +// +// Synopsis: Convert a Unicode (wide) string to ANSI +// +// Inputs: The Unicode String +// The buffer for the ANSI string +// The size of the above buffer +// +// Outputs: 0 if successful +// GetLastError() otherwise +// +// Effects: None +// +//+--------------------------------------------------------------------------------------- + +DWORD UnicodeToAnsi( const WCHAR * wszUnicode, + CHAR * szAnsi, + int cbAnsiMax ) +{ + int cbAnsi = 0; + + // Convert WCS to the MBCS, using the ANSI code page. + + cbAnsi = WideCharToMultiByte( CP_ACP, + WC_COMPOSITECHECK | WC_DEFAULTCHAR, + wszUnicode, + wcslen( wszUnicode ), + szAnsi, + cbAnsiMax, + NULL, + NULL ); + if( !cbAnsi ) + { + // No characters were converted - there was an error. + // Note that this will be returned if a null Unicode string is + // passed in. + + return( GetLastError() ); + } + else + { + // Terminate the Ansi string and return. + + szAnsi[ cbAnsi ] = '\0'; + return( 0L ); + } + +} // UnicodeToAnsi() + + + +//+--------------------------------------------------------------------------------------- +// +// Function: AnsiToUnicode +// +// Synopsis: Convert an ANSI string to Unicode (i.e. Wide) +// +// Inputs: The ANSI String +// The buffer for the Unicode string +// The size of the above buffer. +// +// Outputs: 0 if successful +// GetLastError() otherwise +// +// Effects: None +// +//+--------------------------------------------------------------------------------------- + +DWORD AnsiToUnicode( const CHAR * szAnsi, + WCHAR * wszUnicode, + int cbUnicodeMax ) +{ + int cbUnicode = 0; + + cbUnicode = MultiByteToWideChar( CP_ACP, + MB_PRECOMPOSED, + szAnsi, + strlen( szAnsi ), + wszUnicode, + cbUnicodeMax ); + + if( !cbUnicode ) + { + // If no characters were converted, then there was an error. + + return( GetLastError() ); + } + else + { + // Terminate the Unicode string and return. + + wszUnicode[ cbUnicode ] = L'\0'; + return( 0L ); + } + +} // AnsiToUnicode() + + + +//+--------------------------------------------------------------------------------------- +// +// Function: main +// +// Synopsis: Run the CFMEx DRT. All tests are in the CTest object. These +// tests are simply called sequentially. +// +// Inputs: (argc) the count of arguments +// (argv) the arguments. See DisplayHelp() for a description. +// +// Outputs: 0 if completely successful +// 1 if help was displayed +// 2 if a test failed +// +// Effects: None +// +//+--------------------------------------------------------------------------------------- + + +int main( int argc, char** argv ) +{ + + // --------------- + // Local Variables + // --------------- + + // Test statistics. + + int nTotalTests = 0; + int nTestsFailed = 0; + + // The original and final directories (in ANSI) of the link source file. + + CHAR* szOriginalDirectory = NULL; + CHAR* szFinalDirectory = NULL; + + // Objects representing the original and final directories. + + CDirectory cDirectoryOriginal; + CDirectory cDirectoryFinal; + + // The test engine. + + CTest cTest; + + int index = 0; + + + // -------------- + // Opening Banner + // -------------- + + printf( "\n" + "*** CreateFileMonikerEx DRT ***\n" + "(use \"cfmex -?\" for help)\n" + "\n" ); + + + // ------------------------------ + // Handle command-line parameters + // ------------------------------ + + + for( index = 1; index < argc; index++ ) + { + // The first character of an argument should be an "-" or "/" + // (they are interchangable). + + if( ( ( argv[index][0] != '-' ) + && + ( argv[index][0] != '/' ) + ) + || + ( strlen( &argv[index][0] ) < 2 ) // Must have more than '-' & an option. + ) + { + printf( "Invalid argument ignored: %s\n", argv[ index ] ); + continue; + } + + + // Switch based on the first character (which defines the option). + + switch( argv[index][1] ) + { + // Help requested + + case '?': + DisplayHelp(); + exit( 1 ); + + // An original directory is specified. + + case 'o': + case 'O': + + // Verify the specified path length. + + if( strlen( &argv[index][2] ) > MAX_PATH ) + { + printf( "Path is too long, ignored: %s\n", &argv[index][2] ); + break; // From the switch + } + + szOriginalDirectory = &argv[index][2]; + break; // From the switch + + // A final directory is specified + + case 'f': + case 'F': + + if( strlen( &argv[index][2] ) > MAX_PATH ) + { + printf( "Path is too long, ignored: %s\n", &argv[index][2] ); + break; // From the switch + } + + szFinalDirectory = &argv[index][2]; + break; // From the switch + + // Invalid argument. + + default: + + printf( "Invalid option ignored: \"-%c\"\n", argv[index][1] ); + break; + } + } + + // -------------- + // Initialization + // -------------- + + // Initialize COM + + CoInitialize( NULL ); + + + // Initialize the CDirectory and CTest objects. If no original/final + // directory was specified above, CDirectory will create a default + // (based on %TEMP%). + + if( !cDirectoryOriginal.Initialize( szOriginalDirectory ) ) + EXIT( L"Could not initialize cDirectoryOriginal" ); + + if( !cDirectoryFinal.Initialize( szFinalDirectory ) ) + EXIT( L"Could not initialize cDirectoryFinal" ); + + if( !cTest.Initialize( cDirectoryOriginal, cDirectoryFinal ) ) + EXIT( L"Could not initialize CTest" ); + + + // Show the end result. + + wprintf( L"Link sources will be created in \"%s\" (%s)\n", + cDirectoryOriginal.GetDirectoryName(), + cDirectoryOriginal.GetFileSystemName() ); + wprintf( L"and will be moved to \"%s\" (%s)\n", + cDirectoryFinal.GetDirectoryName(), + cDirectoryFinal.GetFileSystemName() ); + + + // --------- + // Run Tests + // --------- + + RUN_TEST( GetOversizedBindOpts() ); + RUN_TEST( GetUndersizedBindOpts() ); + RUN_TEST( SetOversizedBindOpts() ); + RUN_TEST( SetUndersizedBindOpts() ); + RUN_TEST( CreateFileMonikerEx() ); + RUN_TEST( GetDisplayName() ); + RUN_TEST( GetTimeOfLastChange() ); + RUN_TEST( ComposeWith() ); + RUN_TEST( IPersist() ); + RUN_TEST( BindToStorage() ); + RUN_TEST( BindToObject() ); + RUN_TEST( DeleteLinkSource( 0 )); // Timeout immediately. + RUN_TEST( DeleteLinkSource( 200 )); // Timeout in multi-threaded search + RUN_TEST( DeleteLinkSource( INFINITE )); // Don't timeout + + // ---- + // Exit + // ---- + +Exit: + + // Show test results. + + wprintf( L"\n\nTesting complete:\n" + L" Total Tests = %d\n" + L" Failed = %d\n", + nTotalTests, nTestsFailed ); + + // Free COM + + CoUninitialize(); + + return( nTestsFailed ? 2 : 0 ); +} diff --git a/private/oleutest/cfmex/cfmex.hxx b/private/oleutest/cfmex/cfmex.hxx new file mode 100644 index 000000000..5f1f6f488 --- /dev/null +++ b/private/oleutest/cfmex/cfmex.hxx @@ -0,0 +1,31 @@ + +//+============================================================================== +// +// File: CFMEx.hxx +// +// Purpose: Provide global definitions and function prototypes +// for the CreateFileMonikerEx DRT. +// +//+============================================================================== + +#ifndef _CFMEX_HXX_ +#define _CFMEX_HXX_ + +// The size of a buffer which will hold a path depends on the size +// of the characters. + +#define MAX_ANSI_PATH MAX_PATH +#define MAX_UNICODE_PATH ( MAX_PATH * sizeof( WCHAR )) + +// Function prototypes. + +DWORD AnsiToUnicode( const CHAR * szAnsi, + WCHAR * wszUnicode, + int cbUnicodeMax ); + +DWORD UnicodeToAnsi( const WCHAR * wszUnicode, + CHAR * szAnsi, + int cbAnsiMax ); + + +#endif // _CFMEX_HXX_ diff --git a/private/oleutest/cfmex/cmoniker.cxx b/private/oleutest/cfmex/cmoniker.cxx new file mode 100644 index 000000000..7a9c555a7 --- /dev/null +++ b/private/oleutest/cfmex/cmoniker.cxx @@ -0,0 +1,1684 @@ + +//+======================================================================= +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#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_ diff --git a/private/oleutest/cfmex/cmoniker.hxx b/private/oleutest/cfmex/cmoniker.hxx new file mode 100644 index 000000000..7d9e1ada0 --- /dev/null +++ b/private/oleutest/cfmex/cmoniker.hxx @@ -0,0 +1,178 @@ + + +//+================================================================ +// +// File: CMoniker.hxx +// +// Purpose: This file declares the CMoniker class. +// This class manages a file moniker. +// +//+================================================================ + + +#ifndef _C_MONIKER_HXX_ +#define _C_MONIKER_HXX_ + + +// -------- +// Includes +// -------- + +#include "CDir.hxx" + +// -------- +// CMoniker +// -------- + +class CMoniker +{ + +// (De)Construction + +public: + + CMoniker(); + ~CMoniker(); + +// Public member routines. + +public: + + BOOL GetTemporaryStorageTime( FILETIME *); + BOOL Initialize( const CDirectory& cDirectoryOriginal, + const CDirectory& cDirectoryFinal ); + BOOL CreateFileMonikerEx( DWORD dwTrackFlags = 0L ); + BOOL SaveDeleteLoad(); + BOOL ComposeWith(); + BOOL Reduce( DWORD dwDelay, IMoniker** ppmkReduced = NULL ); + BOOL GetDisplayName( WCHAR * wszDisplayName, IMoniker* pmnkCaller = NULL ); + BOOL GetTimeOfLastChange( FILETIME *ft ); + BOOL BindToStorage(); + BOOL BindToObject(); + + BOOL CreateTemporaryStorage(); + BOOL RenameTemporaryStorage(); + BOOL DeleteTemporaryStorage(); + + const WCHAR * GetTemporaryStorageName() const; + IBindCtx* GetBindCtx() const; + BOOL TouchTemporaryStorage(); + HRESULT GetHResult() const; + void SuppressErrorMessages( BOOL bSuppress ); + BOOL InitializeBindContext( ); + + +// Private member routines. + +private: + + BOOL CreateLinkTrackingRegistryKey(); + BOOL OpenLinkTrackingRegistryKey(); + BOOL CloseLinkTrackingRegistryKey(); + void DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName ) const; + + +// Private data members + +private: + + WCHAR m_wszSystemTempPath[ MAX_PATH + sizeof( L'\0' ) ]; + WCHAR m_wszTemporaryStorage[ MAX_PATH + sizeof( L'\0' ) ]; + + IMoniker* m_pIMoniker; + IBindCtx* m_pIBindCtx; + IStorage* m_pIStorage; + + WCHAR m_wszErrorMessage[ 100 ]; + DWORD m_dwTrackFlags; + BOOL m_bSuppressErrorMessages; + + const CDirectory* m_pcDirectoryOriginal; + const CDirectory* m_pcDirectoryFinal; + + // The following key, along with being a usable handle, is a flag + // which indicates if we need to restore the data in the registry. + + HKEY m_hkeyLinkTracking; + + + // Note that m_hr is used for more than just HRESULTs, sometimes + // it is used for other errors as well. + + HRESULT m_hr; + +}; + + +// -------------- +// Inline Members +// -------------- + +#define OUTFILE stdout + +// CMoniker::DisplayErrors + +inline void CMoniker::DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName ) const +{ + if( !bSuccess + && + !m_bSuppressErrorMessages + ) + { + fwprintf( OUTFILE, L"Error in %s (%08x)\n %s\n", + wszFunctionName, m_hr, m_wszErrorMessage ); + } +} + +// CMoniker::GetTemporaryStorage + +inline const WCHAR * CMoniker::GetTemporaryStorageName() const +{ + return m_wszTemporaryStorage; +} + +// CMoniker::GetBindCtx + +inline IBindCtx* CMoniker::GetBindCtx() const +{ + return( m_pIBindCtx ); +} + +// CMoniker::GetHResult + +inline HRESULT CMoniker::GetHResult() const +{ + return( m_hr ); +} + +// CMoniker::SuppressErrorMessages + +inline void CMoniker::SuppressErrorMessages( BOOL bSuppress ) +{ + // Normalize to TRUE or FALSE + + m_bSuppressErrorMessages = bSuppress ? TRUE : FALSE; +} + + +// ------ +// Macros +// ------ + +#define DEFAULT_TRACK_FLAGS ( TRACK_LOCALONLY ) + +#define EXIT_ON_FAILED( error ) if( FAILED( m_hr )) \ + {\ + wcscpy( m_wszErrorMessage, ##error );\ + goto Exit;\ + } + +#undef EXIT +#define EXIT( error ) \ + {\ + wcscpy( m_wszErrorMessage, ##error );\ + goto Exit;\ + } + + +#endif // _C_MONIKER_HXX_ diff --git a/private/oleutest/cfmex/ctest.cxx b/private/oleutest/cfmex/ctest.cxx new file mode 100644 index 000000000..e2de08c3c --- /dev/null +++ b/private/oleutest/cfmex/ctest.cxx @@ -0,0 +1,1283 @@ + + +//+======================================================================= +// +// File: CTest.cxx +// +// Purpose: Define the CTest class. +// +// This class is the test engine for the CreateFileMonikerEx +// (CFMEx) DRTs. All interactions with monikers are handled +// through the CMoniker class. +// +//+======================================================================= + + +// ------------- +// Include Files +// ------------- + +#define _DCOM_ // Allow DCOM extensions (e.g., CoInitializeEx). + +#include +#include +#include +#include +#include +#include +#include +#include +#include "CDir.hxx" +#include "CMoniker.hxx" +#include "CTest.hxx" + + +//+------------------------------------------------------------------------ +// +// Function: CTest::CTest +// +// Synopsis: Inititialize member variables. +// +// Inputs: None. +// +// Outputs: N/A +// +// Effects: All members are initialized/defaulted. +// +//+------------------------------------------------------------------------ + + +CTest::CTest( ) +{ + + m_lError = 0L; + *m_wszErrorMessage = L'\0'; + + m_pcDirectoryOriginal = NULL; + m_pcDirectoryFinal = NULL; + +} // CTest::CTest + +//+------------------------------------------------------------------------------ +// +// Function: CTest::~CTest +// +// Synopsis: No action. +// +// Inputs: N/A +// +// Outputs: N/A +// +// Effects: None. +// +//+------------------------------------------------------------------------------ + + +CTest::~CTest() +{ +} // CTest::~CTest + + +//+------------------------------------------------------------------------------- +// +// Function: CTest::Initialize +// +// Synopsis: Inititialize a CTest object. +// +// Inputs: CDirectory objects representing the original and final +// locations of a link source file. The original location +// is used in CreateTemporaryStorage(), and the final location +// is used in RenameTemporaryStorage(). +// +// Outputs: TRUE if successful, FALSE otherwise. +// +// Effects: m_cDirectoryOriginal and m_cDirectoryFinal are set. +// +//+------------------------------------------------------------------------------- + + +BOOL CTest::Initialize( const CDirectory& cDirectoryOriginal, + const CDirectory& cDirectoryFinal + ) +{ + // ----- + // Begin + // ----- + + m_pcDirectoryOriginal = &cDirectoryOriginal; + m_pcDirectoryFinal = &cDirectoryFinal; + + m_cMoniker.Initialize( cDirectoryOriginal, cDirectoryFinal ); + + // ---- + // Exit + // ---- + + return TRUE; + +} // CTest::Initialize + +//+------------------------------------------------------------------------- +// +// Function: CTest::CreateFileMonikerEx +// +// Synopsis: Verify that CreateFileMonikerEx actually creates a +// *tracking* file moniker. This is done by creating +// the file moniker, renaming the link source, +// Reducing the moniker, and getting the display name +// of the reduced moniker. Note that this tests +// both CreateFileMonikerEx and Reduce. +// +// Inputs: None. +// +// Outputs: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+------------------------------------------------------------------------- + + +BOOL CTest::CreateFileMonikerEx( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' ) ]; + IMoniker* pmnkReduced = NULL; + + // ----- + // Begin + // ----- + + wprintf( L"CreateFileMonikerEx()\n" ); + wprintf( L" Create a tracking file moniker (using CreateFileMonikerEx),\n" + L" move the represented file, Reduce the moniker, and get\n" + L" the display name from the reduced moniker. It should be the\n" + L" new file name. This test covers both CreateFileMonikerEx and\n" + L" Reduce.\n" ); + + + // Create the tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Rename the link source file. + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + // Reduce the tracking file moniker + + if( !m_cMoniker.Reduce( INFINITE, &pmnkReduced )) + EXIT( L"Could not reduce the moniker" ); + + // Use the reduced (non-tracking) file moniker to get the display name. + + if( !m_cMoniker.GetDisplayName( wszDisplayName, pmnkReduced )) + EXIT( L"Could not get the display name" ); + + // Validate the display name. + + if( _wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() )) + EXIT( L"Failed" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + DisplayErrors( bSuccess, L"CTest::CreateFileMonikerEx()" ); + return( bSuccess ); + +} // CTest::CreateFileMonikerEx() + + +//+-------------------------------------------------------------------------- +// +// Function: CTest::GetDisplayName +// +// Synopsis: Create a tracking file moniker, get its display name, +// rename the link source file, and get the display name again. +// The value of the second display name will depend on whether +// or not the original and final link source are within the set +// of local indexed volumes. +// +// Inputs: None. +// +// Outputs: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+-------------------------------------------------------------------------- + + +BOOL CTest::GetDisplayName( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + WCHAR wszFinalDisplayName[ MAX_PATH + sizeof( L'\0' ) ]; + WCHAR wszOriginalDisplayName[ MAX_PATH + sizeof( L'\0' ) ]; + + // ----- + // Begin + // ----- + + wprintf( L"GetDisplayName()\n" ); + wprintf( L" Create a tracking file moniker, move the represented file,\n" + L" and perform a GetDisplayName on the moniker. If the original\n" + L" and final locations of the source file are within the set of local\n" + L" indexed drives, the display name will represent the final file name.\n" + L" Otherwise, it will represent the original display name.\n" ); + + // Create a tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Get its display name. + + if( !m_cMoniker.GetDisplayName( wszOriginalDisplayName )) + EXIT( L"Could not get the original display name" ); + + // Rename the link source. + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + // Get the renamed moniker's display name. + + if( !m_cMoniker.GetDisplayName( wszFinalDisplayName )) + EXIT( L"Could not get the final display name" ); + + // Was and is the link source on a local, indexed volume? + + if( ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS ) + && + ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS ) + ) + { + // Yes, so the GetDisplayName should have tracked the rename. + + if( _wcsicmp( wszFinalDisplayName, m_cMoniker.GetTemporaryStorageName() )) + EXIT( L"Failed" ); + } + else + { + // No, so the GetDisplayName should have returned the original name. + + if( _wcsicmp( wszOriginalDisplayName, wszFinalDisplayName )) + EXIT( L"Failed" ); + } + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + DisplayErrors( bSuccess, L"CTest::GetDisplayName()" ); + return( bSuccess ); + +} // CTest::GetDisplayName() + + + +//+-------------------------------------------------------------------------- +// +// Function: CTest::GetTimeOfLastChange +// +// Synopsis: Create a tracking file moniker, rename it, sleep, and +// touch it. If the original and final link sources are +// on local, indexed volumes, then a GetDisplayName should +// return the final link source's time. Otherwise, it should +// return the original link source's time. +// +// Inputs: None. +// +// Outputs: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+-------------------------------------------------------------------------- + + +BOOL CTest::GetTimeOfLastChange( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + FILETIME ftOriginal; + FILETIME ftFinal; + FILETIME ftMoniker; + + // ----- + // Begin + // ----- + + wprintf( L"GetTimeOfLastChange()\n" ); + wprintf( L" Create a tracking file moniker and move it. Then touch (set the Access\n" + L" time) on the link source, and perform a GetTimeOfLastChange on the Moniker.\n" + L" If the original and final location of the link source is within the set\n" + L" of local indexed volumes, then the time returned from the moniker should\n" + L" match that of the post-touch link source. Otherwise it should match the\n" + L" link sources original time.\n" ); + + // Create a tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( TRACK_LOCALONLY ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Get the link source's current time. + + if( !m_cMoniker.GetTemporaryStorageTime( &ftOriginal )) + EXIT( L"Could not get original file time" ); + + // Move the link source. + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + // Delay so that when we touch the final link source, its time + // will be noticably different from the original link source's time. + + { + wprintf( L" Sleeping to let the time change: " ); + for( int i = 0; i < 10; i++ ) // Sleep for 5 seconds + { + wprintf( L"z" ); + Sleep( 500 ); // 1/2 second + } + wprintf( L"\n" ); + } + + // Touch the final link source. + + if( !m_cMoniker.TouchTemporaryStorage()) + EXIT( L"Could not touch temporary storage" ); + + // Get the final link source's time from the file system. + + if( !m_cMoniker.GetTemporaryStorageTime( &ftFinal )) + EXIT( L"could not get final file time" ); + + // Get the final link source's time from the moniker. + + if( !m_cMoniker.GetTimeOfLastChange( &ftMoniker )) + EXIT( L"Could not get the time of last change" ); + + // Is the original & final location of the link source file + // in the set of local, indexed volumes? + + if( ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS ) + && + ( m_pcDirectoryOriginal->GetFileSystemType() == fstOFS ) + ) + { + // Yes. GetTimeOfLastChange should therefore have found + // the time of the final link source file. + + if( memcmp( &ftFinal, &ftMoniker, sizeof( FILETIME ) )) + EXIT( L"Failed" ); + } + else + { + // No. GetTimeOfLastChange should therefore have returned + // the time of the original link source file. + + if( memcmp( &ftOriginal, &ftMoniker, sizeof( FILETIME ) )) + EXIT( L"Failed" ); + } + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + DisplayErrors( bSuccess, L"CTest::GetTimeOfLastChange()" ); + return( bSuccess ); + +} // CTest::GetTimeOfLastChange() + + +//+-------------------------------------------------------------------- +// +// Function: CTest::BindToObject +// +// Synopsis: Create a tracking file moniker, move the link source, +// and attempt to bind to it with a BindToObject. +// Since presumably the temporary file we're using as a link +// source has no server, this will fail. But any failure +// downstream of locating the link source file will be +// ignored. +// +// Inputs: None. +// +// Output: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+-------------------------------------------------------------------- + + +BOOL CTest::BindToObject( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + // ----- + // Begin + // ----- + + wprintf( L"BindToObject()\n" ); + wprintf( L" Create a tracking file moniker, moved the represented file,\n" + L" and attempt a BindToStorage() (which should succeed).\n" ); + + // Create a tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Move the link source file. + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + // Attempt a bind. + + if( !m_cMoniker.BindToObject( )) + EXIT( L"Could not bind to Object" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + DisplayErrors( bSuccess, L"CTest::BindToObject()" ); + return( bSuccess ); + +} // CTest::BindToObject() + + +//+----------------------------------------------------------- +// +// Function: CTest::IPersist +// +// Synopsis: Create a tracking file moniker, move the link +// source, and perform the CMoniker::SaveDeleteLoad +// test. +// +// Inputs: None. +// +// Output: TRUE if successful, FALSE otherwise +// +// Effects: None. +// +//+----------------------------------------------------------- + + +BOOL CTest::IPersist( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + // ----- + // Begin + // ----- + + wprintf( L"IPersist()\n" ); + wprintf( L" Create a tracking file moniker (using CreateFileMonikerEx), and\n" + L" save it to a Stream. Delete the moniker, create a new one using\n" + L" CreateFileMoniker, load it from the Stream, and verify that the resulting\n" + L" file moniker is tracking.\n" ); + + // Create a tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Rename the link source. + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + // Save the moniker, deleted, create a new moniker, and reload it. + + if( !m_cMoniker.SaveDeleteLoad( )) + EXIT( L"Failed SaveDeleteLoad" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + DisplayErrors( bSuccess, L"CTest::IPersist()" ); + return( bSuccess ); + +} // CTest::IPersist() + + +//+---------------------------------------------------------------------- +// +// Function: CTest::ComposeWith +// +// Synopsis: Create a tracking file moniker, and use it in the +// CMoniker::ComposeWith operation. +// +// Inputs: None. +// +// Output: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+---------------------------------------------------------------------- + +BOOL CTest::ComposeWith( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + IMoniker* pmnkReduced = NULL; + WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' )]; + + // ----- + // Begin + // ----- + + m_lError = 0; + + wprintf( L"ComposeWith()\n" ); + wprintf( L" Create a tracking file moniker, and compose it with a non-tracking\n" + L" file moniker on the right. The resulting moniker should be tracking.\n" ); + + // Create the tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Perform the ComposeWith operation. + + if( !m_cMoniker.ComposeWith( )) + EXIT( L"Failed ComposeWith" ); + + // Move the link source file. + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + // Reduce the composed moniker. + + if( !m_cMoniker.Reduce( INFINITE, &pmnkReduced )) + EXIT( L"Could not reduce the moniker" ); + + // Get the display name on the reduced moniker. + + if( !m_cMoniker.GetDisplayName( wszDisplayName, pmnkReduced )) + EXIT( L"Could not get the display name" ); + + // Verify that the name from the moniker is the actual link source + // file's new name. + + if( _wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() )) + EXIT( L"Failed" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + DisplayErrors( bSuccess, L"CTest::ComposeWith()" ); + return( bSuccess ); + +} // CTest::ComposeWith() + + +//+------------------------------------------------------------------ +// +// Function: CTest::BindToStorage +// +// Synopsis: Create a tracking file moniker, and perform the +// CMoniker::BindToStorage operation. +// +// Inputs: None. +// +// Output: TRUE if successful, FALSE otherwise. +// +//+------------------------------------------------------------------ + + +BOOL CTest::BindToStorage( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + // ----- + // Begin + // ----- + + m_lError = 0; + + wprintf( L"BindToStorage()\n" ); + wprintf( L" Create a tracking file moniker (using CreateFileMonikerEx),\n" + L" move the represented file, Reduce the moniker, and get\n" + L" the display name from the reduced moniker. It should be the\n" + L" new file name. This test covers both CreateFileMonikerEx and\n" + L" Reduce.\n" ); + + // Create the tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Move the link source file. + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + // Bind to the Storage + + if( !m_cMoniker.BindToStorage( )) + EXIT( L"Could not bind to Storage" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + DisplayErrors( bSuccess, L"CTest::BindToStorage()" ); + return( bSuccess ); + +} // CTest::BindToStorage() + + +//+-------------------------------------------------------------------------- +// +// Function: CTest::DeleteLinkSource +// +// Synopsis: Create a tracking file moniker, delete the link source, +// and attempt a Reduce. The Reduce should not fail, but +// it should return an HResult of MK_S_REDUCED_TO_SELF. +// +// Inputs: Tick count limit on the length of the Reduce operation. +// +// Output: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+-------------------------------------------------------------------------- + +BOOL CTest::DeleteLinkSource( DWORD dwDelay ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + WCHAR wszTimeout[ 80 ]; + + // ----- + // Begin + // ----- + + m_lError = 0L; + + // Generate a string which shows what the delay is. + + switch( dwDelay ) + { + case 0: + wcscpy( wszTimeout, L"instant timeout" ); + break; + + case INFINITE: + wcscpy( wszTimeout, L"infinite timeout" ); + break; + + default: + wsprintf( wszTimeout, L"%d ms timeout", dwDelay ); + } + + // Display a header. + + wprintf( L"Delete Link Source (%s)\n", + wszTimeout ); + wprintf( L" Create a tracking file moniker, then delete the link source, and\n" + L" attempt a reduce with a %s.\n", + wszTimeout ); + + // Create a tracking file moniker. + + if( !m_cMoniker.CreateFileMonikerEx( ) ) + EXIT( L"Could not CreateFileMonikerEx" ); + + // Delete the link source file. + + if( !m_cMoniker.DeleteTemporaryStorage() ) + EXIT( L"Could not delete temporary storage" ); + + // Tell CMoniker not to alarm the user with error messages. + + m_cMoniker.SuppressErrorMessages( TRUE ); + + // Reduce the moniker, and verify it returns the proper Success code. + + if( !m_cMoniker.Reduce( dwDelay ) + || + m_cMoniker.GetHResult() != MK_S_REDUCED_TO_SELF + ) + EXIT( L"Failed" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + m_cMoniker.SuppressErrorMessages( FALSE ); + + DisplayErrors( bSuccess, L"CTest::DeleteLinkSource()" ); + return( bSuccess ); + +} // CTest::DeleteLinkSource() + + +//+------------------------------------------------------------------ +// +// Function: CTest::GetOversizedBindOpts +// +// Synopsis: Test a bind context's ability to return a BIND_OPTS +// which is larger than expected. +// +// First, initialize the default BIND_OPTS in the bind +// context to 1s. Then, ask for a large BIND_OPTS. +// The resulting buffer should have 1s up to the size of +// the normal BIND_OPTS, and 0s for the remainder of the +// buffer. The length, however, should be that of the large +// buffer. +// +// Inputs: None. +// +// Outputs: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+------------------------------------------------------------------ + + +BOOL CTest::GetOversizedBindOpts( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + BIND_OPTS bind_opts; + LPBIND_OPTS pbind_optsLarge = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ]; + LPBIND_OPTS pbind_optsExpected = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ]; + + // ----- + // Begin + // ----- + + m_lError = 0L; + + wprintf( L"Get Oversized BindOpts\n" ); + wprintf( L" Create a buffer which is much larger than a normal BIND_OPTS, and\n" + L" use it to request the BIND_OPTS from a bind context. The length\n" + L" of the resulting buffer should be the large value, and the extra\n" + L" room in the buffer should be all 0s.\n" ); + + + // Validate our 'new' operations. + + if( pbind_optsLarge == NULL ) + EXIT( L"Could not allocate pbind_optsLarge" ); + pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + if( pbind_optsExpected == NULL ) + EXIT( L"Could not allocate pbind_optsExpected" ); + pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + + // Initialize the bind_opts (normal sized) in the bind context to 1s. + + if( !m_cMoniker.InitializeBindContext() ) + EXIT( L"Could not initialize the bind context" ); + + memset( &bind_opts, 1, sizeof( bind_opts )); + bind_opts.cbStruct = sizeof( bind_opts );; + + m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts ); + if( FAILED( m_lError )) EXIT( L"Could not set original bind options" ); + + // Initialize the large bind_opts to 2s, then retrieve the bind_opts into + // this structure. This is done to verify that the GetBindOptions below + // fills in the entire requested buffer (overwirting all of the 2s). + + memset( pbind_optsLarge, 2, SIZE_OF_LARGE_BIND_OPTS ); + pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( pbind_optsLarge ); + if( FAILED( m_lError )) EXIT( L"Could not get large bind options" ); + + // The returned structure should have the large cbStruct, 1s up to + // the length of BIND_OPTS, and 0s after that. + + memset( pbind_optsExpected, 0, SIZE_OF_LARGE_BIND_OPTS ); + memset( pbind_optsExpected, 1, sizeof( bind_opts )); + pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + if( memcmp( pbind_optsLarge, pbind_optsExpected, SIZE_OF_LARGE_BIND_OPTS )) + EXIT( L"Failed" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + DisplayErrors( bSuccess, L"CTest::GetOversizedBindOpts()" ); + return( bSuccess ); + +} // CTest::GetOversizeBindOpts() + + + +//+---------------------------------------------------------------- +// +// Function: CTest::GetUndersizedBindOpts +// +// Synopsis: Create a bind context, and initialize the data in its +// BIND_OPTS to 1s. Create a normal BIND_OPTS-sized buffer, +// initialize it to 2s, then use it to get a small-sized +// BIND_OPTS from the bind context. The resulting buffer +// should have a small length, a small number of 1s, +// and 2s for the remainder of the buffer. +// +// Inputs: None. +// +// Outputs: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+---------------------------------------------------------------- + + + +BOOL CTest::GetUndersizedBindOpts( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + LPBIND_OPTS pbind_optsSmall = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ]; + LPBIND_OPTS pbind_optsExpected = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ]; + BIND_OPTS bind_opts; + bind_opts.cbStruct = sizeof( bind_opts ); + + // ----- + // Begin + // ----- + + m_lError = 0L; + + wprintf( L"Get Undersized BindOpts\n" ); + wprintf( L" Get the BIND_OPTS from a bind context, but only providing a small\n" + L" buffer, and verify that only that portion of the actual BIND_OPTS\n" + L" is returned.\n" ); + + // Validate our 'new's. + + if( pbind_optsSmall == NULL ) + EXIT( L"Could not allocate pbind_optsSmall" ); + pbind_optsSmall->cbStruct = SIZE_OF_SMALL_BIND_OPTS; + + if( pbind_optsExpected == NULL ) + EXIT( L"Could not allocate pbind_optsExpected" ); + pbind_optsExpected->cbStruct = SIZE_OF_SMALL_BIND_OPTS; + + + // Initialize the bind_opts (normal sized) in the bind context to 1s. + + if( !m_cMoniker.InitializeBindContext() ) + EXIT( L"Could not initialize the bind context" ); + + memset( &bind_opts, 1, sizeof( bind_opts )); + bind_opts.cbStruct = sizeof( bind_opts );; + + m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts ); + if( FAILED( m_lError )) EXIT( L"Could not set original bind options" ); + + + // Initialize the small bind_opts to 2s, then retrieve the bind_opts into + // this structure. + + memset( pbind_optsSmall, 2, SIZE_OF_LARGE_BIND_OPTS ); + pbind_optsSmall->cbStruct = SIZE_OF_SMALL_BIND_OPTS; + + m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( pbind_optsSmall ); + if( FAILED( m_lError )) EXIT( L"Could not get small bind options" ); + + // The returned structure should have the small cbStruct, 1s up to + // the end of the small buffer, and 2s to the end of the real buffer. + + memset( pbind_optsExpected, 2, SIZE_OF_LARGE_BIND_OPTS ); + memset( pbind_optsExpected, 1, SIZE_OF_SMALL_BIND_OPTS ); + pbind_optsExpected->cbStruct = SIZE_OF_SMALL_BIND_OPTS; + + if( memcmp( pbind_optsSmall, pbind_optsExpected, SIZE_OF_LARGE_BIND_OPTS )) + EXIT( L"Failed" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + DisplayErrors( bSuccess, L"CTest::GetUndersizedBindOpts()" ); + return( bSuccess ); + +} // CTest::GetUndersizedBindOpts() + + +//+---------------------------------------------------------------- +// +// Function: CTest::SetOversizedBindOpts +// +// Synopsis: Create a large BIND_OPTS buffer, set it in +// a bind context, and verify that it can be read back. +// +// Inputs: None. +// +// Outputs: TRUE if successful, FALSE otherwise. +// +// Effects: None. +// +//+---------------------------------------------------------------- + +BOOL CTest::SetOversizedBindOpts( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + LPBIND_OPTS pbind_optsLarge = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ]; + LPBIND_OPTS pbind_optsExpected = (LPBIND_OPTS) new BYTE[ SIZE_OF_LARGE_BIND_OPTS ]; + + // ----- + // Begin + // ----- + + wprintf( L"Set Oversized BindOpts\n" ); + wprintf( L" Set a larger-than-usual BIND_OPTS in a bind context, and verify\n" + L" that it can be read back in its entirety.\n" ); + + // Validate our 'new's. + + if( pbind_optsLarge == NULL ) + EXIT( L"Could not allocate pbind_optsLarge" ); + pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + if( pbind_optsExpected == NULL ) + EXIT( L"Could not allocate pbind_optsExpected" ); + pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + // Initialize the large bind_opts to 1s, then set the large BIND_OPTS + // into the bind context. + + if( !m_cMoniker.InitializeBindContext() ) + EXIT( L"Could not initialize the bind context" ); + + memset( pbind_optsLarge, 1, SIZE_OF_LARGE_BIND_OPTS ); + pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( pbind_optsLarge ); + if( FAILED( m_lError )) EXIT( L"Could not set large bind options" ); + + // Get the BIND_OPTS back from the bind context, and verify that it's + // what we set. + + memset( pbind_optsLarge, 0, SIZE_OF_LARGE_BIND_OPTS ); + pbind_optsLarge->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( pbind_optsLarge ); + + memset( pbind_optsExpected, 1, SIZE_OF_LARGE_BIND_OPTS ); + pbind_optsExpected->cbStruct = SIZE_OF_LARGE_BIND_OPTS; + + if( memcmp( pbind_optsLarge, pbind_optsExpected, SIZE_OF_LARGE_BIND_OPTS )) + EXIT( L"Failed" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + DisplayErrors( bSuccess, L"CTest::SetOversizedBindOpts()" ); + return( bSuccess ); + +} // CTest::SetOversizeBindOpts() + + +//+------------------------------------------------------------ +// +// Function: CTest::SetUndersizedBindOpts +// +// Synopsis: Create a bind context, and initialize its BIND_OPTS to +// all 1s. Then, set a small BIND_OPTS in the bind context +// which is set to 2s. Read back the whold BIND_OPTS, and +// verify that it has the normal length, 2s at the +// beginning, and 1s to the end. +// +// Inputs: None. +// +// Output: TRUE if successful, FALSE otherwise. +// +//+------------------------------------------------------------ + + +BOOL CTest::SetUndersizedBindOpts( ) +{ + // --------------- + // Local Variables + // --------------- + + BOOL bSuccess = FALSE; + + BIND_OPTS bind_opts; + BIND_OPTS bind_optsExpected; + + // ----- + // Begin + // ----- + + m_lError = 0L; + + wprintf( L"Set Undersized BindOpts\n" ); + wprintf( L" Initialize a BIND_OPTS in a bind context to 1s, then set a smaller\n" + L" BIND_OPTS in it set to 2s. When the buffer is read back, it should\n" + L" have 2s up to the small buffer size, followed by 1s.\n" ); + + // Initialize the bind context's BIND_OPTS (normal sized) to 1s. + + if( !m_cMoniker.InitializeBindContext() ) + EXIT( L"Could not initialize the bind context" ); + + memset( &bind_opts, 1, sizeof( bind_opts )); + bind_opts.cbStruct = sizeof( bind_opts ); + m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts ); + if( FAILED( m_lError )) EXIT( L"Could not set initial BIND_OPTS" ); + + // Now set a smaller BIND_OPTS. But initialize the local BIND_OPTS to all + // 2s, so that we can verify that only part of the buffer is put into the + // bind context. + + memset( &bind_opts, 2, sizeof( bind_opts ) ); + bind_opts.cbStruct = SIZE_OF_SMALL_BIND_OPTS; + m_lError = m_cMoniker.GetBindCtx()->SetBindOptions( &bind_opts ); + if( FAILED( m_lError )) EXIT( L"Could not set small BIND_OPTS" ); + + // The resulting BIND_OPTS in the bind context should have 2s up + // to SIZE_OF_SMALL_BIND_OPTS, and 1s for the remainder of the buffer. + + bind_opts.cbStruct = sizeof( bind_opts ); + m_lError = m_cMoniker.GetBindCtx()->GetBindOptions( &bind_opts ); + if( FAILED( m_lError )) EXIT( L"Could not get BIND_OPTS" ); + + memset( &bind_optsExpected, 1, sizeof( bind_opts )); + memset( &bind_optsExpected, 2, SIZE_OF_SMALL_BIND_OPTS ); + bind_optsExpected.cbStruct = sizeof( bind_opts ); + + if( memcmp( &bind_opts, &bind_optsExpected, sizeof( bind_opts ))) + EXIT( L"Failed" ); + + + bSuccess = TRUE; + + // ---- + // Exit + // ---- + +Exit: + + DisplayErrors( bSuccess, L"CTest::SetUndersizedBindOpts()" ); + return( bSuccess ); + +} // CTest::SetUndersizedBindOpts() + + +#ifdef _FUTURE_ + +BOOL CTest::CFMWithRegistryClear( ) +{ + BOOL bSuccess = FALSE; + WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' ) ]; + + if( !m_cMoniker.SaveRegistryTrackFlags() ) + EXIT( L"Could not save the existing track flags in the registry" ); + + if( !m_cMoniker.DeleteRegistryTrackFlags() ) + EXIT( L"Could not delete the existing track flags in the registry" ); + + if( !m_cMoniker.CreateFileMoniker() ) + EXIT( L"Could not CreateFileMoniker" ); + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + if( !m_cMoniker.GetDisplayName( wszDisplayName )) + EXIT( L"Could not get the display name" ); + + if( !_wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() )) + EXIT( L"Test failed: A moniker was created using CreateFileMoniker, after\n" + L" the Track Flags had been cleared from the Registry.\n" + L" The underlying root storage was then renamed.\n" + L" But a GetDisplayName then showed the new name, implying\n" + L" that the created moniker is using tracking (which it\n" + L" should not, because without the Track Flags set there\n" + L" should be no tracking).\n" ); + + + bSuccess = TRUE; + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + if( !m_cMoniker.RestoreRegistryTrackFlags() ) + ERROR_IN_EXIT( L"Could not restore Track Flags in Registry" ); + + + DisplayErrors( bSuccess, L"CTest::CFMWithRegistryClear" ); + return( bSuccess ); + +} // CTest::CFMWithRegistryClear + + + + +BOOL CTest::CFMWithRegistrySet( ) +{ + BOOL bSuccess = FALSE; + WCHAR wszDisplayName[ MAX_PATH + sizeof( L'\0' ) ]; + + if( !m_cMoniker.SaveRegistryTrackFlags() ) + EXIT( L"Could not save the existing track flags in the registry" ); + + if( !m_cMoniker.SetTrackFlagsInRegistry( TRACK_LOCALONLY ) ) + EXIT( L"Could not set track flags in the registry" ); + + if( !m_cMoniker.CreateFileMoniker() ) + EXIT( L"Could not CreateFileMoniker" ); + + if( !m_cMoniker.RenameTemporaryStorage() ) + EXIT( L"Could not rename the temporary storage file" ); + + if( !m_cMoniker.GetDisplayName( wszDisplayName )) + EXIT( L"Could not get the display name" ); + + if( _wcsicmp( wszDisplayName, m_cMoniker.GetTemporaryStorageName() )) + EXIT( L"Test failed: A moniker was created using CreateFileMoniker, after\n" + L" setting the TRACK_LOCALONLY flag in the Registry.\n" + L" However, after moving the linked file, GetDisplayName\n" + L" did not return the new name.\n" ); + + + bSuccess = TRUE; + +Exit: + + m_cMoniker.DeleteTemporaryStorage(); + + if( !m_cMoniker.RestoreRegistryTrackFlags() ) + ERROR_IN_EXIT( L"Could not restore Track Flags in Registry" ); + + + DisplayErrors( bSuccess, L"CTest::CFMWithRegistrySet()" ); + return( bSuccess ); + +} // CTest::CFMWithRegistrySet + + +#endif // _FUTURE_ diff --git a/private/oleutest/cfmex/ctest.hxx b/private/oleutest/cfmex/ctest.hxx new file mode 100644 index 000000000..32d1e0012 --- /dev/null +++ b/private/oleutest/cfmex/ctest.hxx @@ -0,0 +1,118 @@ + + +//+================================================================ +// +// File: CTest.hxx +// +// Purpose: Declare the CTest class. +// +// This class is the test engine for the CreateFileMonikerEx +// API (CFMEx) DRTs. +// +//+================================================================ + +#ifndef _C_TEST_HXX_ +#define _C_TEST_HXX_ + +// -------- +// Includes +// -------- + +#include "CDir.hxx" + +// ----- +// CTest +// ----- + +class CTest +{ + +// (De)Construction + +public: + + CTest( ); + ~CTest(); + +// Public member routines. + +public: + + BOOL Initialize( const CDirectory& cDirectoryOriginal, + const CDirectory& cDirectoryFinal ); + BOOL CreateFileMonikerEx(); + BOOL BindToStorage(); + BOOL BindToObject(); + BOOL IPersist(); + BOOL ComposeWith(); + BOOL GetDisplayName(); + BOOL GetTimeOfLastChange(); + BOOL DeleteLinkSource( DWORD dwDelay = INFINITE ); + + BOOL GetOversizedBindOpts(); + BOOL GetUndersizedBindOpts(); + BOOL SetOversizedBindOpts(); + BOOL SetUndersizedBindOpts(); + +// Private member routines. + +private: + + void DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName ); + +// Private member variables. + +private: + + CMoniker m_cMoniker; + long m_lError; + WCHAR m_wszErrorMessage[ 512 ]; + + const CDirectory* m_pcDirectoryOriginal; + const CDirectory* m_pcDirectoryFinal; + +}; + + +// -------------- +// Inline Members +// -------------- + +#define OUTFILE stdout + +inline void CTest::DisplayErrors( BOOL bSuccess, WCHAR * wszFunctionName ) +{ + if( !bSuccess ) + fwprintf( OUTFILE, L"Error in %s (%08x)\n %s \n", + wszFunctionName, m_lError, m_wszErrorMessage ); +} + + +// ------ +// Macros +// ------ + +#undef EXIT +#define EXIT( error ) \ + {\ + wcscpy( m_wszErrorMessage, ##error );\ + goto Exit;\ + } + + +#define ERROR_IN_EXIT( error ) \ + {\ + wcscpy( m_wszErrorMessage, ##error );\ + bSuccess = FALSE; \ + } + + +// ------- +// Defines +// ------- + +#define SIZE_OF_LARGE_BIND_OPTS ( 2 * sizeof( BIND_OPTS2 )) +#define SIZE_OF_SMALL_BIND_OPTS ( 3 * sizeof( DWORD )) + +#endif // _C_TEST_HXX_ + diff --git a/private/oleutest/cfmex/makefile b/private/oleutest/cfmex/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/oleutest/cfmex/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/oleutest/cfmex/sources b/private/oleutest/cfmex/sources new file mode 100644 index 000000000..0bfd19e12 --- /dev/null +++ b/private/oleutest/cfmex/sources @@ -0,0 +1,35 @@ +!IF 0 + +Copyright (c) 1995 Microsoft Corporation + +!ENDIF + +MAJORCOMP= appl +MINORCOMP= windows +TARGETNAME= CFMEx +TARGETPATH= obj +TARGETTYPE= LIBRARY + + + +INCLUDES=. + +C_DEFINES= \ + $(C_DEFINES) + + +SOURCES= CDir.cxx CMoniker.cxx CTest.cxx + +UMTYPE= console +UMAPPL= CFMEx + +UMLIBS= .\obj\*\CFMEx.lib \ + $(BASEDIR)\public\sdk\lib\cairo\*\ole32.lib \ + $(WIN32_LIBS) \ + $(GUI32_LIBS) \ + $(BASEDIR)\public\sdk\lib\*\uuid.lib \ + $(BASEDIR)\public\sdk\lib\i386\oleaut32.lib \ + $(BASEDIR)\public\sdk\lib\cairo\i386\dsysuuid.lib + + +CAIRO_PRODUCT=1 -- cgit v1.2.3