2056 lines
44 KiB
C++
2056 lines
44 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1993 - 1993.
|
|
//
|
|
// File: citemmon.cxx
|
|
//
|
|
// Contents: Implementation of CItemMoniker
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 12-27-93 ErikGav Created
|
|
// 01-14-94 KevinRo Updated so it actually works
|
|
// 06-14-94 Rickhi Fix type casting
|
|
// 10-13-95 stevebl threadsafty
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <ole2int.h>
|
|
|
|
#include "cbasemon.hxx"
|
|
#include "citemmon.hxx"
|
|
#include "cantimon.hxx"
|
|
#include "mnk.h"
|
|
|
|
#include <olepfn.hxx>
|
|
#include <rotdata.hxx>
|
|
|
|
|
|
INTERNAL RegisterContainerBound(LPBC pbc, LPOLEITEMCONTAINER pOleCont);
|
|
|
|
|
|
INTERNAL_(CItemMoniker *) IsItemMoniker( LPMONIKER pmk )
|
|
{
|
|
CItemMoniker *pIMk;
|
|
|
|
if ((pmk->QueryInterface(CLSID_ItemMoniker, (void **)&pIMk)) == S_OK)
|
|
{
|
|
// we release the AddRef done by QI, but still return the pointer
|
|
pIMk->Release();
|
|
return pIMk;
|
|
}
|
|
|
|
// dont rely on user implementations to set pIMk to NULL on failed QI.
|
|
return pIMk;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::CItemMoniker
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-17-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CItemMoniker::CItemMoniker() CONSTR_DEBUG
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::CItemMoniker(%x)\n",
|
|
this));
|
|
|
|
m_lpszItem = NULL;
|
|
m_lpszDelimiter = NULL;
|
|
m_pszAnsiItem = NULL;
|
|
m_pszAnsiDelimiter = NULL;
|
|
m_fHashValueValid = FALSE;
|
|
m_ccItem = 0;
|
|
m_cbAnsiItem = 0;
|
|
m_cbAnsiDelimiter = 0;
|
|
m_ccDelimiter = 0;
|
|
|
|
m_dwHashValue = 0x12345678;
|
|
//
|
|
// CoQueryReleaseObject needs to have the address of the this objects
|
|
// query interface routine.
|
|
//
|
|
if (adwQueryInterfaceTable[QI_TABLE_CItemMoniker] == 0)
|
|
{
|
|
adwQueryInterfaceTable[QI_TABLE_CItemMoniker] =
|
|
**(DWORD **)((IMoniker *)this);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::ValidateMoniker
|
|
//
|
|
// Synopsis: Check the consistency of this moniker
|
|
//
|
|
// Effects: In a DBG build, check to see if the member variables are
|
|
// sane values.
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-17-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#if DBG == 1
|
|
void CItemMoniker::ValidateMoniker()
|
|
{
|
|
Assert( (m_lpszItem == NULL && m_ccItem == 0) ||
|
|
(m_ccItem == lstrlenW(m_lpszItem)));
|
|
|
|
|
|
Assert( (m_lpszDelimiter == NULL && m_ccDelimiter == 0) ||
|
|
(m_ccDelimiter == lstrlenW(m_lpszDelimiter)));
|
|
|
|
//
|
|
// cbAnsi* fields are NOT string lengths. However, the size of the
|
|
// buffer should be at least equal or bigger to the length of the
|
|
// Ansi part.
|
|
//
|
|
|
|
Assert( (m_pszAnsiItem == NULL && m_cbAnsiItem == 0) ||
|
|
(m_cbAnsiItem >= strlen(m_pszAnsiItem)+1));
|
|
|
|
|
|
Assert( (m_pszAnsiDelimiter == NULL && m_cbAnsiDelimiter == 0) ||
|
|
(m_cbAnsiDelimiter >= strlen(m_pszAnsiDelimiter)+1));
|
|
|
|
Assert( !m_fHashValueValid || (m_dwHashValue != 0x12345678) );
|
|
}
|
|
#endif
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::~CItemMoniker
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [void] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-17-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CItemMoniker::~CItemMoniker( void )
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::~CItemMoniker(%x)\n",
|
|
this));
|
|
UnInit();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::UnInit
|
|
//
|
|
// Synopsis: Uninitialize the Item moniker
|
|
//
|
|
// Effects: Free's path memory stored in Item Moniker.
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-16-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
CItemMoniker::UnInit()
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::UnInit(%x)\n",
|
|
this));
|
|
|
|
ValidateMoniker();
|
|
|
|
if (m_lpszDelimiter != NULL)
|
|
{
|
|
PrivMemFree(m_lpszDelimiter);
|
|
m_lpszDelimiter = NULL;
|
|
m_ccDelimiter = 0;
|
|
}
|
|
|
|
if (m_pszAnsiDelimiter != NULL)
|
|
{
|
|
PrivMemFree(m_pszAnsiDelimiter);
|
|
m_pszAnsiDelimiter = NULL;
|
|
m_cbAnsiDelimiter = 0;
|
|
}
|
|
|
|
if (m_lpszItem != NULL)
|
|
{
|
|
PrivMemFree(m_lpszItem);
|
|
m_lpszItem = NULL;
|
|
m_ccItem = 0;
|
|
}
|
|
|
|
if (m_pszAnsiItem != NULL)
|
|
{
|
|
PrivMemFree(m_pszAnsiItem);
|
|
m_pszAnsiItem = NULL;
|
|
m_cbAnsiItem = 0;
|
|
}
|
|
|
|
m_fHashValueValid = FALSE;
|
|
m_dwHashValue = 0x12345678;
|
|
|
|
ValidateMoniker();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::Initialize
|
|
//
|
|
// Synopsis: Initilaize an Item Moniker
|
|
//
|
|
// Effects: Clears the current state, then sets new state
|
|
//
|
|
// Arguments: [lpwcsDelimiter] -- Delimiter string
|
|
// [ccDelimiter] -- char count of delimiter
|
|
// [lpszAnsiDelimiter] -- Ansi version of delimiter
|
|
// [cbAnsiDelimiter] -- Count of bytes in AnsiDelimiter
|
|
// [lpwcsItem] -- Item string
|
|
// [ccItem] -- Count of characters in item string
|
|
// [lpszAnsiItem] -- Ansi version of item string
|
|
// [cbAnsiItem] -- Count of bytes in Ansi version
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-16-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
CItemMoniker::Initialize ( LPWSTR lpwcsDelimiter,
|
|
USHORT ccDelimiter,
|
|
LPSTR lpszAnsiDelimiter,
|
|
USHORT cbAnsiDelimiter,
|
|
LPWSTR lpwcsItem,
|
|
USHORT ccItem,
|
|
LPSTR lpszAnsiItem,
|
|
USHORT cbAnsiItem )
|
|
{
|
|
//
|
|
// OleLoadFromStream causes two inits; the member vars may already be set
|
|
// UnInit() will free existing resources
|
|
//
|
|
|
|
UnInit();
|
|
|
|
ValidateMoniker();
|
|
|
|
m_lpszItem = lpwcsItem;
|
|
m_ccItem = ccItem;
|
|
|
|
m_pszAnsiItem = lpszAnsiItem;
|
|
m_cbAnsiItem = cbAnsiItem;
|
|
|
|
m_lpszDelimiter = lpwcsDelimiter;
|
|
m_ccDelimiter = ccDelimiter;
|
|
|
|
m_pszAnsiDelimiter = lpszAnsiDelimiter;
|
|
m_cbAnsiDelimiter = cbAnsiDelimiter;
|
|
|
|
ValidateMoniker();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::Initialize
|
|
//
|
|
// Synopsis: Initialize the contents of this moniker
|
|
//
|
|
// Effects:
|
|
// Copies the input parameters using PrivMemAlloc(), then passes them
|
|
// to the other version of Initialize, which takes control of the
|
|
// pointers.
|
|
//
|
|
// Arguments: [lpszDelimiter] --
|
|
// [lpszItemName] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-17-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
INTERNAL_(BOOL)
|
|
CItemMoniker::Initialize ( LPCWSTR lpszDelimiter,
|
|
LPCWSTR lpszItemName )
|
|
{
|
|
ValidateMoniker();
|
|
|
|
USHORT ccItem;
|
|
USHORT ccDelimiter;
|
|
|
|
LPWSTR pwcsDelimiter = NULL;
|
|
LPWSTR pwcsItem = NULL;
|
|
|
|
//VDATEPTRIN rejects NULL
|
|
if( lpszDelimiter )
|
|
{
|
|
GEN_VDATEPTRIN(lpszDelimiter,WCHAR, FALSE);
|
|
}
|
|
|
|
if( lpszItemName )
|
|
{
|
|
GEN_VDATEPTRIN(lpszItemName,WCHAR, FALSE);
|
|
}
|
|
|
|
if (FAILED(DupWCHARString(lpszDelimiter,
|
|
pwcsDelimiter,
|
|
ccDelimiter)))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
if (FAILED(DupWCHARString(lpszItemName,pwcsItem,ccItem)))
|
|
{
|
|
goto errRet;
|
|
}
|
|
Initialize(pwcsDelimiter,
|
|
ccDelimiter,
|
|
NULL,
|
|
0,
|
|
pwcsItem,
|
|
ccItem,
|
|
NULL,
|
|
0);
|
|
|
|
return TRUE;
|
|
|
|
errRet:
|
|
|
|
if (pwcsDelimiter != NULL)
|
|
{
|
|
PrivMemFree(pwcsDelimiter);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
CItemMoniker FAR *CItemMoniker::Create (
|
|
LPCWSTR lpszDelimiter, LPCWSTR lpszItemName)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::Create() item(%ws) delim(%ws)\n",
|
|
lpszItemName,
|
|
lpszDelimiter));
|
|
//
|
|
// Parameter validation is handled in Initialize
|
|
//
|
|
CItemMoniker FAR * pCIM = new CItemMoniker();
|
|
|
|
if (pCIM)
|
|
{
|
|
pCIM->AddRef();
|
|
|
|
if (pCIM->Initialize( lpszDelimiter, lpszItemName ))
|
|
return pCIM;
|
|
|
|
delete pCIM;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::QueryInterface (THIS_ REFIID riid,
|
|
LPVOID FAR* ppvObj)
|
|
{
|
|
VDATEIID (riid);
|
|
VDATEPTROUT(ppvObj, LPVOID);
|
|
|
|
#ifdef _DEBUG
|
|
if (riid == IID_IDebug)
|
|
{
|
|
*ppvObj = &(m_Debug);
|
|
return NOERROR;
|
|
}
|
|
#endif
|
|
|
|
if (IsEqualIID(riid, CLSID_ItemMoniker))
|
|
{
|
|
// called by IsItemMoniker.
|
|
AddRef();
|
|
*ppvObj = this;
|
|
return S_OK;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IROTData))
|
|
{
|
|
AddRef();
|
|
*ppvObj = (IROTData *) this;
|
|
return S_OK;
|
|
}
|
|
|
|
return CBaseMoniker::QueryInterface(riid, ppvObj);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CItemMoniker::Release (void)
|
|
{
|
|
mnkDebugOut((DEB_TRACE, "%p CItemMoniker::Release(%ld)\n",
|
|
this, m_refs - 1));
|
|
|
|
Assert(m_refs != 0);
|
|
|
|
if (InterlockedDecrement((long *)&m_refs) == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_refs;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::GetClassID (LPCLSID lpClassId)
|
|
{
|
|
|
|
VDATEPTROUT(lpClassId, CLSID);
|
|
|
|
*lpClassId = CLSID_ItemMoniker;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: WriteDoubleString
|
|
//
|
|
// Synopsis: Writes a double string to stream. See ExtractUnicodeString
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pStm] --
|
|
// [pwcsWide] --
|
|
// [ccWide] --
|
|
// [pszAnsi] --
|
|
// [cbAnsi] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-16-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
WriteDoubleString( LPSTREAM pStm,
|
|
LPWSTR pwcsWide,
|
|
USHORT ccWide,
|
|
LPSTR pszAnsi,
|
|
USHORT cbAnsi)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"WriteDoubleString pwcsWide(%ws) cbWide(0x%x) psz(%s) cb(0x%x)\n",
|
|
pwcsWide?pwcsWide:L"<NULL>",
|
|
ccWide,
|
|
pszAnsi?pszAnsi:"<NULL>",
|
|
cbAnsi));
|
|
HRESULT hr;
|
|
|
|
//
|
|
// The string size is always written, but not including the size of the
|
|
// preceding DWORD so we conform to the way WriteAnsiString does it
|
|
//
|
|
|
|
ULONG ulTotalSize = 0;
|
|
|
|
//
|
|
// The entire reason we are supposed to be in this routine is that the
|
|
// pwcsWide could not be converted to ANSI. Therefore, it had better
|
|
// be valid.
|
|
//
|
|
|
|
Assert( (pwcsWide != NULL) && (ccWide == lstrlenW(pwcsWide)));
|
|
Assert( (pszAnsi == NULL) || (cbAnsi == (strlen(pszAnsi) + 1)));
|
|
|
|
ulTotalSize += ccWide * sizeof(WCHAR);
|
|
|
|
// Lets assume most ItemStrings will fit in this buffer
|
|
|
|
BYTE achQuickBuffer[256];
|
|
BYTE *pcbQuickBuffer = achQuickBuffer;
|
|
|
|
//
|
|
// Since we are going to cheat, and write something to the back of the
|
|
// ANSI string, the ANSI string must contain at least a NULL character.
|
|
// If it doesn't, we are going to cheat one in.
|
|
//
|
|
if (pszAnsi == NULL)
|
|
{
|
|
ulTotalSize += sizeof(char);
|
|
}
|
|
else
|
|
{
|
|
ulTotalSize += cbAnsi;
|
|
}
|
|
|
|
//
|
|
// If we don't fit in the QuickBuffer, allocate some memory
|
|
//
|
|
if (ulTotalSize > sizeof(achQuickBuffer))
|
|
{
|
|
pcbQuickBuffer = (BYTE *)PrivMemAlloc(ulTotalSize);
|
|
|
|
if (pcbQuickBuffer == NULL)
|
|
{
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
//
|
|
// First DWORD in the buffer is the total size of the string. This
|
|
// value includes strlen's of both strings, plus the size of the NULL
|
|
// on the Ansi string.
|
|
//
|
|
// Intrinsics will make this into a move of the correct alignment.
|
|
// Casting pcbQuickBuffer to a ULONG pointer is dangerous, since
|
|
// the alignment may be incorrect. Let the compiler figure out the
|
|
// correct thing to do.
|
|
//
|
|
|
|
memcpy(pcbQuickBuffer,&ulTotalSize,sizeof(ulTotalSize));
|
|
|
|
//
|
|
// Here, we make sure that pszAnsi ends up writing at least the NULL
|
|
// character
|
|
//
|
|
|
|
ULONG ulAnsiWritten;
|
|
|
|
memcpy(pcbQuickBuffer + sizeof(ulTotalSize),
|
|
pszAnsi?pszAnsi:"",
|
|
ulAnsiWritten = pszAnsi?cbAnsi:1);
|
|
|
|
//
|
|
// At this point, there should be a ULONG followed by at least 1
|
|
// character. The pointer arithmetic below puts us just past the
|
|
// null terminator of the Ansi string
|
|
//
|
|
|
|
memcpy(pcbQuickBuffer + sizeof(ulTotalSize) + ulAnsiWritten,
|
|
pwcsWide,
|
|
ccWide * sizeof(WCHAR));
|
|
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"WriteDoubleString ulTotalSize(0x%x)\n",
|
|
ulTotalSize));
|
|
|
|
hr = pStm->Write(pcbQuickBuffer, ulTotalSize + sizeof(ULONG) ,NULL);
|
|
|
|
if (pcbQuickBuffer != achQuickBuffer)
|
|
{
|
|
PrivMemFree(pcbQuickBuffer);
|
|
}
|
|
|
|
return(hr);
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ExtractUnicodeString
|
|
//
|
|
// Synopsis: Given an ANSI string buffer, return a UNICODE path
|
|
//
|
|
// Effects:
|
|
// If it exists, this routine will extract the UNICODE section
|
|
// of a string written out in the following format:
|
|
//
|
|
// <ANSI string><0><UNICODESTRING>
|
|
// ^ cbAnsiString ^
|
|
//
|
|
//
|
|
// If the UNICODE string doesn't exist, then the Ansi string is converted
|
|
// to UNICODE and returned
|
|
//
|
|
// Arguments: [pszAnsiString] -- Ansi string with potential UNICODE end
|
|
// [cbAnsiString] -- Total number of bytes in pszAnsiString
|
|
// [pwcsWideString] -- Reference to output string pointer
|
|
// [ccWideString] -- Reference to output cound of characters
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
// pwcsWideString will be a PrivMemAlloc()'d UNICODE string
|
|
// ccWideString will be the character count (excluding the NULL)
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-16-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT ExtractUnicodeString(LPSTR pszAnsiString,
|
|
USHORT cbAnsiString,
|
|
LPWSTR & pwcsString,
|
|
USHORT & ccString)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"ExtractUnicodeString pszAnsi(%s) cbAnsi(0x%x)\n",
|
|
ANSICHECK(pszAnsiString),
|
|
cbAnsiString));
|
|
|
|
|
|
USHORT cbAnsiStrLen;
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// If the Ansi string is NULL, then the Wide char will be also
|
|
//
|
|
|
|
if (pszAnsiString == NULL)
|
|
{
|
|
pwcsString = NULL;
|
|
ccString = 0;
|
|
|
|
return(NOERROR);
|
|
}
|
|
|
|
Assert( pwcsString == NULL);
|
|
|
|
//
|
|
// If strlen(pszAnsiString)+1 == cbAnsiString, then there is no
|
|
// UNICODE extent.
|
|
//
|
|
|
|
cbAnsiStrLen = strlen(pszAnsiString);
|
|
|
|
if ((cbAnsiStrLen + 1) == cbAnsiString)
|
|
{
|
|
//
|
|
// There is not a UNICODE extent. Convert from Ansi to UNICODE
|
|
//
|
|
pwcsString = NULL;
|
|
|
|
hr= MnkMultiToUnicode(pszAnsiString,
|
|
pwcsString,
|
|
0,
|
|
ccString,
|
|
CP_ACP);
|
|
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"ExtractUnicodeString converted (%s) to (%ws) ccString(0x%x)\n",
|
|
ANSICHECK(pszAnsiString),
|
|
WIDECHECK(pwcsString),
|
|
ccString));
|
|
}
|
|
else
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"ExtractUnicodeString found UNICODE extent\n"));
|
|
|
|
//
|
|
// There are extra characters following the AnsiString. Make a
|
|
// new buffer to copy them. Don't forget to add an extra WCHAR for
|
|
// the NULL termination
|
|
//
|
|
// AnsiStrLen + AnsiNull char
|
|
USHORT cbWideString = cbAnsiString - (cbAnsiStrLen + 1);
|
|
|
|
Assert(cbWideString != 0);
|
|
|
|
//
|
|
// There had best be an even number of bytes, or else something
|
|
// has gone wrong.
|
|
//
|
|
|
|
Assert( ! (cbWideString & 1));
|
|
// Strlen + sizeof(1 NULL char)
|
|
pwcsString = (WCHAR *) PrivMemAlloc(cbWideString + sizeof(WCHAR));
|
|
if (pwcsString == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto errRet;
|
|
}
|
|
|
|
memcpy(pwcsString,pszAnsiString + cbAnsiStrLen + 1, cbWideString);
|
|
|
|
ccString = cbWideString / sizeof(WCHAR);
|
|
|
|
pwcsString[ccString] = 0;
|
|
|
|
hr = NOERROR;
|
|
}
|
|
|
|
errRet:
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"ExtractUnicodeString result hr(%x) pwcsString(%ws) ccString(0x%x)\n",
|
|
hr,
|
|
WIDECHECK(pwcsString),
|
|
ccString));
|
|
return(hr);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::Load
|
|
//
|
|
// Synopsis: Loads an Item moniker from a stream
|
|
//
|
|
// Effects: The first version of CItemMoniker stored two counted strings
|
|
// in the stream. Both were stored in ANSI.
|
|
//
|
|
// This version saves a UNICODE string on the end of the ANSI
|
|
// string. Therefore, when it is read back in, the count of
|
|
// bytes read as the ANSI string may include a UNICODE string.
|
|
//
|
|
// See ::Save() for more details.
|
|
//
|
|
//
|
|
// Arguments: [pStm] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-16-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CItemMoniker::Load (LPSTREAM pStm)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::Load(%x)\n",
|
|
this));
|
|
|
|
VDATEIFACE(pStm);
|
|
|
|
ValidateMoniker();
|
|
|
|
HRESULT hresult;
|
|
LPSTR pszAnsiItem = NULL;
|
|
LPSTR pszAnsiDelim = NULL;
|
|
|
|
LPWSTR pwcsItem = NULL;
|
|
LPWSTR pwcsDelim = NULL;
|
|
|
|
USHORT cbAnsiDelim;
|
|
USHORT cbAnsiItem;
|
|
|
|
USHORT ccDelim;
|
|
USHORT ccItem;
|
|
|
|
//
|
|
// First, read in the two strings into the Ansi versions
|
|
//
|
|
|
|
hresult = ReadAnsiStringStream( pStm, pszAnsiDelim,cbAnsiDelim );
|
|
if (hresult != NOERROR)
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::Load(%x) pszAnsiDelim(%s) cbAnsiDelim(0x%x)\n",
|
|
this,
|
|
pszAnsiDelim,
|
|
cbAnsiDelim));
|
|
|
|
hresult = ReadAnsiStringStream( pStm, pszAnsiItem, cbAnsiItem );
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::Load(%x) pszAnsiItem(%s) cbAnsiItem(0x%x)\n",
|
|
this,
|
|
pszAnsiItem,
|
|
cbAnsiItem));
|
|
//
|
|
// Now, determine the UNICODE strings. They may be stashed at the
|
|
// end of the Ansi strings.
|
|
//
|
|
|
|
hresult = ExtractUnicodeString(pszAnsiDelim,
|
|
cbAnsiDelim,
|
|
pwcsDelim,
|
|
ccDelim);
|
|
|
|
if (FAILED(hresult))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
hresult = ExtractUnicodeString(pszAnsiItem,
|
|
cbAnsiItem,
|
|
pwcsItem,
|
|
ccItem);
|
|
if (FAILED(hresult))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
Initialize ( pwcsDelim,
|
|
ccDelim,
|
|
pszAnsiDelim,
|
|
cbAnsiDelim,
|
|
pwcsItem,
|
|
ccItem,
|
|
pszAnsiItem,
|
|
cbAnsiItem );
|
|
|
|
ValidateMoniker();
|
|
return(NOERROR);
|
|
|
|
errRet:
|
|
PrivMemFree(pszAnsiItem);
|
|
PrivMemFree(pszAnsiDelim);
|
|
PrivMemFree(pwcsItem);
|
|
PrivMemFree(pwcsDelim);
|
|
return hresult;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SaveUnicodeAsAnsi
|
|
//
|
|
// Synopsis: This function will save a string to the stream
|
|
//
|
|
// Effects:
|
|
// This routine always attempts to save the string in Ansi. If it isn't
|
|
// possible to save an Ansi version of the string, it will save an
|
|
// Ansi version (which may be NULL), and a UNICODE version.
|
|
//
|
|
// Arguments: [pStm] -- Stream to write to
|
|
// [pwcsWide] -- Unicode string
|
|
// [ccWide] -- Count of UNICODE characters (EXCL NULL)
|
|
// [pszAnsi] -- Ansi string
|
|
// [cbAnsi] -- Count of bytes (INCL NULL)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-17-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT SaveUnicodeAsAnsi( LPSTREAM pStm,
|
|
LPWSTR pwcsWide,
|
|
USHORT ccWide,
|
|
LPSTR pszAnsi,
|
|
USHORT cbAnsi)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::SaveUnicodeAsAnsi pwcsWide(%ws) ccWide(0x%x) pwsAnsi(%s) cbAnsi(0x%x)\n",
|
|
WIDECHECK(pwcsWide),
|
|
ccWide,
|
|
ANSICHECK(pszAnsi),
|
|
cbAnsi));
|
|
HRESULT hr;
|
|
BOOL fFastConvert;
|
|
|
|
//
|
|
// If the Ansi version exists, or the Unicode string is NULL,
|
|
// write out the Ansi version
|
|
//
|
|
|
|
if ((pszAnsi != NULL) || (pwcsWide == NULL))
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::SaveUnicodeAsAnsi Ansi Only (%s)\n",
|
|
ANSICHECK(pszAnsi)));
|
|
|
|
hr = WriteAnsiStringStream( pStm,
|
|
pszAnsi,
|
|
cbAnsi);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There isn't an AnsiVersion, and the UNICODE version isn't NULL
|
|
// Try to convert the UNICODE to Ansi
|
|
//
|
|
|
|
Assert( (pwcsWide != NULL) &&
|
|
(ccWide == lstrlenW(pwcsWide)));
|
|
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::SaveUnicodeAsAnsi Unicode string exists(%ws)\n",
|
|
WIDECHECK(pwcsWide)));
|
|
|
|
//
|
|
// We can use the pszAnsi pointer since it is NULL
|
|
//
|
|
|
|
Assert( pszAnsi == NULL);
|
|
|
|
hr = MnkUnicodeToMulti( pwcsWide,
|
|
ccWide,
|
|
pszAnsi,
|
|
cbAnsi,
|
|
fFastConvert);
|
|
|
|
Assert( (pszAnsi == NULL) || (cbAnsi == strlen(pszAnsi)+1) );
|
|
|
|
//
|
|
// A failure would mean out of memory, or some other terrible thing
|
|
// happened.
|
|
//
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
//
|
|
// If fFastConvert, then the UnicodeString was converted using a
|
|
// truncation algorithm, and the resulting Ansi string can be saved
|
|
// without the Unicode section appended
|
|
//
|
|
|
|
if (fFastConvert)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::SaveUnicodeAsAnsi Fast converted wide(%ws) to (%s) cbAnsi(0x%x)\n",
|
|
WIDECHECK(pwcsWide),
|
|
ANSICHECK(pszAnsi),
|
|
cbAnsi));
|
|
|
|
hr = WriteAnsiStringStream( pStm,
|
|
pszAnsi,
|
|
cbAnsi);
|
|
}
|
|
else
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::SaveUnicodeAsAnsi Full conversion wide(%ws) to (%s) cbAnsi(0x%x)\n",
|
|
WIDECHECK(pwcsWide),
|
|
ANSICHECK(pszAnsi),
|
|
cbAnsi));
|
|
|
|
hr = WriteDoubleString( pStm,
|
|
pwcsWide,
|
|
ccWide,
|
|
pszAnsi,
|
|
cbAnsi);
|
|
}
|
|
|
|
//
|
|
// We are done with the Ansi string.
|
|
//
|
|
// BUGBUG: (KevinRo) It would be nice if we could get the double
|
|
// string back from WriteDoubleString and cache it. Perhaps later
|
|
// this can be done.
|
|
//
|
|
|
|
PrivMemFree(pszAnsi);
|
|
}
|
|
|
|
errRet:
|
|
return(hr);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::Save
|
|
//
|
|
// Synopsis: Save the moniker to a stream
|
|
//
|
|
// Effects: The first version of CItemMoniker stored two counted strings
|
|
// in the stream. Both were stored in ANSI.
|
|
//
|
|
// This version saves a UNICODE string on the end of the ANSI
|
|
// string. Therefore, when it is read back in, the count of
|
|
// bytes read as the ANSI string may include a UNICODE string.
|
|
//
|
|
// We don't actually write the UNICODE string unless we have
|
|
// to.
|
|
//
|
|
// Arguments: [pStm] --
|
|
// [fClearDirty] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-16-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
// There are two ways to create a CItemMoniker. Using CreateItemMoniker(),
|
|
// and Load().
|
|
//
|
|
// If we were Load()'d, then it will be the case that we already have an
|
|
// Ansi version of both strings. In this case, we will just save those
|
|
// Ansi strings back out. If they already contain the UNICODE sections,
|
|
// then they are saved as part of the package. Hopefully, this will be
|
|
// the common case.
|
|
//
|
|
// Another possibility is the moniker was created using CreateItemMoniker.
|
|
// If this is the case, then there are no Ansi versions of the strings.
|
|
// We need to create Ansi strings, if possible. If we can't convert the
|
|
// string to Ansi cleanly, then we need to save away a UNICODE section
|
|
// of the string.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CItemMoniker::Save (LPSTREAM pStm, BOOL fClearDirty)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::Save(%x)\n",
|
|
this));
|
|
|
|
ValidateMoniker();
|
|
|
|
VDATEIFACE(pStm);
|
|
UNREFERENCED(fClearDirty);
|
|
HRESULT hr;
|
|
|
|
//
|
|
// If a AnsiDelimiter exists, OR the UNICODE version is NULL, then
|
|
// write out the Ansi version
|
|
//
|
|
|
|
hr = SaveUnicodeAsAnsi( pStm,
|
|
m_lpszDelimiter,
|
|
m_ccDelimiter,
|
|
m_pszAnsiDelimiter,
|
|
m_cbAnsiDelimiter);
|
|
if (FAILED(hr))
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::Save(%x) SaveUnicodeAsAnsi Delim failed (%x)\n",
|
|
this,
|
|
hr));
|
|
goto errRet;
|
|
}
|
|
|
|
hr = SaveUnicodeAsAnsi( pStm,
|
|
m_lpszItem,
|
|
m_ccItem,
|
|
m_pszAnsiItem,
|
|
m_cbAnsiItem);
|
|
if (FAILED(hr))
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::Save(%x) SaveUnicodeAsAnsi Item failed (%x)\n",
|
|
this,
|
|
hr));
|
|
goto errRet;
|
|
}
|
|
|
|
errRet:
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::GetSizeMax
|
|
//
|
|
// Synopsis: Get the maximum size required to serialize this moniker
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pcbSize] -- Place to return value
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-17-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CItemMoniker::GetSizeMax (ULARGE_INTEGER FAR* pcbSize)
|
|
{
|
|
ValidateMoniker();
|
|
VDATEPTROUT(pcbSize, ULARGE_INTEGER);
|
|
UINT cb;
|
|
|
|
//
|
|
// BUGBUG: (KevinRo) Revisit this calculation. Is there a better
|
|
// way of determining the size?
|
|
//
|
|
// The largest a UNICODE to MBSTRING should end up being is
|
|
// 2 * character count.
|
|
//
|
|
if (m_lpszItem)
|
|
{
|
|
cb = (m_ccItem + 1) * 2 * sizeof(WCHAR);
|
|
}
|
|
if (m_lpszDelimiter)
|
|
{
|
|
cb += (m_ccDelimiter + 1) * 2 * sizeof(WCHAR);
|
|
}
|
|
|
|
//
|
|
// sizeof(CLSID) accounts for the GUID that OleSaveToStream might
|
|
// write on our behalf. The two ULONGs are the string lengths,
|
|
// and cb is the max string sizes.
|
|
//
|
|
|
|
ULISet32(*pcbSize, sizeof(CLSID) + 2*(1 + sizeof(ULONG)) + cb);
|
|
|
|
return(NOERROR);
|
|
}
|
|
|
|
|
|
#define dwModerateTime 2500
|
|
// 2.5 seconds divides immediate from moderate.
|
|
|
|
DWORD BindSpeedFromBindCtx( LPBC pbc )
|
|
{
|
|
BIND_OPTS bindopts;
|
|
HRESULT hresult;
|
|
DWORD dwBindSpeed = BINDSPEED_INDEFINITE;
|
|
|
|
bindopts.cbStruct = sizeof(bindopts);
|
|
hresult = pbc->GetBindOptions( &bindopts );
|
|
if (hresult != NOERROR) return dwBindSpeed;
|
|
Assert( bindopts.cbStruct >= 16);
|
|
if (bindopts.dwTickCountDeadline != 0)
|
|
{
|
|
if (bindopts.dwTickCountDeadline < dwModerateTime)
|
|
dwBindSpeed = BINDSPEED_IMMEDIATE;
|
|
else dwBindSpeed = BINDSPEED_MODERATE;
|
|
}
|
|
// else speed = default, BINDSPEED_INDEFINITE
|
|
return dwBindSpeed;
|
|
}
|
|
|
|
STDMETHODIMP CItemMoniker::BindToObject ( LPBC pbc,
|
|
LPMONIKER pmkToLeft, REFIID iidResult,
|
|
VOID FAR * FAR * ppvResult)
|
|
{
|
|
M_PROLOG(this);
|
|
VDATEPTROUT(ppvResult, LPVOID);
|
|
*ppvResult = NULL;
|
|
VDATEIFACE(pbc);
|
|
if (pmkToLeft) VDATEIFACE(pmkToLeft);
|
|
VDATEIID(iidResult);
|
|
|
|
ValidateMoniker();
|
|
HRESULT hresult;
|
|
LPOLEITEMCONTAINER pOleCont;
|
|
|
|
if (pmkToLeft)
|
|
{
|
|
hresult = pmkToLeft->BindToObject( pbc, NULL, IID_IOleItemContainer,
|
|
(LPVOID FAR*)&pOleCont);
|
|
// AssertOutPtrIface(hresult, pOleCont);
|
|
if (hresult != NOERROR) return hresult;
|
|
|
|
hresult = RegisterContainerBound(pbc, pOleCont);
|
|
hresult = pOleCont->GetObject(m_lpszItem, BindSpeedFromBindCtx(pbc),
|
|
pbc, iidResult, ppvResult);
|
|
// AssertOutPtrIface(hresult, *ppvResult);
|
|
pOleCont->Release();
|
|
return hresult;
|
|
}
|
|
return ResultFromScode(E_INVALIDARG); // needs non-null moniker to left.
|
|
}
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::BindToStorage (LPBC pbc, LPMONIKER
|
|
pmkToLeft, REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
M_PROLOG(this);
|
|
VDATEPTROUT(ppvObj,LPVOID);
|
|
*ppvObj = NULL;
|
|
VDATEIFACE(pbc);
|
|
if (pmkToLeft) VDATEIFACE(pmkToLeft);
|
|
VDATEIID(riid);
|
|
|
|
HRESULT hresult;
|
|
LPOLEITEMCONTAINER pOleCont;
|
|
|
|
ValidateMoniker();
|
|
|
|
if (pmkToLeft)
|
|
{
|
|
hresult = pmkToLeft->BindToObject( pbc, NULL, IID_IOleItemContainer,
|
|
(LPVOID FAR*)&pOleCont);
|
|
// AssertOutPtrIface(hresult, pOleCont);
|
|
if (hresult != NOERROR) return hresult;
|
|
hresult = RegisterContainerBound(pbc, pOleCont);
|
|
hresult = pOleCont->GetObjectStorage(m_lpszItem, pbc,
|
|
riid, ppvObj);
|
|
// AssertOutPtrIface(hresult, *ppvObj);
|
|
pOleCont->Release();
|
|
return hresult;
|
|
}
|
|
return ResultFromScode(E_INVALIDARG); // needs non-null moniker to left.
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::ComposeWith
|
|
//
|
|
// Synopsis: Compose this moniker with another moniker
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pmkRight] --
|
|
// [fOnlyIfNotGeneric] --
|
|
// [ppmkComposite] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 2-04-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CItemMoniker::ComposeWith ( LPMONIKER pmkRight,
|
|
BOOL fOnlyIfNotGeneric, LPMONIKER FAR* ppmkComposite)
|
|
{
|
|
|
|
VDATEPTROUT(ppmkComposite,LPMONIKER);
|
|
*ppmkComposite = NULL;
|
|
VDATEIFACE(pmkRight);
|
|
|
|
HRESULT hresult = NOERROR;
|
|
|
|
ValidateMoniker();
|
|
|
|
//
|
|
// If this is an AntiMoniker, then we are going to ask the AntiMoniker
|
|
// for the composite. This is a backward compatibility problem. Check
|
|
// out the CAntiMoniker::EatOne() routine for details.
|
|
//
|
|
|
|
CAntiMoniker *pCAM = IsAntiMoniker(pmkRight);
|
|
if (pCAM)
|
|
{
|
|
pCAM->EatOne(ppmkComposite);
|
|
}
|
|
else
|
|
{
|
|
if (!fOnlyIfNotGeneric)
|
|
{
|
|
hresult = CreateGenericComposite( this, pmkRight, ppmkComposite );
|
|
}
|
|
else
|
|
{
|
|
hresult = ResultFromScode(MK_E_NEEDGENERIC);
|
|
*ppmkComposite = NULL;
|
|
}
|
|
}
|
|
return hresult;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::Enum (THIS_ BOOL fForward, LPENUMMONIKER FAR* ppenumMoniker)
|
|
{
|
|
M_PROLOG(this);
|
|
VDATEPTROUT(ppenumMoniker,LPENUMMONIKER);
|
|
*ppenumMoniker = NULL;
|
|
noError;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::IsEqual (THIS_ LPMONIKER pmkOtherMoniker)
|
|
{
|
|
M_PROLOG(this);
|
|
VDATEIFACE(pmkOtherMoniker);
|
|
|
|
ValidateMoniker();
|
|
|
|
CItemMoniker FAR* pCIM = IsItemMoniker(pmkOtherMoniker);
|
|
if (!pCIM)
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
// the other moniker is a item moniker.
|
|
// for the names, we do a case-insensitive compare.
|
|
if (m_lpszItem && pCIM->m_lpszItem)
|
|
{
|
|
if (0 == lstrcmpiW(pCIM->m_lpszItem, m_lpszItem))
|
|
return NOERROR; // S_TRUE;
|
|
}
|
|
else
|
|
return (m_lpszItem || pCIM->m_lpszItem ? ResultFromScode(S_FALSE ) : NOERROR /*S_TRUE*/);
|
|
|
|
return ResultFromScode(S_FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::Hash
|
|
//
|
|
// Synopsis: Compute a hash value
|
|
//
|
|
// Effects: Computes a hash using the same basic algorithm as the
|
|
// file moniker. If possible, use the same routine as the
|
|
// file monikers. However, if the string is longer than
|
|
// MAX_PATH, calc it on our own.
|
|
//
|
|
// Arguments: [pdwHash] --
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 1-17-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CItemMoniker::Hash (THIS_ LPDWORD pdwHash)
|
|
{
|
|
CLock lck(m_mxs); // protect m_fHashValueValid and m_dwHashValue
|
|
|
|
VDATEPTROUT(pdwHash, DWORD);
|
|
DWORD dwTemp = 0;
|
|
LPWSTR lp;
|
|
WCHAR ch;
|
|
|
|
ValidateMoniker();
|
|
if (m_fHashValueValid == FALSE)
|
|
{
|
|
//
|
|
// The CalcFileMonikerHash function does a STRUPR before running
|
|
// the length of the string. In UNICODE, that is faster.
|
|
// It uses a MAX_PATH buffer to do this. If the length is
|
|
// greater than MAX_PATH, then calculate it the old fashioned way.
|
|
//
|
|
if (m_ccItem < MAX_PATH)
|
|
{
|
|
m_dwHashValue = CalcFileMonikerHash(m_lpszItem);
|
|
}
|
|
else
|
|
{
|
|
lp = m_lpszItem;
|
|
|
|
if (lp != NULL)
|
|
{
|
|
while (*lp != 0)
|
|
{
|
|
dwTemp *= 3;
|
|
ch = (WCHAR)CharUpperW((LPWSTR)*lp);
|
|
dwTemp ^= ch;
|
|
lp++;
|
|
}
|
|
}
|
|
m_dwHashValue = dwTemp;
|
|
}
|
|
m_fHashValueValid = TRUE;
|
|
}
|
|
*pdwHash = m_dwHashValue;
|
|
|
|
return(NOERROR);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::IsRunning (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
|
|
LPMONIKER pmkNewlyRunning)
|
|
{
|
|
VDATEIFACE (pbc);
|
|
HRESULT hresult;
|
|
|
|
|
|
if (pmkToLeft)
|
|
VDATEIFACE (pmkToLeft);
|
|
if (pmkNewlyRunning)
|
|
VDATEIFACE (pmkNewlyRunning);
|
|
|
|
LPMONIKER pmkWild = NULL;
|
|
LPMONIKER pmk = NULL;
|
|
LPOLEITEMCONTAINER pCont = NULL;
|
|
LPRUNNINGOBJECTTABLE prot = NULL;
|
|
|
|
hresult = CreateItemMoniker(L"\\", NULL, &pmkWild);
|
|
if (hresult != NOERROR) goto errRet;
|
|
|
|
if (pmkToLeft == NULL)
|
|
{
|
|
if (pmkNewlyRunning != NULL)
|
|
{
|
|
hresult = IsEqual(pmkNewlyRunning);
|
|
if (hresult == NOERROR) goto errRet;
|
|
hresult = IsEqual(pmkNewlyRunning);
|
|
if (hresult != NOERROR)
|
|
{
|
|
hresult = ResultFromScode(S_FALSE);
|
|
goto errRet;
|
|
}
|
|
}
|
|
pbc->GetRunningObjectTable( &prot );
|
|
// check to see if "this" is in ROT
|
|
hresult = prot->IsRunning(this);
|
|
goto errRet;
|
|
}
|
|
|
|
hresult = pmkToLeft->IsRunning(pbc, NULL, NULL);
|
|
if (hresult == NOERROR)
|
|
{
|
|
hresult = pmkToLeft->BindToObject(pbc, NULL, IID_IOleItemContainer,
|
|
(LPVOID FAR *)&pCont );
|
|
// AssertOutPtrIface(hresult, pCont);
|
|
if (hresult == NOERROR)
|
|
{
|
|
// don't use RegisterContainerBound(pbc, pCont) here since we
|
|
// will lock/unlock the container unecessarily and possibly
|
|
// shut it down.
|
|
hresult = pbc->RegisterObjectBound(pCont);
|
|
if (hresult != NOERROR) goto errRet;
|
|
hresult = pCont->IsRunning(m_lpszItem);
|
|
}
|
|
}
|
|
errRet:
|
|
if (pmkWild) pmkWild->Release();
|
|
if (pCont) pCont->Release();
|
|
if (prot) prot->Release();
|
|
return hresult;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::GetTimeOfLastChange (THIS_ LPBC pbc, LPMONIKER pmkToLeft,
|
|
FILETIME FAR* pfiletime)
|
|
{
|
|
M_PROLOG(this);
|
|
VDATEIFACE(pbc);
|
|
if (pmkToLeft) VDATEIFACE(pmkToLeft);
|
|
VDATEPTROUT(pfiletime, FILETIME);
|
|
|
|
ValidateMoniker();
|
|
|
|
HRESULT hresult;
|
|
LPMONIKER pmkTemp = NULL;
|
|
LPRUNNINGOBJECTTABLE prot = NULL;
|
|
|
|
if (pmkToLeft == NULL)
|
|
return ResultFromScode(MK_E_NOTBINDABLE);
|
|
// Getting time of last change
|
|
// for an orphan item moniker.
|
|
|
|
// Check to see if the composite is in the running object table
|
|
hresult = CreateGenericComposite( pmkToLeft, this, &pmkTemp );
|
|
if (hresult != NOERROR) goto errRet;
|
|
hresult = pbc->GetRunningObjectTable(& prot);
|
|
if (hresult != NOERROR) goto errRet;
|
|
hresult = prot->GetTimeOfLastChange( pmkTemp, pfiletime);
|
|
if (hresult != MK_E_UNAVAILABLE) goto errRet;
|
|
|
|
// if not, pass on to the left.
|
|
hresult = pmkToLeft->GetTimeOfLastChange(pbc, NULL, pfiletime);
|
|
errRet:
|
|
if (pmkTemp) pmkTemp->Release();
|
|
if (prot) prot->Release();
|
|
return hresult;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::Inverse (THIS_ LPMONIKER FAR* ppmk)
|
|
{
|
|
M_PROLOG(this);
|
|
VDATEPTROUT(ppmk, LPMONIKER);
|
|
return CreateAntiMoniker(ppmk);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::CommonPrefixWith (LPMONIKER pmkOther, LPMONIKER FAR*
|
|
ppmkPrefix)
|
|
{
|
|
ValidateMoniker();
|
|
VDATEPTROUT(ppmkPrefix,LPMONIKER);
|
|
*ppmkPrefix = NULL;
|
|
VDATEIFACE(pmkOther);
|
|
|
|
if (!IsItemMoniker(pmkOther))
|
|
{
|
|
return(MonikerCommonPrefixWith(this,pmkOther,ppmkPrefix));
|
|
}
|
|
|
|
if (NOERROR == IsEqual(pmkOther))
|
|
{
|
|
*ppmkPrefix = this;
|
|
AddRef();
|
|
return ResultFromScode(MK_S_US);
|
|
}
|
|
return ResultFromScode(MK_E_NOPREFIX);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::RelativePathTo (THIS_ LPMONIKER pmkOther, LPMONIKER FAR*
|
|
ppmkRelPath)
|
|
{
|
|
ValidateMoniker();
|
|
VDATEPTROUT(ppmkRelPath,LPMONIKER);
|
|
|
|
*ppmkRelPath = NULL;
|
|
|
|
VDATEIFACE(pmkOther);
|
|
|
|
return ResultFromScode(MK_E_NOTBINDABLE);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::GetDisplayName ( LPBC pbc, LPMONIKER
|
|
pmkToLeft, LPWSTR FAR * lplpszDisplayName )
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"CItemMoniker::GetDisplayName(%x)\n",
|
|
this));
|
|
|
|
ValidateMoniker();
|
|
|
|
VDATEPTROUT(lplpszDisplayName, LPWSTR);
|
|
*lplpszDisplayName = NULL;
|
|
|
|
VDATEIFACE(pbc);
|
|
|
|
if (pmkToLeft)
|
|
{
|
|
VDATEIFACE(pmkToLeft);
|
|
}
|
|
|
|
ULONG cc = m_ccItem + m_ccDelimiter;
|
|
|
|
//
|
|
// cc holds the count of characters. Make extra room for the NULL
|
|
//
|
|
|
|
*lplpszDisplayName = (LPWSTR) CoTaskMemAlloc(sizeof(WCHAR)*(1 + cc));
|
|
|
|
if (*lplpszDisplayName == NULL)
|
|
{
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::GetDisplayName(%x) returning out of memory\n",
|
|
this));
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
//
|
|
// To handle the case where both strings are NULL, we set the first
|
|
// (and perhaps only) character to 0
|
|
//
|
|
|
|
*lplpszDisplayName[0] = 0;
|
|
|
|
//
|
|
// Concat the two strings. Don't forget the NULL! Thats what the
|
|
// extra character is for.
|
|
//
|
|
|
|
if (m_lpszDelimiter != NULL)
|
|
{
|
|
memcpy( *lplpszDisplayName,
|
|
m_lpszDelimiter,
|
|
(m_ccDelimiter + 1) * sizeof(WCHAR));
|
|
}
|
|
|
|
//
|
|
// The existing string was NULL terminated to just in case the
|
|
// Item string is NULL.
|
|
//
|
|
// Concat the Item string on the end of the Delimiter Again, don't
|
|
// forget the NULL.
|
|
//
|
|
|
|
if (m_lpszItem != NULL)
|
|
{
|
|
memcpy( *lplpszDisplayName + m_ccDelimiter,
|
|
m_lpszItem,
|
|
(m_ccItem + 1) * sizeof(WCHAR));
|
|
}
|
|
|
|
mnkDebugOut((DEB_ITRACE,
|
|
"::GetDisplayName(%x) returning %ws\n",
|
|
this,
|
|
*lplpszDisplayName));
|
|
|
|
return(NOERROR);
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::ParseDisplayName
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pbc] -- Bind Context
|
|
// [pmkToLeft] -- Left moniker
|
|
// [lpszDisplayName] -- String to parse
|
|
// [pchEaten] -- Output number of characters eaten
|
|
// [ppmkOut] -- Output moniker
|
|
//
|
|
// Requires:
|
|
// pmkToLeft MUST be valid. NULL is inappropriate
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 2-03-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CItemMoniker::ParseDisplayName ( LPBC pbc,
|
|
LPMONIKER pmkToLeft,
|
|
LPWSTR lpszDisplayName,
|
|
ULONG FAR* pchEaten,
|
|
LPMONIKER FAR* ppmkOut)
|
|
{
|
|
HRESULT hresult;
|
|
VDATEPTRIN(lpszDisplayName, WCHAR);
|
|
VDATEPTROUT(pchEaten,ULONG);
|
|
VDATEPTROUT(ppmkOut,LPMONIKER);
|
|
|
|
IParseDisplayName FAR * pPDN = NULL;
|
|
IOleItemContainer FAR * pOIC = NULL;
|
|
|
|
ValidateMoniker();
|
|
|
|
*pchEaten = 0;
|
|
*ppmkOut = NULL;
|
|
|
|
VDATEIFACE(pbc);
|
|
|
|
//
|
|
// Item monikers require the moniker on the left to be non-null, so
|
|
// they can get the container to parse the display name
|
|
//
|
|
|
|
if (pmkToLeft != NULL)
|
|
{
|
|
VDATEIFACE(pmkToLeft);
|
|
}
|
|
else
|
|
{
|
|
hresult = MK_E_SYNTAX;
|
|
goto errRet;
|
|
}
|
|
|
|
|
|
hresult = pmkToLeft->BindToObject( pbc,
|
|
NULL,
|
|
IID_IOleItemContainer,
|
|
(VOID FAR * FAR *)&pOIC );
|
|
if (FAILED(hresult))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
hresult = RegisterContainerBound(pbc, pOIC);
|
|
|
|
if (FAILED(hresult))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
hresult = pOIC->GetObject( m_lpszItem,
|
|
BindSpeedFromBindCtx(pbc),
|
|
pbc,
|
|
IID_IParseDisplayName,
|
|
(LPVOID FAR*)&pPDN);
|
|
if (FAILED(hresult))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
hresult = pPDN->ParseDisplayName(pbc,
|
|
lpszDisplayName,
|
|
pchEaten,
|
|
ppmkOut );
|
|
if (FAILED(hresult))
|
|
{
|
|
goto errRet;
|
|
}
|
|
|
|
hresult = pbc->RegisterObjectBound( pPDN );
|
|
|
|
errRet:
|
|
if (pPDN)
|
|
{
|
|
pPDN->Release();
|
|
}
|
|
|
|
if (pOIC)
|
|
{
|
|
pOIC->Release();
|
|
}
|
|
|
|
return hresult;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CItemMoniker::IsSystemMoniker (THIS_ LPDWORD pdwType)
|
|
{
|
|
M_PROLOG(this);
|
|
VDATEPTROUT(pdwType,DWORD);
|
|
|
|
*pdwType = MKSYS_ITEMMONIKER;
|
|
return NOERROR;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CItemMoniker::GetComparisonData
|
|
//
|
|
// Synopsis: Get comparison data for registration in the ROT
|
|
//
|
|
// Arguments: [pbData] - buffer to put the data in.
|
|
// [cbMax] - size of the buffer
|
|
// [pcbData] - count of bytes used in the buffer
|
|
//
|
|
// Returns: NOERROR
|
|
// E_OUTOFMEMORY
|
|
//
|
|
// Algorithm: Build the ROT data from internal data of the item moniker.
|
|
//
|
|
// History: 03-Feb-95 ricksa Created
|
|
//
|
|
// Note: Validating the arguments is skipped intentionally because this
|
|
// will typically be called internally by OLE with valid buffers.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CItemMoniker::GetComparisonData(
|
|
byte *pbData,
|
|
ULONG cbMax,
|
|
DWORD *pcbData)
|
|
{
|
|
//
|
|
// CLSID plus delimiter plus item plus one NULL
|
|
//
|
|
ULONG ulLength = sizeof(CLSID_ItemMoniker) +
|
|
(m_ccItem + m_ccDelimiter + 1) * sizeof(WCHAR);
|
|
|
|
Assert(pcbData != NULL);
|
|
Assert(pbData != NULL);
|
|
|
|
if (cbMax < ulLength)
|
|
{
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
|
|
//
|
|
// Copy the classID
|
|
//
|
|
memcpy(pbData,&CLSID_ItemMoniker,sizeof(CLSID_FileMoniker));
|
|
|
|
//
|
|
// Copy the delimiter WITHOUT the NULL. This saves a little space,
|
|
// and allows us to uppercase them both as a single string
|
|
//
|
|
memcpy(pbData+sizeof(CLSID_FileMoniker),
|
|
m_lpszDelimiter,
|
|
m_ccDelimiter * sizeof(WCHAR));
|
|
|
|
//
|
|
// Copy the item plus the NULL
|
|
//
|
|
memcpy(pbData+sizeof(CLSID_FileMoniker)+(m_ccDelimiter * sizeof(WCHAR)),
|
|
m_lpszItem,
|
|
(m_ccItem + 1)*sizeof(WCHAR));
|
|
|
|
//
|
|
// Insure entire string is upper case, since the item monikers are spec'd
|
|
// (and already do) case insensitive comparisions
|
|
//
|
|
CharUpperW((WCHAR *)(pbData+sizeof(CLSID_FileMoniker)));
|
|
|
|
*pcbData = ulLength;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
STDMETHODIMP_(void) NC(CItemMoniker,CDebug)::Dump ( IDebugStream FAR * pdbstm)
|
|
{
|
|
VOID_VDATEIFACE(pdbstm);
|
|
|
|
*pdbstm << "CItemMoniker @" << (VOID FAR *)m_pItemMoniker;
|
|
*pdbstm << '\n';
|
|
pdbstm->Indent();
|
|
*pdbstm << "Refcount is " << (int)(m_pItemMoniker->m_refs) << '\n';
|
|
*pdbstm << "Item string is " << m_pItemMoniker->m_lpszItem << '\n';
|
|
*pdbstm << "Delimiter is " << m_pItemMoniker->m_lpszDelimiter << '\n';
|
|
pdbstm->UnIndent();
|
|
}
|
|
|
|
STDMETHODIMP_(BOOL) NC(CItemMoniker,CDebug)::IsValid ( BOOL fSuspicious )
|
|
{
|
|
return ((LONG)(m_pItemMoniker->m_refs) > 0);
|
|
// add more later, maybe
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// Unlock Delay object
|
|
//
|
|
class FAR CDelayUnlockContainer : public CPrivAlloc, public IUnknown
|
|
{
|
|
public:
|
|
STDMETHOD(QueryInterface) ( REFIID iid, LPVOID FAR* ppvObj);
|
|
STDMETHOD_(ULONG,AddRef) (void);
|
|
STDMETHOD_(ULONG,Release) (void);
|
|
|
|
CDelayUnlockContainer();
|
|
|
|
private:
|
|
ULONG m_refs;
|
|
IOleItemContainer FAR * m_pOleCont;
|
|
|
|
friend INTERNAL RegisterContainerBound(LPBC pbc, LPOLEITEMCONTAINER pOleCont);
|
|
};
|
|
|
|
|
|
CDelayUnlockContainer::CDelayUnlockContainer()
|
|
{
|
|
m_pOleCont = NULL;
|
|
m_refs = 1;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDelayUnlockContainer::QueryInterface (REFIID iid, LPLPVOID ppv)
|
|
{
|
|
M_PROLOG(this);
|
|
if (IsEqualIID(iid, IID_IUnknown))
|
|
{
|
|
*ppv = this;
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
else {
|
|
*ppv = NULL;
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CDelayUnlockContainer::AddRef ()
|
|
{
|
|
return(InterlockedIncrement((long *)&m_refs));
|
|
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CDelayUnlockContainer::Release ()
|
|
{
|
|
if (InterlockedDecrement((long *)&m_refs) == 0)
|
|
{
|
|
if (m_pOleCont != NULL)
|
|
{
|
|
m_pOleCont->LockContainer(FALSE);
|
|
m_pOleCont->Release();
|
|
}
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
INTERNAL RegisterContainerBound (LPBC pbc, LPOLEITEMCONTAINER pOleCont)
|
|
{
|
|
// don't give the delay object the pOleCont before we lock it; do in
|
|
// this order so error checking is correct and we don't lock/unlock
|
|
// inappropriately.
|
|
|
|
CDelayUnlockContainer FAR* pCDelay = new CDelayUnlockContainer();
|
|
if (pCDelay == NULL)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
HRESULT hresult;
|
|
if ((hresult = pbc->RegisterObjectBound(pCDelay)) != NOERROR)
|
|
goto errRet;
|
|
|
|
if ((hresult = pOleCont->LockContainer(TRUE)) != NOERROR) {
|
|
// the delay object is still in the bindctx; no harm
|
|
hresult = E_FAIL;
|
|
goto errRet;
|
|
}
|
|
|
|
|
|
pCDelay->m_pOleCont = pOleCont;
|
|
pOleCont->AddRef();
|
|
|
|
errRet:
|
|
pCDelay->Release();
|
|
return hresult;
|
|
}
|