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

2255 lines
60 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1993.
//
// File: cmonimp.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 12-27-93 ErikGav Created
// 16-May-94 AlexT Removed reference variables
// Added support for '!' in paths
// 21-Jun-94 KentCe Corrected string dup routine.
// 11-Nov-94 BruceMa Make use of GetLongPathName more efficient
// and enable its use for Chicago
// 20-Jul-95 BruceMa Rewrote MkParseDisplayName
// Rewrote FindMaximalFileName
// General cleanup
// 22-Sep-95 MikeHill Added CreateFileMonikerEx
// 29-Nov-95 MikeHill Added ValidateBindOpts().
//
//----------------------------------------------------------------------------
#include <ole2int.h>
#include <io.h>
#include "cbasemon.hxx"
#include "citemmon.hxx"
#include "cfilemon.hxx"
#include "cantimon.hxx"
#include "cbindctx.hxx"
#include "cptrmon.hxx"
#include "mnk.h"
#include "rothint.hxx"
#include "crot.hxx"
#include "classmon.hxx"
#include <longname.h>
#define IsFileSystemSeparator(ch) ('\\' == (ch) || ':' == (ch))
#define IsItemMonikerSeparator(ch) ('!' == (ch) || '/' == (ch) || '[' == (ch) || '#' == (ch))
#define IsDriveLetter(ch) ( ( (ch) >= L'A' && (ch) <= L'Z') || ( (ch) >= L'a' && (ch) <= L'z'))
#ifdef _CAIRO_
//+---------------------------------------------------------------------------
//
// Function: ValidateBindOpts
//
// Synopsis: Validates the fields of a BIND_OPTS (or BIND_OPTS2) structure with
// respect to file monikers.
//
// Effects: Outputs a debugger message if an invalid condition is found.
//
// Arguments: [pbind_opts] -- Pointer to a BIND_OPTS or BIND_OPTS2 structure.
//
// Requires: None.
//
// Returns: TRUE if valid. FALSE otherwise.
//
// Signals: None.
//
// Modifies: None.
//
// Algorithm: Verify that bits set in dwTrackFlags are defined.
//
// History: 11-29-95 MikeHill Created.
//
// Notes: This routine can process either BIND_OPTS or BIND_OPTS2 structures,
// but the latter must be cast as an LPBIND_OPTS.
//
//----------------------------------------------------------------------------
BOOL ValidateBindOpts( const LPBIND_OPTS pbind_opts )
{
Assert( pbind_opts != NULL );
// Validate fields that only exist in BIND_OPTS2.
if( pbind_opts->cbStruct >= sizeof( BIND_OPTS2 ))
{
const LPBIND_OPTS2 &pbind_opts2 = (const LPBIND_OPTS2) pbind_opts;
// Verify the TRACK_FLAGS.
if( pbind_opts2->dwTrackFlags & ~TRACK_FLAGS_MASK )
{
mnkDebugOut(( DEB_ITRACE,
"ValidateBindOpts: Invalid TRACK_FLAGS (%x)\n",
pbind_opts2->dwTrackFlags ));
return( FALSE );
}
}
// No error conditions were found, so we'll declare this a valid Bind Opts.
return( TRUE );
} // ValidateBindOpts
#endif // _CAIRO_
//+---------------------------------------------------------------------------
//
// Function: DupWCHARString
//
// Synopsis: Duplicate a WCHAR string
//
// Effects:
// lpwcsOutput is allocated via PrivMemAlloc(), and lpwcsString
// is copied into it.
//
// Arguments: [lpwcsString] -- String to dup
// [lpwcsOutput] -- Reference to new string pointer
// [ccOutput] -- Reference to character count in string
//
// Requires:
//
// Returns:
// If lpwcsString == NULL, then lpwcsOutput == NULL, and
// ccOutput == 0.
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 1-16-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT DupWCHARString(LPCWSTR lpwcsString,
LPWSTR & lpwcsOutput,
USHORT & ccOutput)
{
if (lpwcsString != NULL)
{
ccOutput = lstrlenW(lpwcsString);
lpwcsOutput = (WCHAR *)PrivMemAlloc(sizeof(WCHAR)*(1+ccOutput));
if (lpwcsOutput != NULL)
{
memcpy(lpwcsOutput, lpwcsString, (ccOutput + 1) * sizeof(WCHAR));
return(NOERROR);
}
else
{
return(E_OUTOFMEMORY);
}
}
lpwcsOutput = NULL;
ccOutput = 0;
return(NOERROR);
}
STDAPI CreateItemMoniker ( LPCWSTR lpszDelim, LPCWSTR lpszItem,
LPMONIKER FAR * ppmk )
{
OLETRACEIN((API_CreateItemMoniker, PARAMFMT("lpszDelim= %ws, lpszItem= %ws, ppmk= %p"),
lpszDelim, lpszItem, ppmk));
mnkDebugOut((DEB_ITRACE,
"CreateItemMoniker lpszDelim(%ws) lpszItem(%ws)\n",
lpszDelim?lpszDelim:L"<NULL>",
lpszItem?lpszItem:L"<NULL>"));
CItemMoniker FAR * pCIM;
HRESULT hresult;
VDATEPTROUT_LABEL(ppmk,LPMONIKER, errRtn, hresult);
VDATEPTRIN_LABEL(lpszDelim,WCHAR, errRtn, hresult);
*ppmk = NULL;
//VDATEPTRIN rejects NULL
if( lpszItem )
VDATEPTRIN_LABEL(lpszItem,WCHAR, errRtn, hresult);
pCIM = CItemMoniker::Create(lpszDelim, lpszItem);
if (pCIM)
{
*ppmk = (LPMONIKER)pCIM;
CALLHOOKOBJECTCREATE(S_OK,CLSID_ItemMoniker,IID_IMoniker,(IUnknown **)ppmk);
hresult = NOERROR;
}
else
{
hresult = ResultFromScode(E_OUTOFMEMORY);
}
errRtn:
OLETRACEOUT((API_CreateItemMoniker, hresult));
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: IsAbsolutePath
//
// Synopsis: Returns true if the path starts with a drive letter, or
// with a UNC delimiter ('\\')
//
// Effects:
//
// Arguments: [szPath] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 3-03-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL IsAbsolutePath (LPCWSTR szPath)
{
if (NULL==szPath || *szPath == '\0')
{
return FALSE;
}
if (*szPath == '\\')
{
// return TRUE if UNC path
return (szPath[1] == '\\');
}
//
// If the second character is a ':', then
// it could very well be a drive letter and a ':'
//
// We could test for valid drive letters, but we don't have a really
// compelling reason to do so. It will either work or fail later
//
return (szPath[1] == ':');
}
//+---------------------------------------------------------------------------
//
// Function: IsAbsoluteNonUNCPath
//
// Synopsis: Returns true if the path is an absolute, non UNC path
//
// Effects:
//
// Arguments: [szPath] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 3-03-94 kevinro Created
// 04-27-94 darryla changed to return FALSE if first char
// a \ since either relative or UNC
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL IsAbsoluteNonUNCPath (LPCWSTR szPath)
{
if (NULL==szPath || *szPath == '\0')
{
return FALSE;
}
if (*szPath == '\\')
{
// return FALSE since it is either a UNC path or a relative
// path like \foo
return FALSE;
}
//
// If the second character is a ':', then
// it could very well be a drive letter and a ':'
//
// We could test for valid drive letters, but we don't have a really
// compelling reason to do so. It will either work or fail later
//
return (szPath[1] == ':');
}
//+---------------------------------------------------------------------------
//
// Function: FindUNCEndServer
//
// Synopsis: Finds the end of the server section of a UNC path
//
// Effects:
//
// Arguments: [lpszPathName] -- Path to search for UNC prefix
// [endServer] -- Returned offset to end of UNC name
//
// Requires:
//
// Returns:
// If the path is a UNC name, then endServer will point to the first
// character of the 'path' section.
//
// For example, \\server\share\path would return with endServer = 14
// or \\server\share would also return with endServer = 14.
//
// If the path isn't of this form, endServer == DEF_ENDSERVER on return.
// Also, we need to make sure that if the form is ill-formed, we
// mislead later steps into thinking this is a real UNC name. For
// example, \\server\ is ill-formed and would later be treated as a
// real UNC name.
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 1-11-94 kevinro Created
// 03-27-94 darryla Changed to catch \\server\share legal
// form and illegal \\server\.
//
// Notes:
//
//----------------------------------------------------------------------------
void FindUNCEndServer(LPCWSTR lpszPathName, USHORT *pendServer)
{
if (lpszPathName[0] == '\\' && lpszPathName[1] == '\\')
{
//
// Need to find the second slash following the UNC delimiter
//
ULONG ulCountDown = 2;
//
// Found UNC prefix. Now find the second backslash
//
for(*pendServer = 2 ; lpszPathName[*pendServer] != 0 ; (*pendServer)++)
{
if (lpszPathName[*pendServer] == '\\')
{
if( --ulCountDown == 0)
{
return;
}
}
}
// If we reached the end of the string and found one \, then we
// have the form \\server\share and the *pendServer is the terminator
// as long as we aren't looking at \\server\.
if(lpszPathName[*pendServer] == '\0' &&
ulCountDown == 1 &&
lpszPathName[*pendServer - 1] != '\\')
{
return;
}
}
*pendServer = DEF_ENDSERVER;
}
//+---------------------------------------------------------------------------
//
// Function: ExpandUNCName
//
// Synopsis: Given a path, determine a UNC share to it
//
// Effects:
//
// Arguments: [lpszIn] -- Path to determine UNC name of
// [lplpszOut] -- Output UNC name, allocated using new
// [pEndServer] -- Output USHORT offset to start of actual path
//
// Requires:
// lpszIn should be of the form 'A:\<path>'
//
// Returns:
//
// lplpszOut can return as NULL if there was no UNC path available. In
// this case, the caller should just use the normal string
//
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 1-11-94 kevinro Created
// 05-25-94 AlexT Use WNetGetUniversalName for non-Chicago
// 06-15-94 AlexT Only call WNetGetUniversalName for remote
//
// Notes:
//
//----------------------------------------------------------------------------
#ifdef _CAIRO_
// We need to pass a buffer to WNetGetUniversalName which will get filled in
// with a UNIVERSAL_NAME_INFOW structure plus a universal path which
// can be up to MAX_PATH long.
#define UNIVERSAL_NAME_BUFFER_SIZE (sizeof(UNIVERSAL_NAME_INFOW) + \
MAX_PATH * sizeof(WCHAR) )
#else
// We need to pass a buffer to WNetGetUniversalName which will get filled in
// with a REMOTE_NAME_INFO structure add three strings - a universal path
// (can be up to MAX_PATH long) and a remote connection and remaing path
// (these last two will be at most MAX_PATH + 1 characters).
#define REMOTE_NAME_BUFFER_SIZE (sizeof(REMOTE_NAME_INFO) + \
MAX_PATH * sizeof(WCHAR) + \
(MAX_PATH + 1) * sizeof(WCHAR))
#endif
INTERNAL ExpandUNCName ( LPWSTR lpszIn, LPWSTR FAR * lplpszOut, USHORT FAR* pEndServer )
{
mnkDebugOut((DEB_ITRACE,
"%p _IN ExpandUNCName (%ws, %p, %p)\n",
NULL, lpszIn, lplpszOut, pEndServer));
WCHAR szDevice[] = L"A:\\";
ULONG ulDriveType;
*pEndServer = DEF_ENDSERVER;
*szDevice = *lpszIn;
Assert(lpszIn[1] == ':');
ulDriveType = GetDriveType(szDevice);
mnkDebugOut((DEB_ITRACE,
"ExpandUNCName: GetDriveType(%ws) says %s (%x)\n",
szDevice,
ulDriveType==DRIVE_REMOTE?"DRIVE_REMOTE":"not remote",
ulDriveType));
#ifdef _CHICAGO_
//
// Note: szRemoteName doesn't really need to be this big. Need to
// findout what the largest \\server\share combination is allowed, and
// use that as the size.
//
WCHAR szRemoteName[MAX_PATH];
DWORD cbRemoteName = MAX_PATH;
HRESULT hr = NOERROR;
int lenRemoteName;
int lenIn;
//
// If this is a remote drive, attempt to get the UNC path that maps
// to it.
//
//
// The device name needs to be A:, not a root like the other API wanted.
//
szDevice[2] = 0;
if (ulDriveType == DRIVE_REMOTE &&
(WN_SUCCESS == (hr = OleWNetGetConnection(szDevice, szRemoteName,&cbRemoteName))))
{
//
// Allocate a buffer large enough to hold the UNC server and share,
// plus the size of the path
//
//
lenRemoteName = lstrlenW(szRemoteName);
lenIn = lstrlenW(lpszIn);
//
// Make sure we aren't about to create a path that is too large.
//
//
// (lenIn - 2) removes the space required by the drive and the
// colon, which are not going to be copied
//
if ((lenRemoteName + lenIn - 2) > MAX_PATH)
{
hr = MK_E_SYNTAX;
goto errRet;
}
//
// Allocate room for the concatenated string. The length of the
// buffer is the length of the remote name, plus the length of the
// input string. Subtract from that the drive + colon (2 WCHARS),
// then add back room for a terminating NULL. This is where
// (lenIn - 1) is derived
//
*lplpszOut = (WCHAR *)
PrivMemAlloc(sizeof(WCHAR) * (lenRemoteName + (lenIn - 1)));
if( !*lplpszOut )
{
hr = ResultFromScode(E_OUTOFMEMORY);
goto errRet;
}
memcpy( *lplpszOut, szRemoteName, lenRemoteName * sizeof(WCHAR));
//
// We know that the lpszIn is of the form A:\path and we want to end
// up with \\server\share\path. Skipping the first two characters of
// lpszIn should suffice. Copying (lenIn - 1) characters makes us
// copy over the NULL character from lpszIn
//
memcpy( *lplpszOut + lenRemoteName, lpszIn + 2, (lenIn - 1) * sizeof(WCHAR));
//
// EndServer is the offset to the start of the 'path'. It should point at the
// first backslash
//
*pEndServer = lenRemoteName;
}
else
{
//
// Its possible that WNetGetConnection failed. In this case, we
// can only use the path that we were given.
//
if (ulDriveType == DRIVE_REMOTE)
{
mnkDebugOut((DEB_IERROR,
"ExpandUNCName: WNetGetConnection(%ws) failed (%x)\n",
szDevice,
hr));
}
//
// There was no UNC form of this path. Set the output pointer to be
// NULL
//
// NOTE:
//
// This would be a very good place to determine if the given path
// has a UNC equivalent, even if it is a local drive.
//
*lplpszOut = NULL;
*pEndServer = DEF_ENDSERVER;
}
errRet:
#else
//
// If this is a remote drive, attempt to get the UNC path that maps
// to it.
//
HRESULT hr = NOERROR;
# ifdef _CAIRO_
// BUGBUG: [mikese] This is the correct thing to do -- use the universal path the
// provider gives back to us. The Daytona code is broken.
BYTE abInfoBuffer[UNIVERSAL_NAME_BUFFER_SIZE];
DWORD dwBufferSize = UNIVERSAL_NAME_BUFFER_SIZE;
if ((DRIVE_REMOTE == ulDriveType) &&
(WN_SUCCESS == OleWNetGetUniversalName(lpszIn, UNIVERSAL_NAME_INFO_LEVEL,
abInfoBuffer, &dwBufferSize)))
{
UNIVERSAL_NAME_INFOW * pUniversalInfo = (UNIVERSAL_NAME_INFOW*)abInfoBuffer;
int cchPath = lstrlenW ( pUniversalInfo->lpUniversalName );
// Allocate space to copy the path, including the terminating null
*lplpszOut = (WCHAR *) PrivMemAlloc(sizeof(WCHAR) * (cchPath + 1));
if( *lplpszOut == NULL )
{
hr = ResultFromScode(E_OUTOFMEMORY);
goto errRet;
}
memcpy(*lplpszOut, pUniversalInfo->lpUniversalName,
(cchPath + 1) * sizeof(WCHAR));
FindUNCEndServer ( *lplpszOut, pEndServer );
}
# else
// Daytona. This isn't really correct.
BYTE abInfoBuffer[REMOTE_NAME_BUFFER_SIZE];
LPREMOTE_NAME_INFO pRemoteNameInfo;
DWORD dwBufferSize;
int cchConnectionName;
int cchRemainingPath;
//
// If this is a remote drive, attempt to get the UNC path that maps
// to it.
//
pRemoteNameInfo = (LPREMOTE_NAME_INFO) abInfoBuffer;
dwBufferSize = REMOTE_NAME_BUFFER_SIZE;
if ((DRIVE_REMOTE == ulDriveType) &&
(WN_SUCCESS == OleWNetGetUniversalName(lpszIn, REMOTE_NAME_INFO_LEVEL,
pRemoteNameInfo, &dwBufferSize)))
{
// Got it
cchConnectionName = lstrlenW(pRemoteNameInfo->lpConnectionName);
cchRemainingPath = lstrlenW(pRemoteNameInfo->lpRemainingPath);
//
// Make sure we aren't about to create a path that is too large.
//
if ((cchConnectionName + cchRemainingPath + 1) > MAX_PATH)
{
hr = MK_E_SYNTAX;
goto errRet;
}
// Allocate room for the concatenated string. The length of the
// buffer is the length of the remote name, plus the length of the
// remaining path, plus room for a terminating NULL.
*lplpszOut = (WCHAR *)
PrivMemAlloc(sizeof(WCHAR) * (cchConnectionName + cchRemainingPath + 1));
if( !*lplpszOut )
{
hr = ResultFromScode(E_OUTOFMEMORY);
goto errRet;
}
memcpy(*lplpszOut, pRemoteNameInfo->lpConnectionName,
cchConnectionName * sizeof(WCHAR));
memcpy(*lplpszOut + cchConnectionName, pRemoteNameInfo->lpRemainingPath,
(cchRemainingPath + 1) * sizeof(WCHAR));
//
// EndServer is the offset to the start of the 'path'. It should point at the
// first backslash
//
*pEndServer = cchConnectionName;
}
#endif
else
{
#if DBG==1
if (DRIVE_REMOTE == ulDriveType)
{
mnkDebugOut((DEB_ITRACE,
"Local drive or WNetGetUniversalName failed - %ld\n",
GetLastError()));
}
#endif
//
// There was no UNC form of this path. Set the output pointer to be
// NULL
//
// NOTE:
//
// This would be a very good place to determine if the given path
// has a UNC equivalent, even if it is a local drive.
//
*lplpszOut = NULL;
*pEndServer = DEF_ENDSERVER;
}
errRet:
#endif // !_CHICAGO_
mnkDebugOut((DEB_ITRACE,
"%p OUT ExpandUNCName (%lx) [%ws, %d]\n",
NULL, hr, *lplpszOut ? *lplpszOut : L"<NULL>",
*pEndServer));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CreateFileMoniker
//
// Synopsis: Creates a FileMoniker
//
// Effects:
//
// Arguments: [lpszPathName] -- Path to create moniker to
// [ppmk] -- Output moniker interface pointer
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 1-11-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI CreateFileMoniker ( LPCWSTR lpszPathName, LPMONIKER FAR * ppmk )
{
OLETRACEIN((API_CreateFileMoniker, PARAMFMT("lpszPathName= %ws, ppmk= %p"),
lpszPathName, ppmk));
mnkDebugOut((DEB_TRACE,
"CreateFileMoniker(%ws)\n",
lpszPathName?lpszPathName:L"<NULL PATH>"));
HRESULT hresult = NOERROR;
CFileMoniker FAR * pCFM = NULL;
USHORT endServer = DEF_ENDSERVER;
*ppmk = NULL;
LPWSTR lpsz = NULL;
WCHAR szBuffer[MAX_PATH+1];
LPOLESTR posPath;
if (NULL == lpszPathName)
{
return MK_E_SYNTAX;
}
VDATEPTROUT_LABEL(ppmk,LPMONIKER, errNoHookRet, hresult);
VDATEPTRIN_LABEL(lpszPathName,WCHAR, errNoHookRet, hresult);
//
// If this is an absolute path, then create as strong of a link to it
// that we can. If not, then its relative, just use the name.
//
// BUGBUG - IsAbsoluteNonUNCPath will return TRUE for relative
// paths like a:foo. Is this a bug or is the function poorly named?
if ( IsAbsoluteNonUNCPath(lpszPathName))
{
mnkDebugOut((DEB_ITRACE,
"CreateFileMoniker(%ws) Is absolute path\n",
lpszPathName?lpszPathName:L"<NULL PATH>"));
szBuffer[MAX_PATH] = 0;
//
// GetFullPathName resolves, using the current directory and drive,
// the path into as much of a normal form as possible
//
LPWSTR pszFilePart;
if (!GetFullPathName(lpszPathName, MAX_PATH, szBuffer, &pszFilePart))
{
hresult = ResultFromScode(MK_E_SYNTAX);
goto errRet;
}
//
// We now demand to have a drive based path.
//
if (*(szBuffer + 1) != ':')
{
hresult = ResultFromScode(MK_E_SYNTAX);
goto errRet;
}
Assert(*(szBuffer + 1) == ':');
hresult = ExpandUNCName( szBuffer, &lpsz, &endServer);
mnkDebugOut((DEB_ITRACE,
"CreateFileMoniker(%ws) Expanded name (%ws)\n",
lpszPathName?lpszPathName:L"<NULL PATH>",
lpsz?lpsz:szBuffer));
if (hresult != NOERROR)
{
goto errRet;
}
posPath = lpsz ? lpsz : szBuffer;
}
else
{
//
// If this is a UNC path, then we need to set the
// m_endServer variable. Otherwise, it defaults to DEF_ENDSERVER
//
mnkDebugOut((DEB_ITRACE,
"CreateFileMoniker(%ws) Is relative path\n",
lpszPathName?lpszPathName:L"<NULL PATH>"));
FindUNCEndServer(lpszPathName, &endServer);
posPath = (LPOLESTR)lpszPathName;
}
// Now that we have a path, expand each component into its long
// form so that monikers create with short names equal their
// long name equivalents
// This only works for files that exist, so if it fails
// simply use the given path
DWORD cchLong, cchDone;
LPOLESTR posLong;
WCHAR wcsTmp[MAX_PATH];
posLong = NULL;
// Special case zero-length paths since the length returns from
// GetLongPathName become ambiguous when zero characters are processed
if (posPath[0])
{
// Attempt to build the long path on the stack
cchLong = GetLongPathNameW(posPath, wcsTmp, MAX_PATH);
// Check for failure
if (cchLong > 0)
{
// Check if stack array was large enough
if (cchLong < MAX_PATH)
{
posPath = wcsTmp;
mnkDebugOut((DEB_ITRACE, "CreateFileMoniker: "
"Lengthened '%ws' to '%ws'\n",
posPath, wcsTmp));
}
// Need to use a larger buffer
else
{
posLong = (LPOLESTR)PrivMemAlloc(cchLong*sizeof(WCHAR));
if (posLong == NULL)
{
goto ErrNoLongMem;
}
cchDone = GetLongPathNameW(posPath, posLong, cchLong);
Win4Assert(cchDone != 0 &&
"GetLongPathNameW shouldn't fail");
mnkDebugOut((DEB_ITRACE, "CreateFileMoniker: "
"Lengthened '%ws' to '%ws'\n",
posPath, posLong));
posPath = posLong;
}
}
}
else
{
mnkDebugOut((DEB_ITRACE, "CreateFileMoniker: No long path for '%ws'\n",
posPath));
}
pCFM = CFileMoniker::Create(posPath,
0,
endServer);
if (posLong != NULL)
{
PrivMemFree(posLong);
}
ErrNoLongMem:
if (lpsz != NULL)
{
PrivMemFree(lpsz);
}
if (!pCFM)
{
hresult = ResultFromScode(E_OUTOFMEMORY);
goto errRet;
}
*ppmk = (LPMONIKER)pCFM;
errRet:
CALLHOOKOBJECTCREATE(hresult, CLSID_FileMoniker, IID_IMoniker, (IUnknown **)ppmk); // HOOKOLE
errNoHookRet:
OLETRACEOUT((API_CreateFileMoniker, hresult));
return hresult;
}
#ifdef _CAIRO_
//+---------------------------------------------------------------------------
//
// Function: CreateFileMonikerEx
//
// Synopsis: Creates a tracking FileMoniker.
//
// Effects:
//
// Arguments: [DWORD] dwTrackFlags
// -- Tracking flags ("TRACK_*").
// [LPCWSTR] lpszPathName
// -- Path to which to create the moniker.
// [LPMONIKER FAR *] pmk
// -- Output moniker interface pointer.
//
// Requires:
//
// Returns: [HRESULT]
//
// Signals: None.
//
// Modifies: None.
//
// Algorithm: Create a FileMoniker, and initializes the tracking
// state.
//
// History: 9-20-95 MikeHill Created
//
// Notes: This function was added to extend the CreateFileMoniker
// API for the newer tracking file monikers. This allows
// the caller to configure the tracking algorithm (with the
// dwTrackFlags) at creation time.
//
//----------------------------------------------------------------------------
STDAPI CreateFileMonikerEx (DWORD dwTrackFlags,
LPCWSTR lpszPathName,
LPMONIKER FAR * ppmk )
{
OLETRACEIN((API_CreateFileMoniker, PARAMFMT("lpszPathName= %ws, ppmk= %p"),
lpszPathName, ppmk));
mnkDebugOut( (DEB_TRACE,
"CreateFileMonikerEx(%ws)\n",
lpszPathName?lpszPathName:L"<NULL PATH>"));
HRESULT hresult = E_FAIL;
VDATEPTROUT_LABEL(ppmk,LPMONIKER, errNoHookRet, hresult);
VDATEPTRIN_LABEL(lpszPathName,WCHAR, errNoHookRet, hresult);
*ppmk = NULL;
// Create a default (i.e. non-tracking) File Moniker.
if( FAILED( hresult = CreateFileMoniker( lpszPathName,
ppmk ))
)
{
goto errRet;
}
Assert( *ppmk != NULL );
// Perform the tracking-related initialization of this moniker.
// Note that the Track Flags are piggy-backed onto the
// EnableTracking routine's OT flags.
hresult = ( (CFileMoniker *) *ppmk)->EnableTracking( NULL,
TRACK_2_OT_FLAGS( dwTrackFlags )
|
OT_MAKETRACKING
);
if( FAILED( hresult ))
{
goto errRet;
}
// ----
// Exit
// ----
errRet:
// Return S_OK unless there was an error. (Word considers everything
// except S_OK to be fatal).
hresult = SUCCEEDED( hresult ) ? S_OK : hresult;
CALLHOOKOBJECTCREATE(hresult, CLSID_FileMoniker, IID_IMoniker, (IUnknown **)ppmk); // HOOKOLE
errNoHookRet:
OLETRACEOUT((API_CreateFileMoniker, hresult));
return hresult;
} // CreateFileMonikerEx
#endif // _CAIRO_
//+---------------------------------------------------------------------------
//
// Function: CreateOle1FileMoniker
//
// Synopsis: Creates a FileMoniker
//
// Effects:
//
// Arguments: [lpszPathName] - Path to create moniker to
// [rclsidOle1] - Ole1 clsid
// [ppmk] - Output moniker interface pointer
//
// Returns: HRESULT
//
//
// Algorithm:
//
// History: 01-Aug-95 BruceMa Added this header
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT
STDAPICALLTYPE
CreateOle1FileMoniker ( LPWSTR lpszPathName,
REFCLSID rclsidOle1,
LPMONIKER FAR * ppmk)
{
CFileMoniker FAR * pCFM;
HRESULT hr;
hr = CreateFileMoniker( lpszPathName, (LPMONIKER FAR *)&pCFM);
*ppmk = pCFM; // this nulls *ppmk in case of error
if (hr == NOERROR)
{
pCFM->m_ole1 = CFileMoniker::ole1;
pCFM->m_clsid = rclsidOle1;
pCFM->m_fClassVerified = TRUE;
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CreateAntiMoniker
//
// Synopsis: Creates a anti moniker
//
// Effects:
//
// Arguments: [ppmk] - Path to create moniker to
//
// Returns: HRESULT
//
//
// Algorithm:
//
// History: 01-Aug-95 BruceMa Added this header
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI CreateAntiMoniker (LPMONIKER FAR* ppmk)
{
CAntiMoniker FAR* pCAM;
HRESULT hr;
OLETRACEIN((API_CreateAntiMoniker, PARAMFMT("ppmk= %p"), ppmk));
VDATEPTROUT_LABEL(ppmk, LPMONIKER, errRtn, hr);
*ppmk = NULL;
pCAM = CAntiMoniker::Create();
if (pCAM != NULL)
{
*ppmk = pCAM;
CALLHOOKOBJECTCREATE(S_OK,CLSID_AntiMoniker,IID_IMoniker,(IUnknown **)ppmk);
hr = NOERROR;
}
else
{
hr = E_OUTOFMEMORY;
}
errRtn:
OLETRACEOUT((API_CreateAntiMoniker, hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CreateBindCtx
//
// Synopsis: Creates a bind context
//
// Effects:
//
// Arguments: [reserved] - Reserved for future expansion
// [ppbc] - Where to place the created bnind context
//
// Returns: HRESULT
//
//
// Algorithm:
//
// History: 01-Aug-95 BruceMa Added this header
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI CreateBindCtx ( DWORD reserved, LPBC FAR * ppbc )
{
HRESULT hr;
OLETRACEIN((API_CreateBindCtx, PARAMFMT("reserved= %x, ppbc= %p"), reserved, ppbc));
VDATEPTROUT_LABEL(ppbc, LPBC, errRtn, hr);
if(reserved != 0)
{
return E_INVALIDARG;
}
*ppbc = CBindCtx::Create();
if (*ppbc == NULL)
{
hr = E_OUTOFMEMORY;
goto errRtn;
}
CALLHOOKOBJECTCREATE(S_OK,CLSID_PSBindCtx,IID_IBindCtx,(IUnknown **)ppbc);
hr = NOERROR;
errRtn:
OLETRACEOUT((API_CreateBindCtx, hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CreatePointerMoniker
//
// Synopsis: Creates a pointer moniker
//
// Effects:
//
// Arguments: [punk] - Pointer being wrappaed
// [ppmk] - Output moniker interface pointer
//
// Returns: HRESULT
//
//
// Algorithm:
//
// History: 01-Aug-95 BruceMa Added this header
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI CreatePointerMoniker (LPUNKNOWN punk, LPMONIKER FAR* ppmk)
{
OLETRACEIN((API_CreatePointerMoniker, PARAMFMT("punk= %p, ppmk= %p"),
punk, ppmk));
HRESULT hresult;
CPointerMoniker FAR* pCPM;
VDATEPTROUT_LABEL(ppmk, LPMONIKER, errRtn, hresult);
*ppmk = NULL;
// When unmarshaling a remoted pointer moniker punk is initially NULL
if (punk)
{
VDATEIFACE_LABEL(punk, errRtn, hresult);
}
pCPM = CPointerMoniker::Create(punk);
if (pCPM)
{
*ppmk = pCPM;
CALLHOOKOBJECTCREATE(S_OK,CLSID_PointerMoniker,IID_IMoniker,(IUnknown **)ppmk);
hresult = NOERROR;
}
else
{
hresult = E_OUTOFMEMORY;
}
errRtn:
OLETRACEOUT((API_CreatePointerMoniker, hresult));
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: OleLoadFromStream
//
// Synopsis: Load a moniker from a stream and QI for the
// requested interface
//
// Effects:
//
// Arguments: [pStm] - The stream to load from
// [iidInterface] - The requested interface
// [ppvObj] - Output moniker interface pointer
//
// Returns: HRESULT
//
//
// Algorithm:
//
// History: 01-Aug-95 BruceMa Added this header
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI OleLoadFromStream ( LPSTREAM pStm, REFIID iidInterface,
LPVOID FAR* ppvObj)
{
OLETRACEIN((API_OleLoadFromStream, PARAMFMT("pStm= %p, iidInterface= %I"),
pStm, &iidInterface));
// Assumptions: The name of the object class is in the stream,
// as a length-prefixed string.
HRESULT hresult = NOERROR;
CLSID cid;
LPPERSISTSTREAM pPS;
LPUNKNOWN pUnk;
VDATEPTROUT_LABEL(ppvObj,LPVOID, errRtn, hresult);
*ppvObj = NULL;
VDATEIID_LABEL(iidInterface, errRtn, hresult);
VDATEIFACE_LABEL(pStm, errRtn, hresult);
if ((hresult = ReadClassStm(pStm, &cid)) != NOERROR)
goto errRtn;
hresult = CoCreateInstance(cid, NULL,
#ifdef WX86OLE
gcwx86.IsWx86Enabled() ? CLSCTX_SERVER | CLSCTX_INPROC_SERVERX86 :
CLSCTX_SERVER,
#else
CLSCTX_SERVER,
#endif
iidInterface,
(LPVOID FAR *) &pUnk);
if (hresult)
goto errRtn;
hresult = pUnk->QueryInterface(IID_IPersistStream,
(LPVOID FAR*) &pPS);
if (!hresult)
{
hresult = pPS->Load( pStm );
pPS->Release();
}
if (!hresult)
hresult = pUnk->QueryInterface(iidInterface, ppvObj );
pUnk->Release();
errRtn:
OLETRACEOUT((API_OleLoadFromStream, hresult));
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: OleSaveToStream
//
// Synopsis: Given an IPersistStream on a moniker, save that moniker
// to a stream
//
// Effects:
//
// Arguments: [pPStm] - IPersistStream pointer
// [pStm] - Stream to save the moniker to
//
// Returns: HRESULT
//
//
// Algorithm:
//
// History: 01-Aug-95 BruceMa Added this header
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI OleSaveToStream ( LPPERSISTSTREAM pPStm, LPSTREAM pStm)
{
OLETRACEIN((API_OleSaveToStream, PARAMFMT("pPStm= %p, pStm= %p"),
pPStm, pStm));
HRESULT hresult = 0;
CLSID clsid;
VDATEIFACE_LABEL(pPStm, errRtn, hresult);
VDATEIFACE_LABEL(pStm, errRtn, hresult);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IPersistStream,(IUnknown **)&pPStm);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pStm);
if (!pPStm)
{
hresult = ResultFromScode(OLE_E_BLANK);
goto errRtn;
}
if (hresult = pPStm->GetClassID(&clsid))
goto errRtn;
if ((hresult = WriteClassStm(pStm, clsid)) != NOERROR)
goto errRtn;
hresult = pPStm->Save(pStm, TRUE);
errRtn:
OLETRACEOUT((API_OleSaveToStream, hresult));
return hresult;
}
//+---------------------------------------------------------------------------
//
// Function: Parse10DisplayName private
//
// Synopsis: Parse a ProgId string as an ole 1.0 file moniker
//
// Arguments: [pbc] - Bind context
// [pszDisplayName] - Display name
// [pcchEaten] - Number of characters eaten
// [ppmk] - Moniker of running object
// if successful, otherwise NULL
//
// Returns:
//
// Algorithm: This routine is being rewritten for performance, hence the
//
// History: 20-Jul-95 BruceMa Added this header and cleaned up
//
//----------------------------------------------------------------------------
STDAPI Parse10DisplayName(REFCLSID clsid,
LPCWSTR szDisplayName,
ULONG *pcchEaten,
ULONG cchEatenSoFar,
LPMONIKER *ppmk)
{
LPCWSTR pch = szDisplayName;
LPMONIKER pmkFile = NULL;
LPMONIKER pmkItem = NULL;
HRESULT hres = NOERROR;
size_t cbFile;
// Skip past the "file" name, looking for first delimiter character
// Note: strtok is not DBCS-friendly.
while (*pch && !wcschr (L"!\"'*+,/;<=>?@[]`|" , *pch))
{
IncLpch(pch);
}
if (*pch)
{
// We hit a delimiter, so there is an item moniker.
CreateItemMoniker (L"!", (LPWSTR)pch+1, &pmkItem);
// Copy the "file" part
LPWSTR szFile = (WCHAR *)
PrivMemAlloc(sizeof(WCHAR) * (cbFile = pch - szDisplayName + 1));
if (NULL==szFile)
{
hres = ResultFromScode (E_OUTOFMEMORY);
goto errRtn;
}
_fmemcpy (szFile, szDisplayName, (cbFile - 1) * sizeof(WCHAR));
szFile [cbFile - 1] = '\0';
hres = CreateOle1FileMoniker (szFile, clsid, &pmkFile);
PrivMemFree(szFile);
if (hres != NOERROR)
{
goto errRtn;
}
hres = CreateGenericComposite (pmkFile, pmkItem, ppmk);
}
else
{
// no Item moniker, just a file
hres = CreateOle1FileMoniker ((LPWSTR)szDisplayName, clsid, ppmk);
}
errRtn:
if (pmkFile)
{
pmkFile->Release();
}
if (pmkItem)
{
pmkItem->Release();
}
*pcchEaten = ((hres==NOERROR) ? lstrlenW (szDisplayName) + cchEatenSoFar : 0);
return hres;
}
//+---------------------------------------------------------------------------
//
// Function: FindProgIdMoniker private
//
// Synopsis: Interpreting a display name as a ProgID, derive a
// moniker from it
//
// Arguments: [pbc] - Bind context
// [pszDisplayName] - Display name to parse
// [pcchEaten] - Number of characters eaten
// [ppmk] - Moniker of running object
//
// Returns: S_OK if successful
// Another HRESULT otherwise
//
// Algorithm: Find largest left-bounded name that corresponds to a
// valid initial moniker, either of an object currently running
// and registered in the ROT or of an extant file. Call
// IParseDisplayName::ParseDisplayName on the right-part of the
// display name not yet consumed.
//
// History: 20-Jul-95 BruceMa Added this header and cleaned up
//
//----------------------------------------------------------------------------
STDAPI FindProgIdMoniker(LPBC pbc,
LPCWSTR pszDisplayName,
ULONG *pcchEaten,
LPMONIKER *ppmk)
{
int cbProgId;
LPWSTR sz = NULL;
WCHAR const *pch;
HRESULT hres;
CLSID cid;
IParseDisplayName *pPDN;
// Initialize
*pcchEaten = 0;
*ppmk = NULL;
// find the prog id
pch = pszDisplayName;
Assert(*pch == '@');
pch++;
if (*pch >= '0' && *pch <= '9')
{
return ResultFromScode(MK_E_SYNTAX);
}
while ((*pch >= '0' && *pch <= '9') || (*pch >= 'a' && *pch <= 'z') ||
(*pch >= 'A' && *pch <= 'Z') || (*pch == '.'))
{
pch++;
}
cbProgId = pch - pszDisplayName;
sz = (WCHAR *) PrivMemAlloc(sizeof(WCHAR) * cbProgId);
_fmemcpy(sz, pszDisplayName + 1, (cbProgId - 1) * sizeof(WCHAR));
sz[cbProgId - 1] = '\0';
// prog id string is now in sz
hres = CLSIDFromProgID(sz, &cid);
if (hres == NOERROR)
{
if (CoIsOle1Class (cid))
{
hres = Parse10DisplayName (cid, pch + 1, pcchEaten, cbProgId + 1,
ppmk);
CairoleAssert(hres!=NOERROR ||
*pcchEaten == (ULONG)lstrlenW(pszDisplayName));
goto errRet;
}
hres = CoGetClassObject(cid,
#ifdef WX86OLE
gcwx86.IsWx86Enabled() ? CLSCTX_ALL |
CLSCTX_INPROC_HANDLERX86 |
CLSCTX_INPROC_SERVERX86 :
CLSCTX_ALL,
#else
CLSCTX_ALL,
#endif
NULL, IID_IParseDisplayName,
(LPVOID *) &pPDN);
if (hres != NOERROR)
{
hres = CoCreateInstance(cid, NULL,
#ifdef WX86OLE
gcwx86.IsWx86Enabled() ?
CLSCTX_INPROC_SERVERX86 |
CLSCTX_INPROC_HANDLERX86 :
CLSCTX_INPROC,
#else
CLSCTX_INPROC,
#endif
IID_IParseDisplayName,
(LPVOID *) &pPDN);
}
}
if (hres == NOERROR)
{
// Unfortunately, IParseDisplayName's 2nd parameter is
// LPOLESTR instead of LPCOLESTR
hres = pPDN->ParseDisplayName(pbc,
(LPOLESTR) pszDisplayName,
pcchEaten,
ppmk);
// AssertOutPtrIface(hres, *ppmk);
pPDN->Release();
}
errRet:
if (sz)
{
PrivMemFree(sz);
}
return hres;
}
//+---------------------------------------------------------------------------
//
// Function: MkParseDisplayName public
//
// Synopsis: Attempts to parse the given file moniker "display name" and
// return the corresponding moniker
//
// Arguments: [pbc] - Bind context
// [pszDisplayName] - Display name to parse
// [pcchEaten] - Number of characters eaten
// [ppmk] - Moniker of running object
//
// Returns: S_OK if successful
// Another HRESULT otherwise
//
// Algorithm: Find the largest left-bounded name that corresponds to a
// valid initial moniker, either of an object currently running
// and registered in the ROT or of an extant file. Then call
// IParseDisplayName::ParseDisplayName on this moniker
// inductively with the right-part of the display name not
// yet consumed, composing the current moniker with the result to
// form the next moniker in the induction
//
// History: 20-Jul-95 BruceMa Rewrote
// 22-Feb-96 ShannonC Added class moniker support.
//
//----------------------------------------------------------------------------
STDAPI MkParseDisplayName(LPBC pbc,
LPCWSTR pwszDisplayName,
ULONG *pchEaten,
LPMONIKER *ppmk)
{
HRESULT hr = MK_E_SYNTAX;
LPCWSTR pszRemainder = pwszDisplayName;
ULONG cchEaten = 0;
LONG cbUneaten;
LPMONIKER pmk;
LPMONIKER pmkNext;
LPMONIKER pmkTemp;
// Some simple checks
if (pwszDisplayName == NULL || pwszDisplayName[0] == L'\0')
{
return E_INVALIDARG;
}
OLETRACEIN((API_MkParseDisplayName,
PARAMFMT("pbc= %p, pszDisplayName= %ws, pchEaten= %p, ppmk= %p"),
pbc, pwszDisplayName, pchEaten, ppmk));
// Trace
mnkDebugOut((DEB_ITRACE, "In MkParseDisplayName \"%ws\"\n",
pwszDisplayName));
// Validate parameters
VDATEPTRIN_LABEL(pwszDisplayName, WCHAR, errRet, hr);
VDATEIFACE_LABEL(pbc, errRet, hr);
VDATEPTROUT_LABEL(pchEaten, ULONG, errRet, hr);
VDATEPTROUT_LABEL(ppmk, LPMONIKER, errRet, hr);
// Call hook ole
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IBindCtx,(IUnknown **)&pbc);
// Initialize
*ppmk = NULL;
*pchEaten = 0;
//Find the initial moniker.
//Parse a class moniker display name.
hr = FindClassMoniker(pbc, pwszDisplayName, &cchEaten, &pmk);
if(FAILED(hr))
{
//Parse a file moniker display name.
hr = FindFileMoniker(pbc, pwszDisplayName, &cchEaten, &pmk);
}
if(FAILED(hr) && (L'@' == pwszDisplayName[0]))
{
//Parse the leftmost part of the display name as a ProgID.
hr = FindProgIdMoniker(pbc, pwszDisplayName, &cchEaten, &pmk);
}
// Inductively consume the remainder of the display name.
// Initialize to loop
if(SUCCEEDED(hr))
{
pszRemainder += cchEaten;
cbUneaten = lstrlenW(pszRemainder);
}
// While more display name remains, successively pass the remainder to the
// current moniker for it to parse
while (SUCCEEDED(hr) && cbUneaten > 0)
{
cchEaten = 0;
hr = pmk->ParseDisplayName(pbc,
NULL,
(LPOLESTR) pszRemainder,
&cchEaten,
&pmkNext);
if (SUCCEEDED(hr) && pmkNext != 0)
{
hr = pmk->ComposeWith(pmkNext, FALSE, &pmkTemp);
if(SUCCEEDED(hr))
{
pmk->Release();
pmk = pmkTemp;
// Update the amount consumed so far
pszRemainder += cchEaten;
cbUneaten -= cchEaten;
}
pmkNext->Release();
}
}
*ppmk = pmk;
*pchEaten = pszRemainder - pwszDisplayName;
errRet:
// Trace
mnkDebugOut((DEB_ITRACE, "Out MkParseDisplayName: %ws",
pwszDisplayName));
OLETRACEOUT((API_MkParseDisplayName, hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: BindMoniker public
//
// Synopsis: Given a moniker, bind to the object it names and
// QI for the requested interface.
//
// Arguments: [pmk] - The moniker
// [grfOpt] - RESERVED (0l)
// [iidResult] - Interface requested
// [ppvResult] - Where to store interface
//
// Returns: S_OK if successful
// Another HRESULT otherwise
//
// Algorithm: Create a bind context and call BindToObject on the moniker
// within that bind context
//
// History: 20-Jul-95 BruceMa Rewrote
//
// Note: This is simply a convenience function
//
//----------------------------------------------------------------------------
STDAPI BindMoniker (LPMONIKER pmk,
DWORD grfOpt,
REFIID iidResult,
LPVOID *ppvResult)
{
LPBC pbc = NULL;
HRESULT hr;
OLETRACEIN((API_BindMoniker, PARAMFMT("pmk= %p, grfOpt= %x, iidResult= %I, ppvResult= %p"),
pmk, grfOpt, &iidResult, ppvResult));
// Validate parameters
VDATEPTROUT_LABEL(ppvResult,LPVOID, errSafeRtn, hr);
*ppvResult = NULL;
VDATEIFACE_LABEL(pmk, errSafeRtn, hr);
VDATEIID_LABEL(iidResult, errSafeRtn, hr);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMoniker,(IUnknown **)&pmk);
if (grfOpt != 0)
{
hr = E_INVALIDARG;
goto errSafeRtn;
}
// Initialize
*ppvResult = NULL;
// Create a bind context
if (FAILED(hr = CreateBindCtx( 0, &pbc)))
{
goto errRtn;
}
// Bind to the object
hr = pmk->BindToObject(pbc, NULL, iidResult, ppvResult);
errRtn:
if (pbc)
{
pbc->Release();
}
// An ole spy hook
CALLHOOKOBJECT(hr,CLSID_NULL,iidResult,(IUnknown **)ppvResult);
errSafeRtn:
OLETRACEOUT((API_BindMoniker, hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CoGetObject public
//
// Synopsis: Get the object identified by the display name.
//
// Arguments: [pszName] - Supplies the display name of the object.
// [pBindOptions] - Supplies the bind options. May be NULL.
// [riid] - Supplies the IID of the requested interface.
// [ppv] - Returns interface pointer to the object.
//
// Returns: S_OK if successful
// Another HRESULT otherwise
//
// Algorithm: Create a bind context, parse the display name, then bind to
// the object.
//
// Note: This is simply a convenience function.
//
// History: 22-Feb-96 ShannonC Created
//
//----------------------------------------------------------------------------
STDAPI CoGetObject(
LPCWSTR pszName,
BIND_OPTS * pBindOptions,
REFIID riid,
void ** ppv)
{
HRESULT hr;
IBindCtx * pbc;
IID iid;
OLETRACEIN((API_CoGetObject,
PARAMFMT("%ws, %p, %I, %p"),
pszName, pBindOptions, &riid, ppv));
__try
{
//Validate parameters.
*ppv = 0;
iid = riid;
//Create a bind context.
hr = CreateBindCtx(0, &pbc);
if(SUCCEEDED(hr))
{
//Set the bind options.
if(pBindOptions != 0)
{
hr = pbc->SetBindOptions(pBindOptions);
}
if(SUCCEEDED(hr))
{
IMoniker * pmk = 0;
ULONG chEaten = 0;
//Parse the display name.
hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
if(SUCCEEDED(hr))
{
//Bind to the object.
hr = pmk->BindToObject(pbc, 0, iid, ppv);
pmk->Release();
}
}
pbc->Release();
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
hr = E_INVALIDARG;
}
CALLHOOKOBJECT(hr, CLSID_NULL, iid, (IUnknown **)ppv);
OLETRACEOUT((API_CoGetObject, hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: FindClassID private
//
// Synopsis: Parse a display name to get a CLSID.
//
// Arguments: [pszDisplayName] - Display name to parse
// [pcchEaten] - Number of characters eaten
// [pClassID] - returns the CLSID
//
// Returns: S_OK if successful
// MK_E_SYNTAX
// E_OUTOFMEMORY
//
// History: 22-Feb-96 ShannonC Created
//
//----------------------------------------------------------------------------
STDAPI FindClassID(
LPCWSTR pszDisplayName,
ULONG * pcchEaten,
CLSID * pClassID)
{
HRESULT hr = MK_E_SYNTAX;
WCHAR const *pch = pszDisplayName;
ULONG cchProgID = 0;
mnkDebugOut((DEB_ITRACE,
"FindClassID(%ws,%x,%x)\n",
pszDisplayName, pcchEaten, pClassID));
*pcchEaten = 0;
//Check if display name contains ProgID:
//or {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}:
while (*pch != '\0' && *pch != ':')
{
pch++;
}
if(':' == *pch)
{
cchProgID = pch - pszDisplayName;
pch++;
}
//cchProgID has the number of characters in the ProgID or CLSID.
//pch points to the next character to be parsed.
if(cchProgID > 1)
{
LPWSTR psz;
//Allocate memory from the stack.
//This memory is freed automatically on function return.
psz = (WCHAR *) alloca(sizeof(WCHAR) * cchProgID + sizeof(WCHAR));
if (psz != 0)
{
//Copy the ProgID string.
memcpy(psz, pszDisplayName, cchProgID * sizeof(WCHAR));
//Add a zero terminator.
psz[cchProgID] = '\0';
//Convert the string to a CLSID. Note that CLSIDFromString will
//parse both ProgID strings and {CLSID} strings.
hr = CLSIDFromString(psz, pClassID);
if(SUCCEEDED(hr))
{
//Calculate the number of characters parsed.
*pcchEaten = pch - pszDisplayName;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: FindClassMoniker private
//
// Synopsis: Interpreting a display name as a ProgID, derive a
// moniker from it.
//
// Arguments: [pbc] - Bind context
// [pszDisplayName] - Display name to parse
// [pcchEaten] - Number of characters eaten
// [ppmk] - Moniker of running object
//
// Returns: S_OK if successful
// CLASS_E_CLASSNOTAVAILABLE
// E_OUTOFMEMORY
// E_NOINTERFACE
// MK_E_SYNTAX
//
// Algorithm: Parse the first part of the display name to get a CLSID.
// Use the CLSID to create a class moniker.
//
// History: 22-Feb-96 ShannonC Created
//
//----------------------------------------------------------------------------
STDAPI FindClassMoniker(
IBindCtx * pbc,
LPCWSTR pszDisplayName,
ULONG * pcchEaten,
IMoniker **ppmk)
{
HRESULT hr;
CLSID classID;
ULONG cEaten = 0;
*ppmk = 0;
*pcchEaten = 0;
mnkDebugOut((DEB_ITRACE,
"FindClassMoniker(%x,%ws,%x,%x)\n",
pbc, pszDisplayName, pcchEaten, ppmk));
hr = FindClassID(pszDisplayName, &cEaten, &classID);
if(SUCCEEDED(hr))
{
IParseDisplayName *pPDN = NULL;
DWORD dwClassContext;
#ifdef WX86OLE
dwClassContext = gcwx86.IsWx86Enabled() ?
CLSCTX_ALL | CLSCTX_INPROC_HANDLERX86 |CLSCTX_INPROC_SERVERX86 :
CLSCTX_ALL;
#else
dwClassContext = CLSCTX_ALL;
#endif
hr = CoGetClassObject(classID,
dwClassContext,
NULL,
IID_IParseDisplayName,
(LPVOID *) &pPDN);
if (FAILED(hr))
{
hr = CoCreateInstance(classID,
NULL,
dwClassContext,
IID_IParseDisplayName,
(LPVOID *) &pPDN);
}
if(SUCCEEDED(hr))
{
hr = pPDN->ParseDisplayName(pbc,
(LPOLESTR) pszDisplayName,
pcchEaten,
ppmk);
pPDN->Release();
}
}
return hr;
}
INTERNAL_(BOOL) RunningMoniker ( LPBINDCTX pbc,
LPWSTR pszFullPath,
USHORT ccFullPath,
ULONG FAR *pcchEaten,
LPMONIKER FAR * ppmk)
{
mnkDebugOut((DEB_ITRACE,
"RunningMoniker szDisplayName(%ws)",
WIDECHECK(pszFullPath)));
WCHAR ch;
LPWSTR pch;
HRESULT hresult;
CFileMoniker FAR * pCFM = NULL;
LPRUNNINGOBJECTTABLE pRot = NULL;
BOOL retVal = FALSE;
*pcchEaten = 0;
pch = pszFullPath + ccFullPath;
hresult = pbc->GetRunningObjectTable(&pRot);
if (hresult != NOERROR) goto errRet;
while (pch > pszFullPath)
{
if (IsFileSystemSeparator(*pch) ||
IsItemMonikerSeparator(*pch) ||
('\0' == *pch))
{
ch = *pch;
*pch = '\0';
hresult = CreateFileMoniker( pszFullPath, (LPMONIKER FAR *)&pCFM );
*pch = ch;
if(SUCCEEDED(hresult))
{
hresult = pRot->IsRunning(pCFM);
//
// If found, then pCFM is our return moniker
//
if (hresult == S_OK)
{
*ppmk = pCFM;
*pcchEaten = (ULONG) (pch - pszFullPath);
retVal = TRUE;
break;
}
else
{
//
// This one isn't a match. Release it and try the next smaller
// path
//
pCFM->Release();
pCFM = NULL;
}
}
}
pch--;
}
errRet:
if (pRot) pRot->Release();
return retVal;
}
INTERNAL FindMaximalFileMoniker(LPWSTR pszFullPath,
USHORT ccFullPath,
ULONG FAR *pcchEaten,
LPMONIKER FAR * ppmk)
{
HRESULT hr = MK_E_SYNTAX;
WCHAR ch;
LPWSTR pch;
DWORD dwAttr;
*pcchEaten = 0;
*ppmk = 0;
pch = pszFullPath + ccFullPath;
while((pch > pszFullPath) &&
(MK_E_SYNTAX == hr))
{
if (IsFileSystemSeparator(*pch) ||
IsItemMonikerSeparator(*pch) ||
('\0' == *pch))
{
ch = *pch;
*pch = '\0';
// Check if this path exists
dwAttr = GetFileAttributes(pszFullPath);
// The file exists
if (dwAttr != 0xffffffff)
{
// We fail if we found a directory
// but not a file.
if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
{
hr = MK_E_CANTOPENFILE;
}
else
{
hr = CreateFileMoniker(pszFullPath, ppmk);
if(SUCCEEDED(hr))
{
*pcchEaten = (ULONG) (pch - pszFullPath);
}
}
}
*pch = ch;
}
pch--;
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: FindFileMoniker
//
// Synopsis: Parse a file moniker display name.
//
// Arguments: [pbc] - Bind context
// [pszDisplayName] - Display name to parse
// [pcchEaten] - Number of characters eaten
// [ppmk] - Moniker of running object
//
// Returns: S_OK if successful
// Another HRESULT otherwise
//
// Algorithm: Find the largest left-bounded name that corresponds to a
// valid initial moniker, either of an object currently running
// and registered in the ROT or of an extant file.
//
// History: 22-Feb-96 ShannonC Moved code from MkParseDisplayName.
//
//----------------------------------------------------------------------------
STDAPI FindFileMoniker(
LPBC pbc,
LPCWSTR pszDisplayName,
ULONG *pcchEaten,
LPMONIKER *ppmk)
{
HRESULT hr = E_OUTOFMEMORY;
USHORT ccPath;
LPWSTR pszPath;
ccPath = lstrlenW(pszDisplayName);
pszPath = (WCHAR *) alloca((ccPath + 1) * sizeof(WCHAR));
if(pszPath != NULL)
{
memcpy(pszPath, pszDisplayName, (ccPath + 1) * sizeof(WCHAR));
if (RunningMoniker(pbc, pszPath, ccPath, pcchEaten, ppmk))
{
hr = S_OK;
}
else
{
hr = FindMaximalFileMoniker(pszPath, ccPath, pcchEaten, ppmk);
}
}
return hr;
}