//+--------------------------------------------------------------------------- // // 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(ppenumIDList)); if (SUCCEEDED(hr)) { Assert(*ppenumIDList); // Call the PidlInitialize function to allow the enumeration // object to copy the list. // reinterpret_cast(*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(this); sfv.psfvcb = dynamic_cast(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(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 pDevCategoryProvider; hr = CoCreateInstance(CLSID_DefCategoryProvider, NULL, CLSCTX_ALL, IID_IDefCategoryProvider, reinterpret_cast(&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(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(ppvOut)); if (SUCCEEDED(hr)) { Assert(*ppvOut); } } else { hr = E_NOINTERFACE; } } else if (riid == IID_IDropTarget) { hr = E_NOINTERFACE; } else if (riid == IID_IQueryAssociations) { CComPtr pQueryAssociations; hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, reinterpret_cast(&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(ppvOut)); if (SUCCEEDED(hr)) { Assert(*ppvOut); reinterpret_cast (*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; }*/