1753 lines
46 KiB
C++
1753 lines
46 KiB
C++
//+---------------------------------------------------------------------------
|
||
//
|
||
// Microsoft Windows
|
||
// Copyright (C) Microsoft Corporation, 1997.
|
||
//
|
||
// File: I S H E L L F . C P P
|
||
//
|
||
// Contents: IShellFolder implementation for CUPnPDeviceFolder
|
||
// Implemention of CUPnPDeviceFoldPidl
|
||
//
|
||
// 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 <upscmn.h>
|
||
#include "tfind.h"
|
||
#include "clist.h"
|
||
#include "clistndn.h"
|
||
|
||
#include "tconst.h"
|
||
|
||
CUPnPDeviceFoldPidl::CUPnPDeviceFoldPidl()
|
||
{
|
||
// if these change, the UPNPUI_PIDL_HEADER structure
|
||
// above needs to change to be the right size
|
||
// Why we used 4 different types, I don't know...
|
||
Assert(2 == sizeof(WORD));
|
||
Assert(2 == sizeof(USHORT));
|
||
Assert(4 == sizeof(DWORD));
|
||
Assert(4 == sizeof(ULONG));
|
||
|
||
m_pszName = NULL;
|
||
m_pszUrl = NULL;
|
||
m_pszUdn = NULL;
|
||
m_pszType = NULL;
|
||
m_pszDesc = NULL;
|
||
}
|
||
|
||
|
||
CUPnPDeviceFoldPidl::~CUPnPDeviceFoldPidl()
|
||
{
|
||
if (m_pszName)
|
||
{
|
||
delete [] m_pszName;
|
||
}
|
||
|
||
if (m_pszUrl)
|
||
{
|
||
delete [] m_pszUrl;
|
||
}
|
||
|
||
if (m_pszUdn)
|
||
{
|
||
delete [] m_pszUdn;
|
||
}
|
||
|
||
if (m_pszType)
|
||
{
|
||
delete [] m_pszType;
|
||
}
|
||
|
||
if (m_pszDesc)
|
||
{
|
||
delete [] m_pszDesc;
|
||
}
|
||
}
|
||
|
||
|
||
HRESULT
|
||
CUPnPDeviceFoldPidl::HrInit(FolderDeviceNode * pDeviceNode)
|
||
{
|
||
Assert(!m_pszName);
|
||
Assert(!m_pszUrl);
|
||
Assert(!m_pszUdn);
|
||
Assert(!m_pszType);
|
||
Assert(!m_pszDesc);
|
||
|
||
Assert(pDeviceNode);
|
||
Assert(pDeviceNode->pszDisplayName);
|
||
Assert(pDeviceNode->pszPresentationURL);
|
||
Assert(pDeviceNode->pszUDN);
|
||
Assert(pDeviceNode->pszType);
|
||
|
||
HRESULT hr;
|
||
|
||
LPWSTR pszName;
|
||
LPWSTR pszUrl;
|
||
LPWSTR pszUdn;
|
||
LPWSTR pszType;
|
||
LPWSTR pszDesc;
|
||
|
||
ULONG cchName;
|
||
ULONG cchUrl;
|
||
ULONG cchUdn;
|
||
ULONG cchType;
|
||
ULONG cchDesc;
|
||
|
||
hr = E_OUTOFMEMORY;
|
||
|
||
pszName = NULL;
|
||
pszUrl = NULL;
|
||
pszUdn = NULL;
|
||
pszType = NULL;
|
||
pszDesc = NULL;
|
||
|
||
// Get the size of the name, and tack on a trailing NULL (since we now
|
||
// have something else in the buffer behind it.
|
||
//
|
||
cchName = lstrlenW(pDeviceNode->pszDisplayName);
|
||
pszName = new WCHAR [cchName + 1];
|
||
if (!pszName)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
cchUrl = lstrlenW(pDeviceNode->pszPresentationURL);
|
||
pszUrl = new WCHAR [cchUrl + 1];
|
||
if (!pszUrl)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
cchUdn = lstrlenW(pDeviceNode->pszUDN);
|
||
pszUdn = new WCHAR [cchUdn + 1];
|
||
if (!pszUdn)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
cchType = lstrlenW(pDeviceNode->pszType);
|
||
pszType = new WCHAR [cchType + 1];
|
||
if (!pszType)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
cchDesc = lstrlenW(pDeviceNode->pszDescription);
|
||
pszDesc = new WCHAR [cchDesc + 1];
|
||
if (!pszDesc)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
// everything that can fail has succeeded.
|
||
|
||
hr = S_OK;
|
||
|
||
// We don't need to check these since we know there's
|
||
// enough room.
|
||
wcscpy(pszName, pDeviceNode->pszDisplayName);
|
||
wcscpy(pszUrl, pDeviceNode->pszPresentationURL);
|
||
wcscpy(pszUdn, pDeviceNode->pszUDN);
|
||
wcscpy(pszType, pDeviceNode->pszType);
|
||
wcscpy(pszDesc, pDeviceNode->pszDescription);
|
||
|
||
m_pszName = pszName;
|
||
m_pszUrl = pszUrl;
|
||
m_pszUdn = pszUdn;
|
||
m_pszType = pszType;
|
||
m_pszDesc = pszDesc;
|
||
|
||
Cleanup:
|
||
if (FAILED(hr))
|
||
{
|
||
if (pszName)
|
||
{
|
||
delete [] pszName;
|
||
}
|
||
|
||
if (pszUrl)
|
||
{
|
||
delete [] pszUrl;
|
||
}
|
||
|
||
if (pszUdn)
|
||
{
|
||
delete [] pszUdn;
|
||
}
|
||
|
||
if (pszType)
|
||
{
|
||
delete [] pszType;
|
||
}
|
||
|
||
if (pszDesc)
|
||
{
|
||
delete [] pszDesc;
|
||
}
|
||
}
|
||
|
||
Assert(FImplies(SUCCEEDED(hr), pszName));
|
||
Assert(FImplies(SUCCEEDED(hr), pszUrl));
|
||
Assert(FImplies(SUCCEEDED(hr), pszUdn));
|
||
Assert(FImplies(SUCCEEDED(hr), pszType));
|
||
Assert(FImplies(SUCCEEDED(hr), pszDesc));
|
||
|
||
return hr;
|
||
}
|
||
|
||
|
||
HRESULT
|
||
HrCopyUnalignedBytesToNewString(BYTE * pByteData,
|
||
ULONG cbData,
|
||
LPWSTR * ppszResult)
|
||
{
|
||
Assert(ppszResult);
|
||
|
||
HRESULT hr;
|
||
LPWSTR pszResult;
|
||
ULONG cchMax;
|
||
|
||
hr = S_OK;
|
||
pszResult = NULL;
|
||
|
||
{
|
||
BOOL fInvalid;
|
||
|
||
fInvalid = IsBadReadPtr(pByteData, cbData);
|
||
if (fInvalid)
|
||
{
|
||
hr = E_POINTER;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
if (!cbData || cbData % sizeof(WCHAR))
|
||
{
|
||
hr = E_INVALIDARG;
|
||
goto Cleanup;
|
||
}
|
||
|
||
cchMax = (cbData / sizeof(WCHAR)) - 1;
|
||
pszResult = new WCHAR [ cchMax + 1 ];
|
||
if (!pszResult)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
::CopyMemory(pszResult, pByteData, cbData);
|
||
|
||
// make sure that the data is null-terminated.
|
||
pszResult[cchMax] = UNICODE_NULL;
|
||
|
||
Cleanup:
|
||
if (FAILED(hr))
|
||
{
|
||
if (pszResult)
|
||
{
|
||
delete [] pszResult;
|
||
pszResult = NULL;
|
||
}
|
||
}
|
||
|
||
*ppszResult = pszResult;
|
||
|
||
TraceError("HrCopyUnalignedBytesToNewString", hr);
|
||
return hr;
|
||
}
|
||
|
||
|
||
HRESULT
|
||
CUPnPDeviceFoldPidl::HrInit(PUPNPDEVICEFOLDPIDL pidl)
|
||
{
|
||
Assert(!m_pszName);
|
||
Assert(!m_pszUrl);
|
||
Assert(!m_pszUdn);
|
||
Assert(!m_pszType);
|
||
Assert(!m_pszDesc);
|
||
|
||
HRESULT hr;
|
||
UNALIGNED UPNPUI_PIDL_HEADER * puph;
|
||
|
||
LPWSTR pszName;
|
||
LPWSTR pszUrl;
|
||
LPWSTR pszUdn;
|
||
LPWSTR pszType;
|
||
LPWSTR pszDesc;
|
||
|
||
hr = S_OK;
|
||
puph = (UPNPUI_PIDL_HEADER *) pidl;
|
||
|
||
pszName = NULL;
|
||
pszUrl = NULL;
|
||
pszUdn = NULL;
|
||
pszType = NULL;
|
||
pszDesc = NULL;
|
||
|
||
{
|
||
BOOL fInvalid;
|
||
|
||
fInvalid = IsBadReadPtr(pidl, sizeof(UPNPUI_PIDL_HEADER));
|
||
if (fInvalid)
|
||
{
|
||
hr = E_POINTER;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
// minimal version checking should have happened already,
|
||
// so we just assert that everything is ok here
|
||
//
|
||
Assert(UPNPDEVICEFOLDPIDL_LEADID == puph->uLeadId);
|
||
Assert(UPNPDEVICEFOLDPIDL_TRAILID == puph->uTrailId);
|
||
|
||
{
|
||
BYTE * pbString;
|
||
ULONG ulOffset;
|
||
ULONG cb;
|
||
|
||
pbString = (BYTE *)pidl;
|
||
ulOffset = puph->ulNameOffset;
|
||
ulOffset += sizeof(UPNPUI_PIDL_HEADER);
|
||
cb = puph->cbName;
|
||
|
||
pbString += ulOffset;
|
||
|
||
hr = HrCopyUnalignedBytesToNewString(pbString,
|
||
cb,
|
||
&pszName);
|
||
if (FAILED(hr))
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
{
|
||
BYTE * pbString;
|
||
ULONG ulOffset;
|
||
ULONG cb;
|
||
|
||
pbString = (BYTE *)pidl;
|
||
ulOffset = puph->ulUrlOffset;
|
||
ulOffset += sizeof(UPNPUI_PIDL_HEADER);
|
||
cb = puph->cbUrl;
|
||
|
||
pbString += ulOffset;
|
||
|
||
hr = HrCopyUnalignedBytesToNewString(pbString,
|
||
cb,
|
||
&pszUrl);
|
||
if (FAILED(hr))
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
{
|
||
BYTE * pbString;
|
||
ULONG ulOffset;
|
||
ULONG cb;
|
||
|
||
pbString = (BYTE *)pidl;
|
||
ulOffset = puph->ulUdnOffset;
|
||
ulOffset += sizeof(UPNPUI_PIDL_HEADER);
|
||
cb = puph->cbUdn;
|
||
|
||
pbString += ulOffset;
|
||
|
||
hr = HrCopyUnalignedBytesToNewString(pbString,
|
||
cb,
|
||
&pszUdn);
|
||
if (FAILED(hr))
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
{
|
||
BYTE * pbString;
|
||
ULONG ulOffset;
|
||
ULONG cb;
|
||
|
||
pbString = (BYTE *)pidl;
|
||
ulOffset = puph->ulTypeOffset;
|
||
ulOffset += sizeof(UPNPUI_PIDL_HEADER);
|
||
cb = puph->cbType;
|
||
|
||
pbString += ulOffset;
|
||
|
||
hr = HrCopyUnalignedBytesToNewString(pbString,
|
||
cb,
|
||
&pszType);
|
||
if (FAILED(hr))
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
{
|
||
BYTE * pbString;
|
||
ULONG ulOffset;
|
||
ULONG cb;
|
||
|
||
pbString = (BYTE *)pidl;
|
||
ulOffset = puph->ulDescOffset;
|
||
ulOffset += sizeof(UPNPUI_PIDL_HEADER);
|
||
cb = puph->cbDesc;
|
||
|
||
pbString += ulOffset;
|
||
|
||
hr = HrCopyUnalignedBytesToNewString(pbString,
|
||
cb,
|
||
&pszDesc);
|
||
if (FAILED(hr))
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
m_pszName = pszName;
|
||
m_pszUrl = pszUrl;
|
||
m_pszUdn = pszUdn;
|
||
m_pszType = pszType;
|
||
m_pszDesc = pszDesc;
|
||
|
||
Cleanup:
|
||
if (FAILED(hr))
|
||
{
|
||
if (pszName)
|
||
{
|
||
delete [] pszName;
|
||
}
|
||
|
||
if (pszUrl)
|
||
{
|
||
delete [] pszUrl;
|
||
}
|
||
|
||
if (pszUdn)
|
||
{
|
||
delete [] pszUdn;
|
||
}
|
||
|
||
if (pszType)
|
||
{
|
||
delete [] pszType;
|
||
}
|
||
|
||
if (pszDesc)
|
||
{
|
||
delete [] pszDesc;
|
||
}
|
||
}
|
||
|
||
Assert(FImplies(SUCCEEDED(hr), pszName));
|
||
Assert(FImplies(SUCCEEDED(hr), pszUrl));
|
||
Assert(FImplies(SUCCEEDED(hr), pszUdn));
|
||
Assert(FImplies(SUCCEEDED(hr), pszType));
|
||
Assert(FImplies(SUCCEEDED(hr), pszDesc));
|
||
|
||
TraceError("CUPnPDeviceFoldPidl::HrInit", hr);
|
||
return hr;
|
||
}
|
||
|
||
|
||
HRESULT
|
||
CUPnPDeviceFoldPidl::HrPersist(IMalloc * pMalloc, LPITEMIDLIST * ppidl)
|
||
{
|
||
Assert(m_pszName);
|
||
Assert(m_pszUrl);
|
||
Assert(m_pszUdn);
|
||
Assert(m_pszType);
|
||
Assert(m_pszDesc);
|
||
Assert(pMalloc);
|
||
Assert(ppidl);
|
||
|
||
HRESULT hr;
|
||
|
||
ULONG cbTotalPidlSize;
|
||
ULONG cbName;
|
||
ULONG cbUrl;
|
||
ULONG cbUdn;
|
||
ULONG cbType;
|
||
ULONG cbDesc;
|
||
|
||
ULONG ulNameOffset;
|
||
ULONG ulUrlOffset;
|
||
ULONG ulUdnOffset;
|
||
ULONG ulTypeOffset;
|
||
ULONG ulDescOffset;
|
||
|
||
UNALIGNED UPNPUI_PIDL_HEADER * puph;
|
||
LPBYTE pbData;
|
||
|
||
hr = S_OK;
|
||
|
||
pbData = NULL;
|
||
|
||
cbName = wcslen(m_pszName);
|
||
cbName = (cbName + 1) * sizeof(WCHAR);
|
||
|
||
cbUrl = wcslen(m_pszUrl);
|
||
cbUrl = (cbUrl + 1) * sizeof(WCHAR);
|
||
|
||
cbUdn = wcslen(m_pszUdn);
|
||
cbUdn = (cbUdn + 1) * sizeof(WCHAR);
|
||
|
||
cbType = wcslen(m_pszType);
|
||
cbType = (cbType + 1) * sizeof(WCHAR);
|
||
|
||
cbDesc = wcslen(m_pszDesc);
|
||
cbDesc = (cbDesc + 1) * sizeof(WCHAR);
|
||
|
||
ulNameOffset = 0;
|
||
ulUrlOffset = ulNameOffset + cbName;
|
||
ulUdnOffset = ulUrlOffset + cbUrl;
|
||
ulTypeOffset = ulUdnOffset + cbUdn;
|
||
ulDescOffset = ulTypeOffset + cbType;
|
||
|
||
cbTotalPidlSize = sizeof(UPNPUI_PIDL_HEADER);
|
||
cbTotalPidlSize += cbName;
|
||
cbTotalPidlSize += cbUrl;
|
||
cbTotalPidlSize += cbUdn;
|
||
cbTotalPidlSize += cbType;
|
||
cbTotalPidlSize += cbDesc;
|
||
|
||
// don't count the PIDL-terminating bytes in the size
|
||
//
|
||
pbData = (BYTE *) pMalloc->Alloc(cbTotalPidlSize +
|
||
FIELD_OFFSET(ITEMIDLIST, mkid.cb) + sizeof(USHORT));
|
||
if (!pbData)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
|
||
TraceError("CUPnPDeviceFoldPidl::HrPersist: Alloc()", hr);
|
||
goto Cleanup;
|
||
}
|
||
|
||
// delegate folder alert: since we're a delete folder, the Alloc() above
|
||
// doesn't just allocate the bytes we asked for, but rather a bunch for our
|
||
// delegate folder prefix, then the bytes we asked for. We need to skip
|
||
// the prefix bytes and just write to our own.
|
||
puph = (UPNPUI_PIDL_HEADER *)ConvertToUPnPDevicePIDL((ITEMIDLIST*)pbData);
|
||
|
||
puph->iCB = cbTotalPidlSize;
|
||
puph->uLeadId = UPNPDEVICEFOLDPIDL_LEADID;
|
||
puph->dwVersion = UP_DEVICE_FOLDER_IDL_VERSION;
|
||
puph->uTrailId = UPNPDEVICEFOLDPIDL_TRAILID;
|
||
puph->uVOID = 0;
|
||
puph->dwCharacteristics = 0;
|
||
|
||
puph->ulNameOffset = ulNameOffset;
|
||
puph->cbName = cbName;
|
||
puph->ulUrlOffset = ulUrlOffset;
|
||
puph->cbUrl = cbUrl;
|
||
puph->ulUdnOffset = ulUdnOffset;
|
||
puph->cbUdn = cbUdn;
|
||
puph->ulTypeOffset = ulTypeOffset;
|
||
puph->cbType = cbType;
|
||
puph->ulDescOffset = ulDescOffset;
|
||
puph->cbDesc = cbDesc;
|
||
|
||
{
|
||
LPBYTE pbDynamicField;
|
||
LPBYTE pbName;
|
||
LPBYTE pbUrl;
|
||
LPBYTE pbUdn;
|
||
LPBYTE pbType;
|
||
LPBYTE pbDesc;
|
||
|
||
// note: this has to be puph (not pbData) because we still
|
||
// have to skip the "delegate folder prefix" junk.
|
||
pbDynamicField = ((BYTE *)puph) + sizeof(UPNPUI_PIDL_HEADER);
|
||
pbName = pbDynamicField + ulNameOffset;
|
||
pbUrl = pbDynamicField + ulUrlOffset;
|
||
pbUdn = pbDynamicField + ulUdnOffset;
|
||
pbType = pbDynamicField + ulTypeOffset;
|
||
pbDesc = pbDynamicField + ulDescOffset;
|
||
|
||
::CopyMemory(pbName, m_pszName, cbName);
|
||
::CopyMemory(pbUrl, m_pszUrl, cbUrl);
|
||
::CopyMemory(pbUdn, m_pszUdn, cbUdn);
|
||
::CopyMemory(pbType, m_pszType, cbType);
|
||
::CopyMemory(pbDesc, m_pszDesc, cbDesc);
|
||
}
|
||
|
||
{
|
||
// terminate the PIDL
|
||
LPITEMIDLIST pidlNext;
|
||
|
||
pidlNext = ILNext((LPITEMIDLIST)puph);
|
||
|
||
Assert((FIELD_OFFSET(ITEMIDLIST, mkid.cb) +
|
||
sizeof(pidlNext->mkid.cb)) == sizeof(USHORT));
|
||
pidlNext->mkid.cb = 0;
|
||
}
|
||
|
||
Cleanup:
|
||
Assert(FImplies(FAILED(hr), !pbData));
|
||
Assert(FImplies(SUCCEEDED(hr), pbData));
|
||
|
||
*ppidl = (LPITEMIDLIST)pbData;
|
||
|
||
TraceError("CUPnPDeviceFoldPidl::HrPersist", hr);
|
||
return hr;
|
||
}
|
||
|
||
|
||
PCWSTR
|
||
CUPnPDeviceFoldPidl::PszGetNamePointer() const
|
||
{
|
||
return m_pszName;
|
||
}
|
||
|
||
|
||
PCWSTR
|
||
CUPnPDeviceFoldPidl::PszGetURLPointer() const
|
||
{
|
||
return m_pszUrl;
|
||
}
|
||
|
||
|
||
PCWSTR
|
||
CUPnPDeviceFoldPidl::PszGetUDNPointer() const
|
||
{
|
||
return m_pszUdn;
|
||
}
|
||
|
||
|
||
PCWSTR
|
||
CUPnPDeviceFoldPidl::PszGetTypePointer() const
|
||
{
|
||
return m_pszType;
|
||
}
|
||
|
||
|
||
PCWSTR
|
||
CUPnPDeviceFoldPidl::PszGetDescriptionPointer() const
|
||
{
|
||
return m_pszDesc;
|
||
}
|
||
|
||
HRESULT CUPnPDeviceFoldPidl::HrSetName(PCWSTR szName)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
if (szName)
|
||
{
|
||
// Free old name
|
||
delete [] m_pszName;
|
||
|
||
// Copy in new name
|
||
m_pszName = WszDupWsz(szName);
|
||
if (!m_pszName)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
|
||
TraceError("CUPnPDeviceFoldPidl::HrSetName", hr);
|
||
return hr;
|
||
}
|
||
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::HrMakeUPnPDevicePidl
|
||
//
|
||
// Purpose: Private function of the folder object that constructs the
|
||
// UPNP device pidl using the delegated allocator
|
||
//
|
||
// Arguments:
|
||
// FolderDeviceNode [in] Structure that contains all the
|
||
// strings we need for the pidl
|
||
// ppidl [out] The result pidl
|
||
//
|
||
// Returns: Returns NOERROR if successful or an OLE-defined error
|
||
// value otherwise
|
||
//
|
||
// Author: tongl 15 Feb 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
|
||
HRESULT CUPnPDeviceFolder::HrMakeUPnPDevicePidl(FolderDeviceNode * pDeviceNode,
|
||
LPITEMIDLIST * ppidl)
|
||
{
|
||
HRESULT hr;
|
||
CUPnPDeviceFoldPidl udfp;
|
||
|
||
hr = udfp.HrInit(pDeviceNode);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = udfp.HrPersist(m_pDelegateMalloc, ppidl);
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT CUPnPDeviceFolder::HrMakeUPnPDevicePidl(IUPnPDevice * pDevice,
|
||
LPITEMIDLIST * ppidl)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
Assert(pDevice);
|
||
|
||
BSTR bstrUDN = NULL;
|
||
BSTR bstrDisplayName = NULL;
|
||
BSTR bstrType = NULL;
|
||
BSTR bstrPresentationURL = NULL;
|
||
BSTR bstrDescription = NULL;
|
||
|
||
Assert(pDevice);
|
||
pDevice->AddRef();
|
||
|
||
hr = pDevice->get_UniqueDeviceName(&bstrUDN);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pDevice->get_FriendlyName(&bstrDisplayName);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pDevice->get_Type(&bstrType);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pDevice->get_PresentationURL(&bstrPresentationURL);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = pDevice->get_Description(&bstrDescription);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
FolderDeviceNode * pDevNode = new FolderDeviceNode;
|
||
if (pDevNode)
|
||
{
|
||
// the buffers in FolderDeviceNode are MAX_PATH
|
||
// wide, so we can only copy MAX_PATH - 1 chars
|
||
// and still have room for the terminating null
|
||
//
|
||
CONST SIZE_T cchMax = MAX_PATH - 1;
|
||
|
||
Assert(bstrUDN);
|
||
wcscpy(pDevNode->pszUDN, L"");
|
||
wcsncat(pDevNode->pszUDN,(PWSTR)bstrUDN,cchMax);
|
||
|
||
Assert(bstrDisplayName);
|
||
wcscpy(pDevNode->pszDisplayName, L"");
|
||
wcsncat(pDevNode->pszDisplayName,(PWSTR)bstrDisplayName,cchMax);
|
||
|
||
Assert(bstrType);
|
||
wcscpy(pDevNode->pszType, L"");
|
||
wcsncat(pDevNode->pszType,(PWSTR)bstrType,cchMax);
|
||
|
||
wcscpy(pDevNode->pszPresentationURL, L"");
|
||
if (bstrPresentationURL)
|
||
{
|
||
wcsncat(pDevNode->pszPresentationURL,
|
||
(PWSTR)bstrPresentationURL,
|
||
cchMax);
|
||
}
|
||
|
||
wcscpy(pDevNode->pszDescription, L"");
|
||
if (bstrDescription)
|
||
{
|
||
wcsncat(pDevNode->pszDescription,
|
||
(PWSTR)bstrDescription,
|
||
cchMax);
|
||
}
|
||
|
||
hr = HrMakeUPnPDevicePidl(pDevNode, ppidl);
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TraceTag(ttidShellFolder, "Failed in pDevice->get_Description from HrMakeUPnPDevicePidl");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TraceTag(ttidShellFolder, "Failed in pDevice->get_PresentationURL from HrMakeUPnPDevicePidl");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TraceTag(ttidShellFolder, "Failed in pDevice->get_Type from HrMakeUPnPDevicePidl");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TraceTag(ttidShellFolder, "Failed in pDevice->get_FriendlyName from HrMakeUPnPDevicePidl");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TraceTag(ttidShellFolder, "Failed in pDevice->get_UniqueDeviceName from HrMakeUPnPDevicePidl");
|
||
}
|
||
|
||
SysFreeString(bstrUDN);
|
||
SysFreeString(bstrDisplayName);
|
||
SysFreeString(bstrPresentationURL);
|
||
SysFreeString(bstrType);
|
||
SysFreeString(bstrDescription);
|
||
|
||
ReleaseObj(pDevice);
|
||
|
||
TraceError("CUPnPDeviceFolder::HrMakeUPnPDevicePidl", hr);
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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: tongl 16 Feb 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
STDMETHODIMP CUPnPDeviceFolder::ParseDisplayName(
|
||
HWND hwndOwner,
|
||
LPBC pbcReserved,
|
||
LPOLESTR lpszDisplayName,
|
||
ULONG * pchEaten,
|
||
LPITEMIDLIST * ppidl,
|
||
ULONG * pdwAttributes)
|
||
{
|
||
TraceTag(ttidShellFolderIface, "CUPnPDeviceFolder::ParseDisplayName");
|
||
|
||
HRESULT hr = S_OK;
|
||
|
||
// note: this is bogus, but we're doing this all over...
|
||
Assert(lpszDisplayName);
|
||
Assert(ppidl);
|
||
*ppidl = NULL;
|
||
|
||
// first, make sure that this is one of our display names:
|
||
// it must start with c_szDelegateFolderPrefix
|
||
//
|
||
int result;
|
||
|
||
result = wcsncmp(lpszDisplayName,
|
||
c_szDelegateFolderPrefix,
|
||
c_cchDelegateFolderPrefix);
|
||
if (0 == result)
|
||
{
|
||
LPCWSTR pszUdn = NULL;
|
||
LPITEMIDLIST pidlDevice = NULL;
|
||
FolderDeviceNode * pDeviceNode = NULL;
|
||
|
||
// this is OK since lpszDisplayName is an LPOLESTR
|
||
pszUdn = lpszDisplayName + c_cchDelegateFolderPrefix;
|
||
|
||
// search our list of devices and try to find a matching UDN
|
||
if (g_CListFolderDeviceNode.FFind(pszUdn, &pDeviceNode))
|
||
{
|
||
Assert(pDeviceNode);
|
||
|
||
// yes, this is one of our devices, construct the pidl using
|
||
// the allocator we are given
|
||
hr = HrMakeUPnPDevicePidl(pDeviceNode, &pidlDevice);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
Assert(pidlDevice);
|
||
*ppidl = pidlDevice;
|
||
|
||
if (pdwAttributes)
|
||
{
|
||
*pdwAttributes = 0;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// no, we don't have such a device in the list
|
||
|
||
// (tongl): try to do a SearchByUDN before we fail the call,
|
||
// as this may be a device discovered by the search from the
|
||
// tray icon, and we are asked for the pidl to create a shortcut.
|
||
|
||
BSTR bstrUdn = NULL;
|
||
IUPnPDeviceFinder * pdf = NULL;
|
||
|
||
bstrUdn = ::SysAllocString(pszUdn);
|
||
if (bstrUdn)
|
||
{
|
||
hr = CoCreateInstance(CLSID_UPnPDeviceFinder, NULL, CLSCTX_INPROC_SERVER,
|
||
IID_IUPnPDeviceFinder, (LPVOID *)&pdf);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
IUPnPDevice * pdev = NULL;
|
||
|
||
hr = pdf->FindByUDN(bstrUdn, &pdev);
|
||
if (S_OK == hr)
|
||
{
|
||
hr = HrMakeUPnPDevicePidl(pdev, &pidlDevice);
|
||
ReleaseObj(pdev);
|
||
}
|
||
ReleaseObj(pdf);
|
||
}
|
||
|
||
::SysFreeString(bstrUdn);
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
TraceError("CUPnPDeviceFolder::ParseDisplayName: "
|
||
"SysAllocString", hr);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TraceTag(ttidShellFolderIface,
|
||
"CUPnPDeviceFolder::ParseDisplayName: "
|
||
"passed non-upnp display name");
|
||
hr = E_FAIL;
|
||
}
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "CUPnPDeviceFolder::ParseDisplayName");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::EnumObjects(
|
||
HWND hwndOwner,
|
||
DWORD grfFlags,
|
||
LPENUMIDLIST * ppenumIDList)
|
||
{
|
||
HRESULT hr = NOERROR;
|
||
|
||
Assert(ppenumIDList);
|
||
*ppenumIDList = NULL;
|
||
|
||
if ((grfFlags & SHCONTF_FOLDERS) && !(grfFlags & SHCONTF_NONFOLDERS))
|
||
{
|
||
// if shell wants to enumerate only folders, we don't return anything
|
||
hr = E_NOTIMPL;
|
||
}
|
||
else
|
||
{
|
||
// Create the IEnumIDList object (CUPnPDeviceFolderEnum)
|
||
//
|
||
hr = CUPnPDeviceFolderEnum::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<CUPnPDeviceFolderEnum *>(*ppenumIDList)->Initialize(
|
||
m_pidlFolderRoot, this);
|
||
}
|
||
else
|
||
{
|
||
// On all failures, this should be NULL.
|
||
if (*ppenumIDList)
|
||
{
|
||
ReleaseObj(*ppenumIDList);
|
||
}
|
||
|
||
*ppenumIDList = NULL;
|
||
}
|
||
}
|
||
|
||
TraceHr(ttidError, FAL, hr, FALSE, "CUPnPDeviceFolder::EnumObjects");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::BindToObject(
|
||
LPCITEMIDLIST pidl,
|
||
LPBC pbcReserved,
|
||
REFIID riid,
|
||
LPVOID * ppvOut)
|
||
{
|
||
HRESULT hr = E_NOTIMPL;
|
||
|
||
// Note - If we add code here, then we ought to param check pidl
|
||
//
|
||
Assert(pidl);
|
||
|
||
*ppvOut = NULL;
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "CUPnPDeviceFolder::BindToObject");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::BindToStorage
|
||
//
|
||
// Purpose: Reserved for a future use. This method should
|
||
// return E_NOTIMPL.
|
||
//
|
||
// Arguments:
|
||
// pidl [] Pointer to an ITEMIDLIST
|
||
// pbcReserved [] Reserved<65>specify NULL
|
||
// riid [] Interface to return
|
||
// ppvObj [] Address that receives interface pointer);
|
||
//
|
||
// Returns: E_NOTIMPL always
|
||
//
|
||
// Author: jeffspr 18 Oct 1997
|
||
//
|
||
// Notes:
|
||
//
|
||
STDMETHODIMP CUPnPDeviceFolder::BindToStorage(
|
||
LPCITEMIDLIST pidl,
|
||
LPBC pbcReserved,
|
||
REFIID riid,
|
||
LPVOID * ppvObj)
|
||
{
|
||
HRESULT hr = E_NOTIMPL;
|
||
|
||
// Note - If we add code here, then we ought to param check pidl
|
||
//
|
||
Assert(pidl);
|
||
|
||
*ppvObj = NULL;
|
||
|
||
TraceHr(ttidShellFolder, FAL, hr, FALSE, "CUPnPDeviceFolder::BindToStorage");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::CompareIDs(
|
||
LPARAM lParam,
|
||
LPCITEMIDLIST pidl1,
|
||
LPCITEMIDLIST pidl2)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
PUPNPDEVICEFOLDPIDL pupdfp1 = NULL;
|
||
PUPNPDEVICEFOLDPIDL pupdfp2 = NULL;
|
||
CUPnPDeviceFoldPidl udfp1;
|
||
CUPnPDeviceFoldPidl udfp2;
|
||
LPCWSTR psz1;
|
||
LPCWSTR psz2;
|
||
CONST INT ciTieBreaker = -1;
|
||
int iCompare = 0;
|
||
int result;
|
||
|
||
TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::CompareIDs");
|
||
|
||
// Make sure that the pidls passed in are our pidls.
|
||
//
|
||
if (!FIsUPnPDeviceFoldPidl(pidl1) || !FIsUPnPDeviceFoldPidl(pidl2))
|
||
{
|
||
hr = E_INVALIDARG;
|
||
goto Exit;
|
||
}
|
||
|
||
pupdfp1 = ConvertToUPnPDevicePIDL(pidl1);
|
||
pupdfp2 = ConvertToUPnPDevicePIDL(pidl2);
|
||
|
||
hr = udfp1.HrInit(pupdfp1);
|
||
if (FAILED(hr))
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
hr = udfp2.HrInit(pupdfp2);
|
||
if (FAILED(hr))
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
// We use the following procedure to compare PIDLs:
|
||
// 1. If two UDNs are the same, the PIDLs are the same
|
||
// 2. Otherwise, the PIDLs _must_ be different, and
|
||
// A. will be sorted based on the desired column
|
||
// B. If the column text matches, we'll return
|
||
// ciTieBreaker (-1), so that the PIDLs are
|
||
// distinguished.
|
||
//
|
||
|
||
psz1 = udfp1.PszGetUDNPointer();
|
||
psz2 = udfp2.PszGetUDNPointer();
|
||
Assert(psz1 && psz2);
|
||
result = wcscmp(psz1, psz2);
|
||
if (0 == result)
|
||
{
|
||
// The UDNs match, these are effectively the same PIDL
|
||
TraceTag(ttidShellFolder, "CUPnPDeviceFolder::CompareIDs: "
|
||
"UDN equal, automatically returning equality");
|
||
|
||
iCompare = 0;
|
||
}
|
||
else
|
||
{
|
||
// Sort based on the desired column
|
||
|
||
switch(lParam & SHCIDS_COLUMNMASK)
|
||
{
|
||
case ICOL_NAME:
|
||
psz1 = udfp1.PszGetNamePointer();
|
||
psz2 = udfp2.PszGetNamePointer();
|
||
break;
|
||
|
||
case ICOL_URL:
|
||
psz1 = udfp1.PszGetURLPointer();
|
||
psz2 = udfp2.PszGetURLPointer();
|
||
break;
|
||
|
||
case ICOL_UDN:
|
||
psz1 = udfp1.PszGetUDNPointer();
|
||
psz2 = udfp2.PszGetUDNPointer();
|
||
break;
|
||
|
||
case ICOL_TYPE:
|
||
psz1 = udfp1.PszGetTypePointer();
|
||
psz2 = udfp2.PszGetTypePointer();
|
||
break;
|
||
|
||
default:
|
||
AssertSz(FALSE, "Sorting on unknown category");
|
||
break;
|
||
}
|
||
|
||
Assert(psz1 && psz2);
|
||
iCompare = _wcsicmp(psz1, psz2);
|
||
|
||
// Ensure that we don't return equality
|
||
if (0 == iCompare)
|
||
{
|
||
TraceTag(ttidShellFolder, "CUPnPDeviceFolder::CompareIDs: "
|
||
"UDNs unequal but column-text equal, breaking tie");
|
||
|
||
iCompare = ciTieBreaker;
|
||
}
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = ResultFromShort(iCompare);
|
||
}
|
||
|
||
TraceTag(ttidShellFolder, "CUPnPDeviceFolder::CompareIDs: returning %d", iCompare);
|
||
Exit:
|
||
|
||
TraceHr(ttidError, FAL, hr, SUCCEEDED(hr), "CUPnPDeviceFolder::CompareIDs");
|
||
return hr;
|
||
}
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::CreateViewObject(
|
||
HWND hwndOwner,
|
||
REFIID riid,
|
||
LPVOID * ppvOut)
|
||
{
|
||
HRESULT hr = E_NOINTERFACE;
|
||
|
||
TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::CreateViewObject");
|
||
|
||
Assert(ppvOut);
|
||
|
||
// Pre-initialize the out param, per OLE guidelines
|
||
//
|
||
*ppvOut = NULL;
|
||
|
||
// (tongl) We are a delegate folder now, CreateViewObject is never called.
|
||
return E_NOTIMPL;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::GetAttributesOf(
|
||
UINT cidl,
|
||
LPCITEMIDLIST * apidl,
|
||
ULONG * rgfInOut)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
ULONG rgfMask = 0;
|
||
PUPNPDEVICEFOLDPIDL pupdfp = NULL;
|
||
|
||
TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::GetAttributesOf");
|
||
|
||
if (cidl > 0)
|
||
{
|
||
// Prepopulate with all values (removed CANCOPY and CANMOVE)
|
||
//
|
||
rgfMask = /* SFGAO_CANDELETE | */ // Don't support delete
|
||
SFGAO_CANRENAME |
|
||
SFGAO_CANLINK |
|
||
SFGAO_HASPROPSHEET;
|
||
|
||
// Disable propsheets for > 1 object
|
||
//
|
||
if (cidl > 1)
|
||
{
|
||
rgfMask &= ~SFGAO_HASPROPSHEET;
|
||
}
|
||
}
|
||
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;
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
*rgfInOut &= rgfMask;
|
||
}
|
||
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::GetUIObjectOf(
|
||
HWND hwndOwner,
|
||
UINT cidl,
|
||
LPCITEMIDLIST * apidl,
|
||
REFIID riid,
|
||
UINT * prgfInOut,
|
||
LPVOID * ppvOut)
|
||
{
|
||
HRESULT hr = E_NOINTERFACE;
|
||
|
||
TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::GetUIObjectOf");
|
||
|
||
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;
|
||
Assert(m_pidlFolderRoot);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
Assert(m_pidlFolderRoot);
|
||
|
||
// Internal IDataObject impl removed. Replaced with common
|
||
// shell code.
|
||
//
|
||
hr = CIDLData_CreateFromIDArray(m_pidlFolderRoot, cidl, apidl, (IDataObject **) ppvOut);
|
||
}
|
||
}
|
||
else if (riid == IID_IContextMenu)
|
||
{
|
||
// Create our context menu object if only one device is selected
|
||
//
|
||
|
||
hr = CUPnPDeviceFolderContextMenu::CreateInstance (
|
||
IID_IContextMenu,
|
||
reinterpret_cast<void**>(ppvOut),
|
||
CMT_OBJECT,
|
||
hwndOwner,
|
||
cidl,
|
||
apidl,
|
||
this);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
Assert(*ppvOut);
|
||
}
|
||
else
|
||
{
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
}
|
||
else if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
|
||
{
|
||
if (cidl == 1)
|
||
{
|
||
hr = CUPnPDeviceFolderExtractIcon::CreateInstance (
|
||
apidl[0],
|
||
riid,
|
||
reinterpret_cast<void**>(ppvOut));
|
||
if(SUCCEEDED(hr))
|
||
{
|
||
hr = reinterpret_cast<CUPnPDeviceFolderExtractIcon *>
|
||
(*ppvOut)->Initialize((LPITEMIDLIST)apidl[0]);
|
||
}
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
Assert(*ppvOut);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
}
|
||
else if (riid == IID_IDropTarget)
|
||
{
|
||
// We don't support drag/drop
|
||
//
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
else if (riid == IID_IQueryInfo)
|
||
{
|
||
if (cidl == 1)
|
||
{
|
||
// Create the IQueryInfo interface
|
||
hr = CUPnPDeviceFolderQueryInfo::CreateInstance (
|
||
IID_IQueryInfo,
|
||
reinterpret_cast<void**>(ppvOut));
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
Assert(*ppvOut);
|
||
|
||
reinterpret_cast<CUPnPDeviceFolderQueryInfo *>
|
||
(*ppvOut)->PidlInitialize((LPITEMIDLIST)apidl[0]);
|
||
|
||
// Normalize return code
|
||
//
|
||
hr = NOERROR;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
AssertSz(FALSE, "GetUIObjectOf asked for query info for more than one item!");
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TraceTag(ttidShellFolder, "CUPnPDeviceFolder::GetUIObjectOf asked for object "
|
||
"that it didn't know how to create. 0x%08x", riid.Data1);
|
||
|
||
hr = E_NOINTERFACE;
|
||
}
|
||
}
|
||
|
||
if (FAILED(hr))
|
||
{
|
||
*ppvOut = NULL;
|
||
}
|
||
|
||
TraceHr(ttidError, FAL, hr, (hr == E_NOINTERFACE), "CUPnPDeviceFolder::GetUIObjectOf");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Function: HrTszToStrRet
|
||
//
|
||
// Purpose: Convert a TCHAR string to a STRRET, depending on the platform
|
||
//
|
||
// Arguments:
|
||
// pszName [in] input string
|
||
// pStrRet [in/out] output STRRET
|
||
//
|
||
// Returns:
|
||
//
|
||
// Author: jeffspr 25 Jan 2000
|
||
//
|
||
// Notes:
|
||
//
|
||
HRESULT HrTszToStrRet(LPCTSTR pszName, STRRET *pStrRet)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
|
||
#ifdef UNICODE
|
||
pStrRet->uType = STRRET_WSTR;
|
||
|
||
// Allocate a new POLESTR block, which the shell can then free,
|
||
// and copy the displayable portion to it.
|
||
//
|
||
hr = HrDupeShellString(
|
||
pszName,
|
||
&pStrRet->pOleStr);
|
||
#else
|
||
pStrRet->uType = STRRET_CSTR;
|
||
lstrcpyn(pStrRet->cStr, pszName, celems(pStrRet->cStr));
|
||
hr = S_OK;
|
||
#endif
|
||
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::GetDisplayNameOf(
|
||
LPCITEMIDLIST pidl,
|
||
DWORD uFlags,
|
||
LPSTRRET lpName)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
PCWSTR pwszStrToCopy = NULL;
|
||
PTSTR pszTemp = NULL;
|
||
PUPNPDEVICEFOLDPIDL pupdfp = NULL;
|
||
|
||
TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::GetDisplayNameOf");
|
||
|
||
Assert(pidl);
|
||
Assert(lpName);
|
||
|
||
if (!pidl || !lpName)
|
||
{
|
||
hr = E_INVALIDARG;
|
||
}
|
||
else if (FIsUPnPDeviceFoldPidl(pidl))
|
||
{
|
||
CUPnPDeviceFoldPidl udfp;
|
||
|
||
pupdfp = ConvertToUPnPDevicePIDL(pidl);
|
||
|
||
#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
|
||
|
||
if (uFlags & SHGDN_FORPARSING)
|
||
{
|
||
#if 0
|
||
AssertSz(FALSE, "SHGDN_FORPARSING support NYI in GetDisplayNameOf");
|
||
#endif
|
||
}
|
||
|
||
hr = udfp.HrInit(pupdfp);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
pwszStrToCopy = udfp.PszGetNamePointer();
|
||
Assert(pwszStrToCopy);
|
||
|
||
pszTemp = TszFromWsz(pwszStrToCopy);
|
||
if (!pszTemp)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
else
|
||
{
|
||
hr = HrTszToStrRet(pszTemp, lpName);
|
||
|
||
free((PVOID) pszTemp);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// not a valid connections pidl (neither Win2K nor Win98).
|
||
//
|
||
hr = E_INVALIDARG;
|
||
}
|
||
|
||
TraceHr(ttidError, FAL, hr, FALSE, "CUPnPDeviceFolder::GetDisplayNameOf");
|
||
return hr;
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Member: CUPnPDeviceFolder::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 CUPnPDeviceFolder::SetNameOf(
|
||
HWND hwndOwner,
|
||
LPCITEMIDLIST pidl,
|
||
LPCOLESTR lpszName,
|
||
DWORD uFlags,
|
||
LPITEMIDLIST * ppidlOut)
|
||
{
|
||
HRESULT hr = S_OK;
|
||
PUPNPDEVICEFOLDPIDL pupdfp = NULL;
|
||
|
||
TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::SetNameOf");
|
||
|
||
Assert(hwndOwner);
|
||
Assert(pidl);
|
||
Assert(lpszName);
|
||
|
||
if (!pidl && !lpszName)
|
||
{
|
||
hr = E_INVALIDARG;
|
||
}
|
||
else if (!*lpszName)
|
||
{
|
||
hr = S_OK;
|
||
}
|
||
else if (FIsUPnPDeviceFoldPidl(pidl))
|
||
{
|
||
CUPnPDeviceFoldPidl udfp;
|
||
|
||
pupdfp = ConvertToUPnPDevicePIDL(pidl);
|
||
|
||
hr = udfp.HrInit(pupdfp);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
// Change the name of the item in the PIDL
|
||
hr = udfp.HrSetName(lpszName);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
LPITEMIDLIST pidlOut;
|
||
|
||
// Persist the PIDL data to a new PIDL so we can generate an event
|
||
// for it
|
||
hr = udfp.HrPersist(m_pDelegateMalloc, &pidlOut);
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
NAME_MAP * pnm;
|
||
|
||
pnm = new NAME_MAP;
|
||
if (pnm)
|
||
{
|
||
// Copy the name and UDN to a struct to keep in a list
|
||
// of mapped UDNs to friendly names.
|
||
//
|
||
pnm->szName = TszDupTsz(udfp.PszGetNamePointer());
|
||
if (!pnm->szName)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
else
|
||
{
|
||
pnm->szUdn = TszDupTsz(udfp.PszGetUDNPointer());
|
||
if (!pnm->szUdn)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
else
|
||
{
|
||
// Delete the item and re-add it again
|
||
g_CListNameMap.FDelete(udfp.PszGetUDNPointer());
|
||
g_CListNameMap.FAdd(pnm);
|
||
|
||
// Notify the shell of the rename
|
||
GenerateEvent(SHCNE_RENAMEITEM, m_pidlFolderRoot,
|
||
pidl, pidlOut);
|
||
|
||
FolderDeviceNode * pDeviceNode;
|
||
|
||
if (g_CListFolderDeviceNode.FFind(pnm->szUdn,
|
||
&pDeviceNode))
|
||
{
|
||
// Delete the node's old name and give it the new
|
||
// one
|
||
//
|
||
wcscpy(pDeviceNode->pszDisplayName,
|
||
pnm->szName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
|
||
if (ppidlOut)
|
||
{
|
||
*ppidlOut = pidlOut;
|
||
}
|
||
else
|
||
{
|
||
FreeIDL(pidlOut);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// not a valid UPnP pidl
|
||
//
|
||
hr = E_INVALIDARG;
|
||
}
|
||
|
||
TraceHr(ttidError, FAL, hr, FALSE, "CUPnPDeviceFolder::SetNameOf");
|
||
return hr;
|
||
}
|
||
|
||
|