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

1355 lines
41 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: I S H E L L F . C P P
//
// Contents: IShellFolder implementation for CConnectionFolder
//
// Notes: The IShellFolder interface is used to manage folders within
// the namespace. Objects that support IShellFolder are
// usually created by other shell folder objects, with the root
// object (the Desktop shell folder) being returned from the
// SHGetDesktopFolder function.
//
// Author: jeffspr 22 Sep 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "foldinc.h" // Standard shell\folder includes
#include "cfutils.h" // Connections folder utilities
#include "foldres.h"
#include "ncnetcon.h"
#include "droptarget.h"
#include "ncperms.h"
#include "ncras.h"
#include "cmdtable.h"
#include "webview.h"
#define ENABLE_CONNECTION_TOOLTIP
const WCHAR c_szNetworkConnections[] = L"NetworkConnections";
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::ParseDisplayName
//
// Purpose: Translates a file object or folder's display name into an
// item identifier.
//
// Arguments:
// hwndOwner [in] Handle of owner window
// pbcReserved [in] Reserved
// lpszDisplayName [in] Pointer to diplay name
// pchEaten [out] Pointer to value for parsed characters
// ppidl [out] Pointer to new item identifier list
// pdwAttributes [out] Address receiving attributes of file object
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise
//
// Author: jeffspr 18 Oct 1997
STDMETHODIMP CConnectionFolder::ParseDisplayName(
HWND hwndOwner,
LPBC pbcReserved,
LPOLESTR lpszDisplayName,
ULONG * pchEaten,
LPITEMIDLIST * ppidl,
ULONG * pdwAttributes)
{
HRESULT hr = S_OK;
TraceFileFunc(ttidShellFolder);
if (!ppidl)
{
return E_POINTER;
}
*ppidl = NULL;
if ((lpszDisplayName == NULL) ||
(wcslen(lpszDisplayName) < (c_cchGuidWithTerm - 1)))
{
return E_INVALIDARG;
}
while (*lpszDisplayName == ':')
{
lpszDisplayName++;
}
if (*lpszDisplayName != '{')
{
return E_INVALIDARG;
}
GUID guid;
if (SUCCEEDED(CLSIDFromString(lpszDisplayName, &guid)))
{
if (g_ccl.IsInitialized() == FALSE)
{
g_ccl.HrRefreshConManEntries();
}
PCONFOLDPIDL pidl;
hr = g_ccl.HrFindPidlByGuid(&guid, pidl);
if (S_OK == hr)
{
*ppidl = pidl.TearOffItemIdList();
TraceTag(ttidShellFolderIface, "IShellFolder::ParseDisplayName generated PIDL: 0x%08x", *ppidl);
}
else
{
hr = E_FILE_NOT_FOUND;
}
}
else
{
return(E_FAIL);
}
if (SUCCEEDED(hr) && pdwAttributes)
{
LPCITEMIDLIST pidlArr[1];
pidlArr[0] = *ppidl;
hr = GetAttributesOf(1, pidlArr, pdwAttributes);
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::EnumObjects
//
// Purpose: Determines the contents of a folder by creating an item
// enumeration object (a set of item identifiers) that can be
// retrieved using the IEnumIDList interface.
//
// Arguments:
// hwndOwner [in] Handle of owner window
// grfFlags [in] Items to include in enumeration
// ppenumIDList [out] Pointer to IEnumIDList
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise
//
// Author: jeffspr 18 Oct 1997
//
// Notes:
//
STDMETHODIMP CConnectionFolder::EnumObjects(
HWND hwndOwner,
DWORD grfFlags,
LPENUMIDLIST * ppenumIDList)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = NOERROR;
Assert(ppenumIDList);
NETCFG_TRY
// Create the IEnumIDList object (CConnectionFolderEnum)
//
hr = CConnectionFolderEnum::CreateInstance (
IID_IEnumIDList,
reinterpret_cast<void**>(ppenumIDList));
if (SUCCEEDED(hr))
{
Assert(*ppenumIDList);
// Call the PidlInitialize function to allow the enumeration
// object to copy the list.
//
reinterpret_cast<CConnectionFolderEnum *>(*ppenumIDList)->PidlInitialize(
FALSE, m_pidlFolderRoot, m_dwEnumerationType);
}
else
{
// On all failures, this should be NULL.
if (*ppenumIDList)
{
ReleaseObj(*ppenumIDList);
}
*ppenumIDList = NULL;
}
NETCFG_CATCH(hr)
TraceHr(ttidError, FAL, hr, FALSE, "CConnectionFolder::EnumObjects");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::BindToObject
//
// Purpose: Creates an IShellFolder object for a subfolder.
//
// Arguments:
// pidl [in] Pointer to an ITEMIDLIST
// pbcReserved [in] Reserved - specify NULL
// riid [in] Interface to return
// ppvOut [out] Address that receives interface pointer;
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise
//
// Author: jeffspr 18 Oct 1997
//
// Notes: We don't need this function, since we don't have subfolders.
//
STDMETHODIMP CConnectionFolder::BindToObject(
LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID * ppvOut)
{
TraceFileFunc(ttidShellFolder);
// Note - If we add code here, then we ought to param check pidl
//
Assert(pidl);
*ppvOut = NULL;
return E_NOTIMPL;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::BindToStorage
//
// Purpose: Reserved for a future use. This method should
// return E_NOTIMPL.
//
// Arguments:
// pidl [] Pointer to an ITEMIDLIST
// pbcReserved [] Reserved¾specify NULL
// riid [] Interface to return
// ppvObj [] Address that receives interface pointer);
//
// Returns: E_NOTIMPL always
//
// Author: jeffspr 18 Oct 1997
//
// Notes:
//
STDMETHODIMP CConnectionFolder::BindToStorage(
LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID * ppvObj)
{
TraceFileFunc(ttidShellFolder);
// Note - If we add code here, then we ought to param check pidl
//
Assert(pidl);
*ppvObj = NULL;
return E_NOTIMPL;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::CompareIDs
//
// Purpose: Determines the relative ordering of two file objects or
// folders, given their item identifier lists.
//
// Arguments:
// lParam [in] Type of comparison to perform
// pidl1 [in] Address of ITEMIDLIST structure
// pidl2 [in] Address of ITEMIDLIST structure
//
// Returns: Returns a handle to a result code. If this method is
// successful, the CODE field of the status code (SCODE) has
// the following meaning:
//
// CODE field Meaning
// ---------- -------
// Less than zero The first item should precede the second
// (pidl1 < pidl2).
// Greater than zero The first item should follow the second
// (pidl1 > pidl2)
// Zero The two items are the same (pidl1 = pidl2)
//
// Author: jeffspr 18 Oct 1997
//
// Notes: Passing 0 as the lParam indicates sort by name.
// 0x00000001-0x7fffffff are for folder specific sorting rules.
// 0x80000000-0xfffffff are used the system.
//
STDMETHODIMP CConnectionFolder::CompareIDs(
LPARAM lParam,
LPCITEMIDLIST pidl1,
LPCITEMIDLIST pidl2)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = S_OK;
int iCompare = 0;
CONFOLDENTRY pccfe1;
CONFOLDENTRY pccfe2;
PCONFOLDPIDL pcfp1;
PCONFOLDPIDL pcfp2;
ConnListEntry cle1;
ConnListEntry cle2;
PCWSTR pszString1 = NULL;
PCWSTR pszString2 = NULL;
INT iStringID1 = 0;
INT iStringID2 = 0;
hr = pcfp1.InitializeFromItemIDList(pidl1);
if (SUCCEEDED(hr))
{
hr = pcfp2.InitializeFromItemIDList(pidl2);
}
// Make sure that the pidls passed in are our pidls.
//
if (FAILED(hr))
{
hr = E_INVALIDARG;
goto Exit;
}
if (WIZARD_NOT_WIZARD != pcfp1->wizWizard && WIZARD_NOT_WIZARD != pcfp2->wizWizard)
{
hr = ResultFromShort(0);
if (pcfp1->wizWizard > pcfp2->wizWizard)
hr = ResultFromShort(-1);
if (pcfp1->wizWizard < pcfp2->wizWizard)
hr = ResultFromShort(1);
goto Exit;
}
// If the first item is a wizard, then it comes first.
//
if (WIZARD_NOT_WIZARD != pcfp1->wizWizard)
{
hr = ResultFromShort(-1);
goto Exit;
}
// If the second item is a wizard, then, well, you get the picture.
//
if (WIZARD_NOT_WIZARD != pcfp2->wizWizard)
{
hr = ResultFromShort(1);
goto Exit;
}
// Note: (jeffspr) & SHC... should be removed once Victor Tan checks in a fix
// for the IShellFolder2 params being used in IShellFolder
//
switch(lParam & SHCIDS_COLUMNMASK)
{
case ICOL_NAME:
{
// Check the name. If the name is the same, then we need to
// check the GUID as well, because we HAVE TO allow duplicate names,
// and this function is used to uniquely identify connections for
// notification purposes
//
LPCWSTR szPcfpName1 = pcfp1->PszGetNamePointer() ? pcfp1->PszGetNamePointer() : L"\0";
LPCWSTR szPcfpName2 = pcfp2->PszGetNamePointer() ? pcfp2->PszGetNamePointer() : L"\0";
iCompare = lstrcmpW(szPcfpName1, szPcfpName2);
if (iCompare == 0)
{
if (!InlineIsEqualGUID(pcfp1->guidId, pcfp2->guidId))
{
// Doesn't really matter which order we put them
// in, as long as we call them non-equal
iCompare = -1;
}
}
}
break;
case ICOL_TYPE:
{
MapNCMToResourceId(pcfp1->ncm, pcfp1->dwCharacteristics, &iStringID1);
MapNCMToResourceId(pcfp2->ncm, pcfp2->dwCharacteristics, &iStringID2);
pszString1 = (PWSTR) SzLoadIds(iStringID1);
pszString2 = (PWSTR) SzLoadIds(iStringID2);
if (pszString1 && pszString2)
{
iCompare = lstrcmpW(pszString1, pszString2);
}
}
break;
case ICOL_STATUS:
{
WCHAR szString1[CONFOLD_MAX_STATUS_LENGTH];
WCHAR szString2[CONFOLD_MAX_STATUS_LENGTH];
MapNCSToComplexStatus(pcfp1->ncs, pcfp1->ncm, pcfp1->ncsm, pcfp1->dwCharacteristics, szString1, CONFOLD_MAX_STATUS_LENGTH, pcfp1->guidId);
MapNCSToComplexStatus(pcfp2->ncs, pcfp2->ncm, pcfp1->ncsm, pcfp2->dwCharacteristics, szString2, CONFOLD_MAX_STATUS_LENGTH, pcfp2->guidId);
iCompare = lstrcmpW(szString1, szString2);
}
break;
case ICOL_DEVICE_NAME:
{
LPCWSTR szPcfpDeviceName1 = pcfp1->PszGetDeviceNamePointer() ? pcfp1->PszGetDeviceNamePointer() : L"\0";
LPCWSTR szPcfpDeviceName2 = pcfp2->PszGetDeviceNamePointer() ? pcfp2->PszGetDeviceNamePointer() : L"\0";
iCompare = lstrcmpW(szPcfpDeviceName1, szPcfpDeviceName2);
}
break;
case ICOL_OWNER:
{
pszString1 = PszGetOwnerStringFromCharacteristics(pszGetUserName(), pcfp1->dwCharacteristics);
pszString2 = PszGetOwnerStringFromCharacteristics(pszGetUserName(), pcfp2->dwCharacteristics);
iCompare = lstrcmpW(pszString1, pszString2);
}
break;
case ICOL_PHONEORHOSTADDRESS:
{
LPCWSTR szPcfpPhoneHostAddress1 = pcfp1->PszGetPhoneOrHostAddressPointer() ? pcfp1->PszGetPhoneOrHostAddressPointer() : L"\0";
LPCWSTR szPcfpPhoneHostAddress2 = pcfp2->PszGetPhoneOrHostAddressPointer() ? pcfp2->PszGetPhoneOrHostAddressPointer() : L"\0";
iCompare = lstrcmpW(szPcfpPhoneHostAddress1, szPcfpPhoneHostAddress2);
}
break;
default:
// AssertFmt(FALSE, FAL, "Shell bug - Sorting on unknown category. Column = %x", (lParam & SHCIDS_COLUMNMASK));
hr = E_INVALIDARG;
break;
}
if (SUCCEEDED(hr))
{
hr = ResultFromShort(iCompare);
}
Exit:
// If these were allocated instead of cached, delete them
//
TraceHr(ttidError, FAL, hr,
(ResultFromShort(-1) == hr) || (ResultFromShort(1) == hr),
"CConnectionFolder::CompareIDs");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::CreateViewObject
//
// Purpose: Creates a view object of a folder.
//
// Arguments:
// hwndOwner [in] Handle of owner window
// riid [in] Interface identifier
// ppvOut [none] Reserved
//
// Returns: Returns NOERROR if successful or an OLE defined error
// value otherwise.
//
// Author: jeffspr 18 Oct 1997
//
// Notes:
//
STDMETHODIMP CConnectionFolder::CreateViewObject(
HWND hwndOwner,
REFIID riid,
LPVOID * ppvOut)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = E_NOINTERFACE;
Assert(ppvOut);
Assert(this);
// Pre-initialize the out param, per OLE guidelines
//
*ppvOut = NULL;
if (riid == IID_IShellView)
{
if (FHasPermission(NCPERM_OpenConnectionsFolder))
{
SFV_CREATE sfv = {0};
sfv.cbSize = sizeof(sfv);
sfv.pshf = dynamic_cast<IShellFolder2*>(this);
sfv.psfvcb = dynamic_cast<IShellFolderViewCB*>(this);
// Note: The shell never gets around to freeing the last view
// when shutting down...
//
hr = SHCreateShellFolderView(&sfv, &m_pShellView);
if (SUCCEEDED(hr))
{
*ppvOut = m_pShellView;
DWORD dwErr = 0;
// Get the state of the "ManualDial" flag from RAS
// so we can initialize our global
//
dwErr = RasUserGetManualDial(
hwndOwner,
FALSE,
(PBOOL) (&g_fOperatorAssistEnabled));
// Ignore the error (don't shove it in the Hr), because
// we still want to run even if we failed to get the value
// Trace it, though
Assert(dwErr == 0);
TraceHr(ttidShellFolder, FAL, HRESULT_FROM_WIN32(dwErr), FALSE,
"RasUserGetManualDial call from CreateViewObject");
}
}
else
{
TraceTag(ttidShellFolder, "No permission to open connections folder (FHasPermission returned 0)");
AssertSz(FALSE, "get off!");
if (hwndOwner)
{
NcMsgBox(_Module.GetResourceInstance(), hwndOwner,
IDS_CONFOLD_WARNING_CAPTION,
IDS_CONFOLD_NO_PERMISSIONS_FOR_OPEN,
MB_ICONEXCLAMATION | MB_OK);
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // user saw the error
}
else
{
hr = E_ACCESSDENIED;
}
}
}
else if (riid == IID_IContextMenu)
{
// Create our context menu object for the background CMs.
//
hr = CConnectionFolderContextMenu::CreateInstance (
IID_IContextMenu,
reinterpret_cast<void**>(ppvOut),
CMT_BACKGROUND,
hwndOwner,
PCONFOLDPIDLVEC(NULL),
this);
if (SUCCEEDED(hr))
{
Assert(*ppvOut);
}
}
else if (riid == IID_ICategoryProvider)
{
// Create our context menu object for the background CMs.
//
CComPtr<IDefCategoryProvider> pDevCategoryProvider;
hr = CoCreateInstance(CLSID_DefCategoryProvider, NULL, CLSCTX_ALL, IID_IDefCategoryProvider, reinterpret_cast<LPVOID *>(&pDevCategoryProvider));
if (SUCCEEDED(hr))
{
SHCOLUMNID pscidType, pscidPhoneOrHostAddress;
MapColumnToSCID(ICOL_TYPE, &pscidType);
MapColumnToSCID(ICOL_PHONEORHOSTADDRESS, &pscidPhoneOrHostAddress);
SHCOLUMNID pscidExclude[2];
pscidExclude[0].fmtid = GUID_NETSHELL_PROPS;
pscidExclude[0].pid = ICOL_PHONEORHOSTADDRESS;
pscidExclude[1].fmtid = GUID_NULL;
pscidExclude[1].pid = 0;
CATLIST catList[] =
{
{&GUID_NULL, NULL}
};
if (SUCCEEDED(hr))
{
pDevCategoryProvider->Initialize(&GUID_NETSHELL_PROPS,
&pscidType,
pscidExclude,
NULL,
catList,
this);
hr = pDevCategoryProvider->QueryInterface(IID_ICategoryProvider, ppvOut);
}
}
}
else
{
goto Exit;
}
Exit:
TraceHr(ttidError, FAL, hr, (E_NOINTERFACE == hr),
"CConnectionFolder::CreateViewObject");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::GetAttributesOf
//
// Purpose: Retrieves the attributes that all passed-in objects (file
// objects or subfolders) have in common.
//
// Arguments:
// cidl [in] Number of file objects
// apidl [in] Pointer to array of pointers to ITEMIDLIST structures
// rgfInOut [out] Address of value containing attributes of the
// file objects
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise.
//
// Author: jeffspr 18 Oct 1997
//
// Notes:
//
STDMETHODIMP CConnectionFolder::GetAttributesOf(
UINT cidl,
LPCITEMIDLIST * apidl,
ULONG * rgfInOut)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = S_OK;
ULONG rgfMask = 0;
PCONFOLDPIDL pcfp;
if (cidl > 0)
{
PCONFOLDPIDLVEC pcfpVec;
hr = PConfoldPidlVecFromItemIdListArray(apidl, cidl, pcfpVec);
if (FAILED(hr))
{
return E_INVALIDARG;
}
// Prepopulate with all values (removed CANCOPY and CANMOVE)
//
rgfMask = SFGAO_CANDELETE |
SFGAO_CANRENAME |
SFGAO_CANLINK |
SFGAO_HASPROPSHEET;
// Disable propsheets for > 1 connection
//
if (cidl > 1)
{
rgfMask &= ~SFGAO_HASPROPSHEET;
}
PCONFOLDPIDLVEC::const_iterator iterLoop;
for (iterLoop = pcfpVec.begin(); iterLoop != pcfpVec.end(); iterLoop++)
{
// Translate the PIDL to our struct, and check for wizard inclusion.
// If so, then we don't support anything but "link". If not, then
// we support all of the standard actions
const PCONFOLDPIDL& pcfp = *iterLoop;
if(!pcfp.empty())
{
if (((*rgfInOut) & SFGAO_VALIDATE))
{
ConnListEntry cleDontCare;
hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cleDontCare);
if (hr != S_OK)
{
// Note: Remove this when we get RAS notifications, because
// we will ALWAYS have the information we need to find the connections
// We're doing this because the CM folks are creating RAS icons on the
// desktop without us knowing about it.
//
// If we didn't find it, then flush the cache and try again.
//
if (S_FALSE == hr)
{
hr = g_ccl.HrRefreshConManEntries();
if (SUCCEEDED(hr))
{
hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cleDontCare);
if (hr != S_OK)
{
hr = E_FAIL;
goto Exit;
}
}
}
else
{
hr = E_FAIL;
goto Exit;
}
}
}
if (WIZARD_NOT_WIZARD != pcfp->wizWizard)
{
// No support for delete/rename/etc, since it's the wizard.
// However, we want to provide our own "delete" warning when the
// wizard is selected along with deleteable connections
//
rgfMask = SFGAO_CANLINK | SFGAO_CANDELETE;
}
if (pcfp->dwCharacteristics & NCCF_BRANDED)
{
if ( !fIsConnectedStatus(pcfp->ncs) && (pcfp->ncs != NCS_DISCONNECTING) )
{
rgfMask |= SFGAO_GHOSTED;
}
}
if (pcfp->dwCharacteristics & NCCF_INCOMING_ONLY)
{
rgfMask &= ~SFGAO_CANLINK;
}
// Mask out the unavailable attributes for this connection
//
if (!(pcfp->dwCharacteristics & NCCF_ALLOW_RENAME) || !HasPermissionToRenameConnection(pcfp))
{
rgfMask &= ~SFGAO_CANRENAME;
}
#if 0 // If I mask this out, I can't give user feedback for objects that can't be deleted.
if (pcfp->dwCharacteristics & NCCF_ALLOW_REMOVAL)
{
rgfMask |= SFGAO_CANDELETE;
}
#endif
}
}
}
else
{
// Apparently, we're called with 0 objects to indicate that we're
// supposed to return flags for the folder itself, not an individual
// object. Weird.
rgfMask = SFGAO_CANCOPY |
SFGAO_CANDELETE |
SFGAO_CANMOVE |
SFGAO_CANRENAME |
SFGAO_DROPTARGET;
}
Exit:
if (SUCCEEDED(hr))
{
*rgfInOut &= rgfMask;
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::GetUIObjectOf
//
// Purpose: Creates a COM object that can be used to carry out actions
// on the specified file objects or folders, typically, to
// create context menus or carry out drag-and-drop operations.
//
// Arguments:
// hwndOwner [in] Handle to owner window
// cidl [in] Number of objects specified in apidl
// apidl [in] Pointer to an array of pointers to an ITEMIDLIST
// riid [in] Interface to return
// prgfInOut [none] Reserved
// ppvOut [out] Address to receive interface pointer
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise
//
// Author: jeffspr 18 Oct 1997
//
// Notes:
//
STDMETHODIMP CConnectionFolder::GetUIObjectOf(
HWND hwndOwner,
UINT cidl,
LPCITEMIDLIST * apidl,
REFIID riid,
UINT * prgfInOut,
LPVOID * ppvOut)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = E_NOINTERFACE;
NETCFG_TRY
if (cidl >= 1)
{
Assert(apidl);
Assert(apidl[0]);
Assert(ppvOut);
if (riid == IID_IDataObject)
{
// Need to initialize so the SUCCEEED check below doesn't fail.
//
hr = S_OK;
if (m_pidlFolderRoot.empty())
{
hr = HrGetConnectionsFolderPidl(m_pidlFolderRoot);
}
if (SUCCEEDED(hr))
{
Assert(!m_pidlFolderRoot.empty());
// Internal IDataObject impl removed. Replaced with common
// shell code.
//
hr = CIDLData_CreateFromIDArray(m_pidlFolderRoot.GetItemIdList(), cidl, apidl, (IDataObject **) ppvOut);
}
}
else if (riid == IID_IContextMenu)
{
PCONFOLDPIDLVEC pcfpVec;
hr = PConfoldPidlVecFromItemIdListArray(apidl, cidl, pcfpVec);
if (FAILED(hr))
{
return E_INVALIDARG;
}
// Create our context menu object for the background CMs.
//
if (SUCCEEDED(hr))
{
hr = CConnectionFolderContextMenu::CreateInstance (
IID_IContextMenu,
reinterpret_cast<void**>(ppvOut),
CMT_OBJECT,
hwndOwner,
pcfpVec,
this);
if (SUCCEEDED(hr))
{
Assert(*ppvOut);
}
else
{
hr = E_NOINTERFACE;
}
}
}
else if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
{
if (cidl == 1)
{
hr = CConnectionFolderExtractIcon::CreateInstance (
apidl[0],
riid,
reinterpret_cast<void**>(ppvOut));
if (SUCCEEDED(hr))
{
Assert(*ppvOut);
}
}
else
{
hr = E_NOINTERFACE;
}
}
else if (riid == IID_IDropTarget)
{
hr = E_NOINTERFACE;
}
else if (riid == IID_IQueryAssociations)
{
CComPtr<IQueryAssociations> pQueryAssociations;
hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, reinterpret_cast<LPVOID *>(&pQueryAssociations));
if (SUCCEEDED(hr))
{
hr = pQueryAssociations->Init(0, c_szNetworkConnections, NULL, NULL);
if (SUCCEEDED(hr))
{
hr = pQueryAssociations->QueryInterface(IID_IQueryAssociations, ppvOut);
}
}
}
else if (riid == IID_IQueryInfo)
{
#ifdef ENABLE_CONNECTION_TOOLTIP
if (cidl == 1)
{
PCONFOLDPIDLVEC pcfpVec;
hr = PConfoldPidlVecFromItemIdListArray(apidl, cidl, pcfpVec);
if (FAILED(hr))
{
return E_INVALIDARG;
}
const PCONFOLDPIDL& pcfp = *pcfpVec.begin();
// Create the IQueryInfo interface
hr = CConnectionFolderQueryInfo::CreateInstance (
IID_IQueryInfo,
reinterpret_cast<void**>(ppvOut));
if (SUCCEEDED(hr))
{
Assert(*ppvOut);
reinterpret_cast<CConnectionFolderQueryInfo *>
(*ppvOut)->PidlInitialize(*pcfpVec.begin());
// Normalize return code
//
hr = NOERROR;
}
}
else
{
AssertSz(FALSE, "GetUIObjectOf asked for query info for more than one item!");
hr = E_NOINTERFACE;
}
#else
hr = E_NOINTERFACE;
#endif // ENABLE_CONNECTION_TOOLTIP
}
else
{
TraceTag(ttidShellFolder, "CConnectionFolder::GetUIObjectOf asked for object "
"that it didn't know how to create. 0x%08x", riid.Data1);
hr = E_NOINTERFACE;
}
}
if (FAILED(hr))
{
*ppvOut = NULL;
}
NETCFG_CATCH(hr)
TraceHr(ttidError, FAL, hr, (hr == E_NOINTERFACE), "CConnectionFolder::GetUIObjectOf");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::GetDisplayNameOf
//
// Purpose: Retrieves the display name for the specified file object or
// subfolder, returning it in a STRRET structure.
//
// Arguments:
// pidl [in] Pointer to an ITEMIDLIST
// uFlags [in] Type of display to return
// lpName [out] Pointer to a STRRET structure
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise.
//
// Author: jeffspr 18 Oct 1997
//
// Notes:
//
STDMETHODIMP CConnectionFolder::GetDisplayNameOf(
LPCITEMIDLIST pidl,
DWORD uFlags,
LPSTRRET lpName)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = S_OK;
PWSTR pszStrToCopy = NULL;
Assert(lpName);
if (!pidl || !lpName)
{
return E_INVALIDARG;
}
PCONFOLDPIDL pcfpLatestVersion;
PCONFOLDPIDL pcfpLatestVersionCached;
PCONFOLDPIDL98 pcfp98;
CONFOLDPIDLTYPE cfpt = GetPidlType(pidl);
switch (cfpt)
{
case PIDL_TYPE_V1:
case PIDL_TYPE_V2:
if (FAILED(pcfpLatestVersion.InitializeFromItemIDList(pidl)))
{
return E_INVALIDARG;
}
break;
case PIDL_TYPE_98:
if (FAILED(pcfp98.InitializeFromItemIDList(pidl)))
{
return E_INVALIDARG;
}
break;
default:
AssertSz(FALSE, "CConnectionFolder::GetDisplayNameOf - Invalid PIDL");
return E_INVALIDARG;
break;
}
if ( (PIDL_TYPE_V1 == cfpt) || (PIDL_TYPE_V2 == cfpt) )
{
#ifdef DBG
// Throw these in here just so I can quickly peek at the values
// set while I'm dorking around in the debugger.
//
DWORD dwInFolder = (uFlags & SHGDN_INFOLDER);
DWORD dwForAddressBar = (uFlags & SHGDN_FORADDRESSBAR);
DWORD dwForParsing = (uFlags & SHGDN_FORPARSING);
#endif
// Find the correct string for the display name. For the wizard, we get it
// from the resources. Otherwise, we use the actual connection name
//
lpName->uType = STRRET_WSTR;
if (uFlags & SHGDN_FORPARSING)
{
lpName->pOleStr = (LPWSTR)SHAlloc(c_cbGuidWithTerm);
if (lpName->pOleStr == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
if (StringFromGUID2(pcfpLatestVersion->clsid, lpName->pOleStr, c_cbGuidWithTerm) == 0)
{
return(ERROR_INVALID_NAME);
}
return(S_OK);
}
else if (WIZARD_MNC == pcfpLatestVersion->wizWizard)
{
pszStrToCopy = (PWSTR) SzLoadIds(IDS_CONFOLD_WIZARD_DISPLAY_NAME);
}
else if (WIZARD_HNW == pcfpLatestVersion->wizWizard)
{
pszStrToCopy = (PWSTR) SzLoadIds(IDS_CONFOLD_HOMENET_WIZARD_DISPLAY_NAME);
}
else
{
hr = g_ccl.HrGetCachedPidlCopyFromPidl(pcfpLatestVersion, pcfpLatestVersionCached);
if (S_OK == hr)
{
pszStrToCopy = pcfpLatestVersionCached->PszGetNamePointer();
}
else
{
pszStrToCopy = pcfpLatestVersion->PszGetNamePointer();
hr = S_OK;
}
}
Assert(pszStrToCopy);
// Allocate a new POLESTR block, which the shell can then free,
// and copy the displayable portion to it.
//
// Note that &lpName->pOleStr is likely misaligned.
//
LPWSTR pOleStr;
pOleStr = lpName->pOleStr;
hr = HrDupeShellString(pszStrToCopy, &pOleStr );
lpName->pOleStr = pOleStr;
}
else if (PIDL_TYPE_98 == cfpt)
{
// Raid#214057, handle win98 pidl for shortcuts
// Return the offset to the string because we store the display
// name in the opaque structure.
lpName->uType = STRRET_OFFSET;
lpName->uOffset = _IOffset(CONFOLDPIDL98, szaName);
}
else
{
// not a valid connections pidl (neither Win2K nor Win98).
//
hr = E_INVALIDARG;
}
TraceHr(ttidError, FAL, hr, FALSE, "CConnectionFolder::GetDisplayNameOf");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::SetNameOf
//
// Purpose: Changes the name of a file object or subfolder, changing its
// item identifier in the process.
//
// Arguments:
// hwndOwner [in] Handle of owner window
// pidl [in] Pointer to an ITEMIDLIST structure
// lpszName [in] Pointer to string specifying new display name
// uFlags [in] Type of name specified in lpszName
// ppidlOut [out] Pointer to new ITEMIDLIST
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise.
//
// Author: jeffspr 18 Oct 1997
//
// Notes:
//
STDMETHODIMP CConnectionFolder::SetNameOf(
HWND hwndOwner,
LPCITEMIDLIST pidlShell,
LPCOLESTR lpszName,
DWORD uFlags,
LPITEMIDLIST * ppidlOut)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = NOERROR;
/*
PWSTR pszWarning = NULL;
INetConnection * pNetCon = NULL;
LPITEMIDLIST pidlNew = NULL;
BOOL fRefresh = FALSE;
BOOL fActivating = FALSE;
PCONFOLDENTRY pccfe = NULL;
*/
PCONFOLDPIDL pcfp;
Assert(hwndOwner);
Assert(pidlShell);
Assert(lpszName);
if (!pidlShell && !lpszName)
{
hr = E_INVALIDARG;
}
else
{
// check lpszName for validity
if (!FIsValidConnectionName(lpszName))
{
(void) NcMsgBox(
_Module.GetResourceInstance(),
hwndOwner,
IDS_CONFOLD_RENAME_FAIL_CAPTION,
IDS_CONFOLD_RENAME_INVALID,
MB_OK | MB_ICONEXCLAMATION);
hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
}
if (SUCCEEDED(hr))
{
// Get what's current from the cache so rename works properly
//
PCONFOLDPIDL pcfpShell;
hr = pcfpShell.InitializeFromItemIDList(pidlShell);
if (SUCCEEDED(hr))
{
hr = g_ccl.HrGetCachedPidlCopyFromPidl(pcfpShell, pcfp);
if (SUCCEEDED(hr))
{
PCONFOLDPIDL pidlOut;
hr = HrRenameConnectionInternal(pcfp, m_pidlFolderRoot, lpszName, TRUE, hwndOwner, pidlOut);
if ( (ppidlOut) && (SUCCEEDED(hr)) )
{
*ppidlOut = pidlOut.TearOffItemIdList();
}
}
}
}
}
if (FAILED(hr) && (ppidlOut))
{
*ppidlOut = NULL;
}
TraceHr(ttidError, FAL, hr, FALSE, "CConnectionFolder::SetNameOf");
return hr;
}
STDMETHODIMP CConnectionFolder::MessageSFVCB(
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
TraceFileFunc(ttidShellFolder);
HRESULT hr = RealMessage(uMsg, wParam, lParam);
if (FAILED(hr))
{
switch (uMsg)
{
case DVM_INVOKECOMMAND:
if ((CMIDM_RENAME == wParam) && m_hwndMain && m_pShellView)
{
PCONFOLDPIDLVEC apidlSelected;
PCONFOLDPIDLVEC apidlCache;
hr = HrShellView_GetSelectedObjects(m_hwndMain, apidlSelected);
if (SUCCEEDED(hr))
{
// If there are objects, try to get the cached versions
if (!apidlSelected.empty())
{
hr = HrCloneRgIDL(apidlSelected, TRUE, TRUE, apidlCache);
}
}
if (SUCCEEDED(hr))
{
Assert(apidlCache.size() == 1);
if (apidlCache.size() == 1)
{
hr = m_pShellView->SelectItem(apidlCache[0].GetItemIdList(), SVSI_EDIT);
}
else
{
hr = E_INVALIDARG;
}
}
}
break;
case SFVM_HWNDMAIN:
// _hwndMain = (HWND)lParam;
hr = S_OK;
break;
}
}
return hr;
}
/*
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::GetOverlayIndex
//
// Purpose: Adds icon overlays to connections that need them
//
// Arguments:
// pidlItem [in] Pidl to item in question
// pIndex [out] Address of overlay index into system image list
//
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise.
//
// Author: kenwic 10 May 2000 created, support for sharing overlay
//
// Notes:
//
STDMETHODIMP CConnectionFolder::GetOverlayIndex(
LPCITEMIDLIST pidlItem,
int* pIndex)
{
TraceFileFunc(ttidShellFolder);
HRESULT hResult = E_FAIL;
*pIndex = -1;
// check to see if connection is sharing, and if so add sharing hand overlay
// i can't call HrNetConFromPidl, because it asserts if passed the wizard icon
PCONFOLDPIDL pcfpItem;
pcfpItem.InitializeFromItemIDList(pidlItem);
CONFOLDENTRY pConnectionFolderEntry;
hResult = pcfpItem.ConvertToConFoldEntry(pConnectionFolderEntry);
if(SUCCEEDED(hResult))
{
if(FALSE == pConnectionFolderEntry.GetWizard()) // sharing the wizard is not yet supported
{
if(NCCF_SHARED & pConnectionFolderEntry.GetCharacteristics())
{
*pIndex = SHGetIconOverlayIndex(NULL, IDO_SHGIOI_SHARE);
hResult = S_OK;
}
else
{
hResult = E_FAIL; // the docs for IShellIconOverlay are wrong, we must return failure to deny the icon
}
}
else
{
hResult = E_FAIL;
}
}
TraceHr(ttidShellFolder, FAL, hResult, TRUE, "CConnectionFolder::GetOverlayIndex");
return hResult;
}
//+---------------------------------------------------------------------------
//
// Member: CConnectionFolder::GetOverlayIconIndex
//
// Purpose: Adds icon overlays to connections that need them
//
// Arguments:
// pidlItem [in] Pidl to item in question
// pIconIndex [out] Address of index into system image list
//
//
// Returns: Returns NOERROR if successful or an OLE-defined error
// value otherwise.
//
// Author: kenwic 10 May 2000 created
//
// Notes:
//
STDMETHODIMP CConnectionFolder::GetOverlayIconIndex(
LPCITEMIDLIST pidlItem,
int* pIconIndex)
{
TraceFileFunc(ttidShellFolder);
*pIconIndex = -1;
HRESULT hResult = GetOverlayIndex(pidlItem, pIconIndex);
if(SUCCEEDED(hResult))
{
*pIconIndex = INDEXTOOVERLAYMASK(*pIconIndex);
}
TraceHr(ttidShellFolder, FAL, hResult, TRUE, "CConnectionFolder::GetOverlayIconIndex");
return hResult;
}*/