[SHELL32] Implement CFolder[Item] getters/setters (#9173)

This commit is contained in:
Whindmar Saksit
2026-07-01 11:41:17 +02:00
committed by GitHub
parent 6679825f21
commit c891aefdcf
25 changed files with 822 additions and 92 deletions
+1 -1
View File
@@ -81,7 +81,7 @@ HRESULT WINAPI CDropTargetHelper::Show(BOOL fShow)
/*************************************************************************
* SH32_SimulateDropWithSite [SHELL32.INTERNAL]
*/
static HRESULT SH32_SimulateDropWithSite(IDropTarget *pDT, IDataObject *pDO, DWORD grfKeyState, PPOINTL pPtl, LPDWORD pdwEffect, IUnknown *pSite)
HRESULT SH32_SimulateDropWithSite(IDropTarget *pDT, IDataObject *pDO, DWORD grfKeyState, PPOINTL pPtl, LPDWORD pdwEffect, IUnknown *pSite)
{
CScopedSetObjectWithSite site(pDT, pSite);
return SHSimulateDrop(pDT, pDO, grfKeyState, pPtl, pdwEffect);
+3
View File
@@ -54,4 +54,7 @@ BEGIN_COM_MAP(CDropTargetHelper)
END_COM_MAP()
};
HRESULT
SH32_SimulateDropWithSite(IDropTarget *pDT, IDataObject *pDO, DWORD grfKeyState, PPOINTL pPtl, LPDWORD pdwEffect, IUnknown *pSite);
#endif /* _DRAGDROPHELPER_H_ */
+131 -24
View File
@@ -6,10 +6,13 @@
*/
#include "precomp.h"
#include "prop.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
EXTERN_C BOOL WINAPI Win32CreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec);
CFolder::CFolder()
{
}
@@ -18,21 +21,19 @@ CFolder::~CFolder()
{
}
HRESULT CFolder::Initialize(LPITEMIDLIST idlist)
HRESULT CFolder::Initialize(LPCITEMIDLIST idlist)
{
m_idlist.Attach(ILClone(idlist));
if (!m_idlist)
return E_OUTOFMEMORY;
return CShellDispatch_Constructor(IID_PPV_ARG(IShellDispatch, &m_Application));
}
HRESULT CFolder::GetShellFolder(CComPtr<IShellFolder>& psfCurrent)
{
CComPtr<IShellFolder> psfDesktop;
HRESULT hr = SHGetDesktopFolder(&psfDesktop);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return psfDesktop->BindToObject(m_idlist, NULL, IID_PPV_ARG(IShellFolder, &psfCurrent));
HRESULT hr = SHBindToObject(NULL, GetAbsoluteIDList(), NULL, IID_PPV_ARG(IShellFolder, &psfCurrent));
FAILED_UNEXPECTEDLY(hr);
return hr;
}
// *** Folder methods ***
@@ -41,12 +42,9 @@ HRESULT STDMETHODCALLTYPE CFolder::get_Title(BSTR *pbs)
if (!pbs)
return E_POINTER;
WCHAR path[MAX_PATH+2] = {0};
WCHAR path[MAX_PATH];
HRESULT hr = ILGetDisplayNameExW(NULL, m_idlist, path, ILGDN_INFOLDER) ? S_OK : E_FAIL;
if (FAILED_UNEXPECTEDLY(hr))
return hr;
*pbs = SysAllocString(path);
*pbs = SysAllocString(SUCCEEDED(hr) ? path : L"");
return S_OK;
}
@@ -75,17 +73,23 @@ HRESULT STDMETHODCALLTYPE CFolder::get_Parent(IDispatch **ppid)
HRESULT STDMETHODCALLTYPE CFolder::get_ParentFolder(Folder **ppsf)
{
TRACE("(%p, %p)\n", this);
TRACE("(%p, %p)\n", this, ppsf);
*ppsf = NULL;
LPCITEMIDLIST pidlAbsSelf = GetAbsoluteIDList();
if (ILIsEmpty(pidlAbsSelf))
return S_FALSE;
return E_NOTIMPL;
CComHeapPtr<ITEMIDLIST> pidlParent;
if (FAILED(SHILCloneParent(pidlAbsSelf, &pidlParent)))
return E_OUTOFMEMORY;
return ShellObjectCreatorInit<CFolder>(static_cast<LPITEMIDLIST>(pidlParent), IID_PPV_ARG(Folder, ppsf));
}
HRESULT STDMETHODCALLTYPE CFolder::Items(FolderItems **ppid)
{
/* FolderItems_Constructor */
return ShellObjectCreatorInit<CFolderItems>(static_cast<LPITEMIDLIST>(m_idlist), this, IID_PPV_ARG(FolderItems, ppid));
return ShellObjectCreatorInit<CFolderItems>(GetAbsoluteIDList(), this, IID_PPV_ARG(FolderItems, ppid));
}
HRESULT STDMETHODCALLTYPE CFolder::ParseName(BSTR bName, FolderItem **ppid)
@@ -97,42 +101,145 @@ HRESULT STDMETHODCALLTYPE CFolder::ParseName(BSTR bName, FolderItem **ppid)
CComPtr<IShellFolder> psfCurrent;
HRESULT hr = GetShellFolder(psfCurrent);
if (FAILED_UNEXPECTEDLY(hr))
if (FAILED(hr))
return hr;
CComHeapPtr<ITEMIDLIST_RELATIVE> relativePidl;
hr = psfCurrent->ParseDisplayName(NULL, NULL, bName, NULL, &relativePidl, NULL);
if (!SUCCEEDED(hr))
return S_FALSE;
CComHeapPtr<ITEMIDLIST> combined;
combined.Attach(ILCombine(m_idlist, relativePidl));
combined.Attach(ILCombine(GetAbsoluteIDList(), relativePidl));
if (!combined)
return E_OUTOFMEMORY;
return ShellObjectCreatorInit<CFolderItem>(this, static_cast<LPITEMIDLIST>(combined), IID_PPV_ARG(FolderItem, ppid));
CComHeapPtr<ITEMIDLIST> parentPidl;
if (FAILED(hr = SHILCloneParent((LPCITEMIDLIST)combined, &parentPidl)))
return hr;
CComPtr<Folder> pParent; // The parent Folder of the thing we just parsed
hr = ShellObjectCreatorInit<CFolder>(parentPidl, IID_PPV_ARG(Folder, &pParent));
if (FAILED(hr))
return hr;
return ShellObjectCreatorInit<CFolderItem>(pParent, static_cast<LPITEMIDLIST>(combined), IID_PPV_ARG(FolderItem, ppid));
}
HRESULT STDMETHODCALLTYPE CFolder::NewFolder(BSTR bName, VARIANT vOptions)
{
TRACE("(%p, %s, %s)\n", this, wine_dbgstr_w(bName), wine_dbgstr_variant(&vOptions));
// Note: MSDN says vOptions "is not currently used"
CComPtr<IStorage> pStg, pStgNew;
HRESULT hr = SHBindToObject(NULL, GetAbsoluteIDList(), NULL, IID_PPV_ARG(IStorage, &pStg));
if (FAILED(hr))
goto tryfs;//return hr;
hr = pStg->CreateStorage(bName, STGM_FAILIFTHERE, 0, 0, &pStgNew);
return (hr == STG_E_FILEALREADYEXISTS) ? S_OK : hr;
tryfs: // HACKFIX: Our CFSFolder does not yet support IStorage, try it directly
LPCITEMIDLIST pidlAbsSelf = GetAbsoluteIDList();
if (SHGetAttributes(NULL, pidlAbsSelf, SFGAO_FILESYSTEM) == SFGAO_FILESYSTEM)
{
CComHeapPtr<WCHAR> pszDirPath;
if (SUCCEEDED(SHELL_DisplayNameOf(NULL, pidlAbsSelf, SHGDN_FORPARSING, &pszDirPath)))
{
DWORD cch = wcslen(pszDirPath) + 1 + wcslen(bName) + 1, attr;
if (PWSTR pszPath = (PWSTR)SHAlloc(cch * sizeof(WCHAR)))
{
StringCchPrintfW(pszPath, cch, L"%s\\%s", &pszDirPath[0], bName);
if (PathFileExistsAndAttributesW(pszPath, &attr))
hr = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_OK : S_FALSE;
else
hr = Win32CreateDirectoryW(pszPath, NULL) ? S_OK : E_FAIL;
SHFree(pszPath);
}
}
}
return hr;
}
static HRESULT GetUIObjectFromVariant(VARIANT &vItem, REFIID riid, void **ppv)
{
CComHeapPtr<ITEMIDLIST> pidlOneItem;
if (SUCCEEDED(VariantToIdlist(&vItem, &pidlOneItem)))
return SHELL_GetUIObjectOfAbsoluteItem(NULL, pidlOneItem, riid, ppv);
// TODO: CFolderItems array
return E_NOTIMPL;
}
HRESULT CFolder::CopyMoveOperation(VARIANT &vItem, VARIANT vOptions, BOOL bCopy)
{
CComPtr<IShellFolder> psfCurrent;
HRESULT hr = GetShellFolder(psfCurrent);
if (FAILED(hr))
return hr;
CComPtr<IDropTarget> pDT;
if (FAILED_UNEXPECTEDLY(hr = psfCurrent->CreateViewObject(GetHwnd(), IID_PPV_ARG(IDropTarget, &pDT))))
return hr;
CComPtr<IDataObject> pDO;
if (FAILED_UNEXPECTEDLY(hr = GetUIObjectFromVariant(vItem, IID_PPV_ARG(IDataObject, &pDO))))
return hr;
if (SUCCEEDED(VariantChangeType(&vOptions, &vOptions, 0, VT_I4)))
{
UINT flags = V_I4(&vOptions) & ~(FOF_MULTIDESTFILES | FOF_WANTMAPPINGHANDLE);
if (flags)
{
extern UINT g_cf_FileOpFlags;
if (!g_cf_FileOpFlags)
g_cf_FileOpFlags = RegisterClipboardFormatW(L"FileOpFlags");
DataObj_SetDWORD(pDO, g_cf_FileOpFlags, flags);
}
}
hr = SH32_SimulateDropWithSite(pDT, pDO, MK_LBUTTON | (bCopy ? MK_CONTROL : MK_SHIFT), NULL, NULL, GetSite());
return SUCCEEDED(hr) ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE CFolder::MoveHere(VARIANT vItem, VARIANT vOptions)
{
TRACE("(%p, %s, %s)\n", this, wine_dbgstr_variant(&vItem), wine_dbgstr_variant(&vOptions));
return E_NOTIMPL;
return CopyMoveOperation(vItem, vOptions, FALSE);
}
HRESULT STDMETHODCALLTYPE CFolder::CopyHere(VARIANT vItem, VARIANT vOptions)
{
TRACE("(%p, %s, %s)\n", this, wine_dbgstr_variant(&vItem), wine_dbgstr_variant(&vOptions));
return E_NOTIMPL;
return CopyMoveOperation(vItem, vOptions, TRUE);
}
HRESULT STDMETHODCALLTYPE CFolder::GetDetailsOf(VARIANT vItem, int iColumn, BSTR *pbs)
{
TRACE("(%p, %s, %i, %p)\n", this, wine_dbgstr_variant(&vItem), iColumn, pbs);
return E_NOTIMPL;
CComPtr<IShellFolder> psf;
HRESULT hr = GetShellFolder(psf);
if (FAILED(hr))
return hr;
PCUITEMID_CHILD pidlItem = CFolderItem::GetLeafPidlRef(&vItem);
if (pidlItem && iColumn == -1)
{
PWSTR pszTip = NULL;
if (SUCCEEDED(hr = SHELL_QueryInfoTipAlloc(psf, QITIPF_DEFAULT, pidlItem, &pszTip)))
{
hr = SHELL_SysAllocString(pszTip, pbs);
SHFree(pszTip);
return hr;
}
}
else
{
VARIANT v;
if (pbs && SUCCEEDED(SHELL_GetDetailsOfAsStringVariant(psf, pidlItem, iColumn, &v)))
{
*pbs = V_BSTR(&v);
return S_OK;
}
}
return SHELL_SysAllocString(L"", pbs);
}
@@ -143,7 +250,7 @@ HRESULT STDMETHODCALLTYPE CFolder::get_Self(FolderItem **ppfi)
if (!ppfi)
return E_POINTER;
return ShellObjectCreatorInit<CFolderItem>(this, static_cast<LPITEMIDLIST>(m_idlist), IID_PPV_ARG(FolderItem, ppfi));
return ShellObjectCreatorInit<CFolderItem>(this, GetAbsoluteIDList(), IID_PPV_ARG(FolderItem, ppfi));
}
HRESULT STDMETHODCALLTYPE CFolder::get_OfflineStatus(LONG *pul)
+5 -1
View File
@@ -16,6 +16,7 @@ class CFolder:
{
private:
HRESULT GetShellFolder(CComPtr<IShellFolder>& psfCurrent);
HRESULT CopyMoveOperation(VARIANT &vItem, VARIANT vOptions, BOOL bCopy);
CComHeapPtr<ITEMIDLIST> m_idlist;
CComPtr<IShellDispatch> m_Application;
@@ -24,7 +25,10 @@ public:
CFolder();
~CFolder();
HRESULT Initialize(LPITEMIDLIST idlist);
HRESULT Initialize(LPCITEMIDLIST idlist);
LPCITEMIDLIST GetAbsoluteIDList() { return m_idlist; }
HWND GetHwnd() { return NULL; }
IUnknown* GetSite() { return NULL; }
// *** Folder methods ***
STDMETHOD(get_Title)(BSTR *pbs) override;
+1 -1
View File
@@ -89,7 +89,7 @@ CFolderItemVerbs::~CFolderItemVerbs()
DestroyMenu(m_menu);
}
HRESULT CFolderItemVerbs::Init(LPITEMIDLIST idlist)
HRESULT CFolderItemVerbs::Init(LPCITEMIDLIST idlist)
{
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, idlist, IID_PPV_ARG(IContextMenu, &m_contextmenu));
if (FAILED_UNEXPECTEDLY(hr))
+3 -1
View File
@@ -67,7 +67,7 @@ public:
CFolderItemVerbs();
virtual ~CFolderItemVerbs();
HRESULT Init(LPITEMIDLIST idlist);
HRESULT Init(LPCITEMIDLIST idlist);
// *** FolderItemVerbs methods ***
STDMETHOD(get_Count)(LONG *plCount) override;
@@ -83,6 +83,8 @@ BEGIN_COM_MAP(CFolderItemVerbs)
COM_INTERFACE_ENTRY_IID(IID_FolderItemVerbs, FolderItemVerbs)
COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch)
END_COM_MAP()
static HRESULT CreateInstance(CComPtr<CFolderItemVerbs> &objref) { return ShellObjectCreator(objref); }
};
#endif
+180 -30
View File
@@ -6,6 +6,7 @@
*/
#include "precomp.h"
#include "prop.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
@@ -18,13 +19,67 @@ CFolderItem::~CFolderItem()
{
}
HRESULT CFolderItem::Initialize(Folder* folder, LPITEMIDLIST idlist)
HRESULT CFolderItem::Initialize(Folder* folder, LPCITEMIDLIST idlist)
{
m_idlist.Attach(ILClone(idlist));
if (!m_idlist)
return E_OUTOFMEMORY;
m_Folder = folder;
return S_OK;
}
inline HRESULT CFolderItem::GetParentShellFolderAndItem(REFIID riid, void**ppv, PCUITEMID_CHILD &pidlLast)
{
return SHBindToParent(GetAbsoluteIDList(), riid, ppv, &pidlLast);
}
LPCITEMIDLIST CFolderItem::GetInternalPidlRef(IUnknown *pUnk)
{
LPCITEMIDLIST pidl = NULL;
FolderItem2 *pFI2;
if (pUnk && SUCCEEDED(pUnk->QueryInterface(IID_PPV_ARG(FolderItem2, &pFI2))))
{
// This assumes we are the only implementer of CFolderItem (probably true)
// but when we get IParentAndItem we can do this in a safer way
pidl = static_cast<CFolderItem*>(pFI2)->m_idlist;
pFI2->Release();
}
return pidl;
}
LPCITEMIDLIST CFolderItem::GetInternalPidlRef(const VARIANT *pV)
{
if (!pV)
return NULL;
if (V_VT(pV) == (VT_VARIANT | VT_BYREF) && V_VARIANTREF(pV))
pV = V_VARIANTREF(pV);
switch (V_VT(pV))
{
case VT_DISPATCH | VT_BYREF:
return V_DISPATCHREF(pV) ? GetInternalPidlRef(*V_DISPATCHREF(pV)) : NULL;
case VT_DISPATCH:
return GetInternalPidlRef(V_DISPATCH(pV));
}
return NULL;
}
PCUITEMID_CHILD CFolderItem::GetLeafPidlRef(const VARIANT *pV)
{
return (PCUITEMID_CHILD)ILFindLastID(GetInternalPidlRef(pV));
}
HRESULT CFolderItem::GetFindDataFromIDList(WIN32_FIND_DATA &wfd)
{
CComPtr<IShellFolder2> psf;
PCUITEMID_CHILD pidlLeaf;
HRESULT hr = GetParentShellFolderAndItem(IID_PPV_ARG(IShellFolder2, &psf), pidlLeaf);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return SHGetDataFromIDListW(psf, pidlLeaf, SHGDFIL_FINDDATA, &wfd, sizeof(wfd));
}
// *** FolderItem methods ***
HRESULT STDMETHODCALLTYPE CFolderItem::get_Application(IDispatch **ppid)
{
@@ -35,12 +90,10 @@ HRESULT STDMETHODCALLTYPE CFolderItem::get_Application(IDispatch **ppid)
HRESULT STDMETHODCALLTYPE CFolderItem::get_Parent(IDispatch **ppid)
{
TRACE("(%p, %p)\n", this, ppid);
if (ppid)
{
*ppid = m_Folder;
(*ppid)->AddRef();
}
return E_NOTIMPL;
if (!ppid)
return E_INVALIDARG;
return m_Folder->QueryInterface(IID_PPV_ARG(IDispatch, ppid));
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_Name(BSTR *pbs)
@@ -49,9 +102,9 @@ HRESULT STDMETHODCALLTYPE CFolderItem::get_Name(BSTR *pbs)
*pbs = NULL;
CComPtr<IShellFolder2> Parent;
LPCITEMIDLIST last_part;
HRESULT hr = SHBindToParent(m_idlist, IID_PPV_ARG(IShellFolder2, &Parent), &last_part);
CComPtr<IShellFolder> Parent;
PCUITEMID_CHILD last_part;
HRESULT hr = GetParentShellFolderAndItem(IID_PPV_ARG(IShellFolder, &Parent), last_part);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
@@ -66,7 +119,25 @@ HRESULT STDMETHODCALLTYPE CFolderItem::get_Name(BSTR *pbs)
HRESULT STDMETHODCALLTYPE CFolderItem::put_Name(BSTR bs)
{
TRACE("(%p, %s)\n", this, wine_dbgstr_w(bs));
return E_NOTIMPL;
CComPtr<IShellFolder> psf;
PCUITEMID_CHILD pidlLeaf;
HRESULT hr = GetParentShellFolderAndItem(IID_PPV_ARG(IShellFolder, &psf), pidlLeaf);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
LPITEMIDLIST pidlNew;
if (SUCCEEDED(hr = psf->SetNameOf(GetHwnd(), pidlLeaf, bs, SHGDN_INFOLDER, &pidlNew)) && pidlNew)
{
LPITEMIDLIST pidlClone = ILClone(m_idlist);
ILRemoveLastID(pidlClone);
if (pidlClone && SUCCEEDED(SHILAppend(pidlNew, &pidlClone)))
{
m_idlist.Free();
m_idlist.Attach(pidlClone);
}
}
return hr;
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_Path(BSTR *pbs)
@@ -93,38 +164,54 @@ HRESULT STDMETHODCALLTYPE CFolderItem::get_GetLink(IDispatch **ppid)
HRESULT STDMETHODCALLTYPE CFolderItem::get_GetFolder(IDispatch **ppid)
{
TRACE("(%p, %p)\n", this, ppid);
return E_NOTIMPL;
return ShellObjectCreatorInit<CFolder>(const_cast<LPITEMIDLIST>(GetAbsoluteIDList()), IID_PPV_ARG(IDispatch, ppid));
}
HRESULT CFolderItem::HasAttribute(DWORD sfgaof, VARIANT_BOOL *pB)
{
*pB = SHGetAttributes(NULL, GetAbsoluteIDList(), sfgaof) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_IsLink(VARIANT_BOOL *pb)
{
TRACE("(%p, %p)\n", this, pb);
return E_NOTIMPL;
return HasAttribute(SFGAO_LINK, pb);
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_IsFolder(VARIANT_BOOL *pb)
{
TRACE("(%p, %p)\n", this, pb);
return E_NOTIMPL;
return HasAttribute(SFGAO_FOLDER, pb);
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_IsFileSystem(VARIANT_BOOL *pb)
{
TRACE("(%p, %p)\n", this, pb);
return E_NOTIMPL;
return HasAttribute(SFGAO_FILESYSTEM, pb);
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_IsBrowsable(VARIANT_BOOL *pb)
{
TRACE("(%p, %p)\n", this, pb);
return E_NOTIMPL;
return HasAttribute(SFGAO_BROWSABLE, pb);
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_ModifyDate(DATE *pdt)
{
TRACE("(%p, %p)\n", this, pdt);
return E_NOTIMPL;
WIN32_FIND_DATA wfd;
if (SUCCEEDED(GetFindDataFromIDList(wfd)))
{
FILETIME ft;
FileTimeToLocalFileTime(&wfd.ftLastWriteTime, &ft);
WORD dd, dt;
if (FileTimeToDosDateTime(&ft, &dd, &dt) && DosDateTimeToVariantTime(dd, dt, pdt))
return S_OK;
}
*pdt = 0;
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CFolderItem::put_ModifyDate(DATE dt)
@@ -136,37 +223,98 @@ HRESULT STDMETHODCALLTYPE CFolderItem::put_ModifyDate(DATE dt)
HRESULT STDMETHODCALLTYPE CFolderItem::get_Size(LONG *pul)
{
TRACE("(%p, %p)\n", this, pul);
return E_NOTIMPL;
WIN32_FIND_DATA wfd;
if (SUCCEEDED(GetFindDataFromIDList(wfd)))
{
*pul = wfd.nFileSizeLow;
return S_OK;
}
*pul = 0;
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CFolderItem::get_Type(BSTR *pbs)
{
TRACE("(%p, %p)\n", this, pbs);
return E_NOTIMPL;
VARIANT v;
V_VT(&v) = VT_EMPTY;
if (SUCCEEDED(GetExtendedProperty(PKEY_ItemTypeText, &v)))
{
if (SUCCEEDED(VariantChangeType(&v, &v, 0, VT_BSTR)))
{
*pbs = V_BSTR(&v);
return S_OK;
}
VariantClear(&v);
}
HRESULT hr = SHELL_SysAllocString(L"", pbs);
return hr == S_OK ? S_FALSE : hr;
}
HRESULT STDMETHODCALLTYPE CFolderItem::Verbs(FolderItemVerbs **ppfic)
{
if (!ppfic)
return E_POINTER;
CFolderItemVerbs* verbs = new CComObject<CFolderItemVerbs>();
HRESULT hr = verbs->Init(m_idlist);
CComPtr<CFolderItemVerbs> pVerbs;
HRESULT hr = CFolderItemVerbs::CreateInstance(pVerbs);
if (SUCCEEDED(hr))
hr = pVerbs->Init(GetAbsoluteIDList());
if (FAILED_UNEXPECTEDLY(hr))
{
delete verbs;
return hr;
}
verbs->AddRef();
*ppfic = verbs;
*ppfic = pVerbs.Detach();
return S_OK;
}
HRESULT STDMETHODCALLTYPE CFolderItem::InvokeVerb(VARIANT vVerb)
{
TRACE("(%p, %s)\n", this, wine_dbgstr_variant(&vVerb));
return E_NOTIMPL;
VARIANT empty;
V_VT(&empty) = VT_EMPTY;
return InvokeVerbEx(vVerb, empty);
}
HRESULT STDMETHODCALLTYPE CFolderItem::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs)
{
TRACE("(%p, %s)\n", this, wine_dbgstr_variant(&vVerb));
SHELLEXECUTEINFOW sei;
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI;
sei.hwnd = GetHwnd();
sei.lpVerb = V_VT(&vVerb) == VT_BSTR ? V_BSTR(&vVerb) : NULL;
sei.lpFile = NULL;
sei.lpParameters = V_VT(&vArgs) == VT_BSTR ? V_BSTR(&vArgs) : NULL;
sei.lpDirectory = NULL;
sei.nShow = SW_SHOW;
sei.lpIDList = const_cast<LPITEMIDLIST>(GetAbsoluteIDList());
ShellExecuteExW(&sei);
return S_OK;
}
HRESULT CFolderItem::GetExtendedProperty(REFPROPERTYKEY pkey, VARIANT *pv)
{
CComPtr<IShellFolder2> psf;
PCUITEMID_CHILD pidlLeaf;
HRESULT hr = GetParentShellFolderAndItem(IID_PPV_ARG(IShellFolder2, &psf), pidlLeaf);
return FAILED(hr) ? hr : psf->GetDetailsEx(pidlLeaf, reinterpret_cast<const SHCOLUMNID*>(&pkey), pv);
}
HRESULT STDMETHODCALLTYPE CFolderItem::ExtendedProperty(BSTR bsPropName, VARIANT *pv)
{
if (!pv)
return E_INVALIDARG;
PROPERTYKEY pkeybuf;
const PROPERTYKEY *pPK = SHELL_GetPropertyKeyFromString(bsPropName, &pkeybuf);
if (pPK && GetExtendedProperty(*pPK, pv) == S_OK)
return S_OK;
V_VT(pv) = VT_EMPTY;
return S_FALSE;
}
CFolderItems::CFolderItems()
@@ -178,11 +326,13 @@ CFolderItems::~CFolderItems()
{
}
HRESULT CFolderItems::Initialize(LPITEMIDLIST idlist, Folder* parent)
HRESULT CFolderItems::Initialize(LPCITEMIDLIST idlist, Folder* parent)
{
CComPtr<IShellFolder> psfDesktop, psfTarget;
m_idlist.Attach(ILClone(idlist));
if (!m_idlist)
return E_OUTOFMEMORY;
HRESULT hr = SHGetDesktopFolder(&psfDesktop);
if (FAILED_UNEXPECTEDLY(hr))
+19 -3
View File
@@ -12,17 +12,29 @@
class CFolderItem:
public CComCoClass<CFolderItem>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IDispatchImpl<FolderItem, &IID_FolderItem>
public IDispatchImpl<FolderItem2, &IID_FolderItem2>
{
private:
CComHeapPtr<ITEMIDLIST> m_idlist;
CComPtr<Folder> m_Folder;
inline HRESULT GetParentShellFolderAndItem(REFIID riid, void**ppv, PCUITEMID_CHILD &pidlLast);
static LPCITEMIDLIST GetInternalPidlRef(IUnknown *pUnk);
static LPCITEMIDLIST GetInternalPidlRef(const VARIANT *pV);
public:
CFolderItem();
~CFolderItem();
HRESULT Initialize(Folder* folder, LPITEMIDLIST idlist);
HRESULT Initialize(Folder* folder, LPCITEMIDLIST idlist);
LPCITEMIDLIST GetAbsoluteIDList() { return m_idlist; }
HWND GetHwnd() { return NULL; }
HRESULT GetFindDataFromIDList(WIN32_FIND_DATA &wfd);
HRESULT HasAttribute(DWORD sfgaof, VARIANT_BOOL *pB);
HRESULT GetExtendedProperty(REFPROPERTYKEY pkey, VARIANT *pv);
static PCUITEMID_CHILD GetLeafPidlRef(const VARIANT *pV);
// *** FolderItem methods ***
STDMETHOD(get_Application)(IDispatch **ppid) override;
@@ -43,12 +55,16 @@ public:
STDMETHOD(Verbs)(FolderItemVerbs **ppfic) override;
STDMETHOD(InvokeVerb)(VARIANT vVerb) override;
// *** FolderItem2 methods ***
STDMETHOD(InvokeVerbEx)(VARIANT vVerb, VARIANT vArgs) override;
STDMETHOD(ExtendedProperty)(BSTR bsPropName, VARIANT *pv) override;
DECLARE_NOT_AGGREGATABLE(CFolderItem)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CFolderItem)
COM_INTERFACE_ENTRY_IID(IID_FolderItem, FolderItem)
COM_INTERFACE_ENTRY_IID(IID_FolderItem2, FolderItem2)
COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch)
END_COM_MAP()
};
@@ -69,7 +85,7 @@ public:
~CFolderItems();
// Please note: CFolderItems takes ownership of idlist.
HRESULT Initialize(LPITEMIDLIST idlist, Folder* parent);
HRESULT Initialize(LPCITEMIDLIST idlist, Folder* parent);
// *** FolderItems methods ***
STDMETHOD(get_Count)(long *plCount) override;
+1
View File
@@ -63,6 +63,7 @@ list(APPEND SOURCE
droptargets/CexeDropHandler.cpp
droptargets/CFSDropTarget.cpp
droptargets/CRecyclerDropTarget.cpp
prop.cpp
shldataobject.cpp
shlexec.cpp
shlfileop.cpp
+26 -22
View File
@@ -8,6 +8,7 @@
*/
#include "precomp.h"
#include "prop.h"
#include "winsvc.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
@@ -61,20 +62,6 @@ HRESULT STDMETHODCALLTYPE CShellDispatch::get_Parent(IDispatch **ppid)
return S_OK;
}
HRESULT VariantToIdlist(VARIANT* var, LPITEMIDLIST* idlist)
{
HRESULT hr = E_FAIL;
if(V_VT(var) == VT_I4)
{
hr = SHGetSpecialFolderLocation(NULL, V_I4(var), idlist);
}
else if(V_VT(var) == VT_BSTR)
{
hr = SHILCreateFromPathW(V_BSTR(var), idlist, NULL);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CShellDispatch::NameSpace(VARIANT vDir, Folder **ppsdf)
{
TRACE("(%p, %s, %p)\n", this, debugstr_variant(&vDir), ppsdf);
@@ -336,6 +323,27 @@ HRESULT STDMETHODCALLTYPE CShellDispatch::GetSystemInformation(BSTR name, VARIAN
V_UI4(ret) = si.wProcessorArchitecture;
return S_OK;
}
else if (!lstrcmpiW(name, L"ProcessorSpeed"))
{
DWORD cb = sizeof(DWORD);
V_VT(ret) = VT_EMPTY;
if (RegGetValueW(HKEY_LOCAL_MACHINE, L"Hardware\\Description\\System\\CentralProcessor\\0",
L"~Mhz", RRF_RT_REG_DWORD, NULL, &V_UI4(ret), &cb))
{
return S_FALSE;
}
V_VT(ret) = VT_I4;
return S_OK;
}
else if (!lstrcmpiW(name, L"PhysicalMemoryInstalled"))
{
MEMORYSTATUSEX mems;
mems.dwLength = sizeof(mems);
GlobalMemoryStatusEx(&mems);
V_VT(ret) = VT_UI8;
V_UI8(ret) = mems.ullTotalPhys;
return S_OK;
}
UINT os = 0;
if (!lstrcmpiW(name, L"IsOS_Professional"))
@@ -538,7 +546,7 @@ HRESULT STDMETHODCALLTYPE CShellDispatch::GetSetting(LONG setting, VARIANT_BOOL
{
TRACE("(%p, %lu, %p)\n", this, setting, result);
int flag = -1;
int flag = 0;
SHELLSTATE ss = { };
SHGetSetSettings(&ss, setting, FALSE);
switch (setting)
@@ -552,14 +560,10 @@ HRESULT STDMETHODCALLTYPE CShellDispatch::GetSetting(LONG setting, VARIANT_BOOL
case SSF_SEPPROCESS: flag = ss.fSepProcess; break;
case SSF_STARTPANELON: flag = ss.fStartPanelOn; break;
case SSF_SERVERADMINUI: flag = IsOS(OS_SERVERADMINUI); break;
default: *result = VARIANT_FALSE; return S_FALSE;
}
if (flag >= 0)
{
*result = flag ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
return S_FALSE;
*result = flag ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
@@ -70,13 +70,22 @@ static void GetDefaultCopyMoveEffect()
// FIXME: When the source is on a different volume than the target, change default from move to copy
}
UINT g_cf_FileOpFlags = 0;
static inline DWORD GetDefaultFileOpFlags(IDataObject *pDO, DWORD fDefault = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR)
{
if (!g_cf_FileOpFlags)
g_cf_FileOpFlags = RegisterClipboardFormatW(L"FileOpFlags"); // github.com/dotnet/winforms/issues/5884?timeline_page=1
return DataObj_GetDWORD(pDO, g_cf_FileOpFlags, fDefault);
}
/****************************************************************************
* CFSDropTarget::_CopyItems
*
* copies or moves items to this folder
*/
HRESULT CFSDropTarget::_CopyItems(IShellFolder * pSFFrom, UINT cidl,
LPCITEMIDLIST * apidl, BOOL bCopy)
HRESULT CFSDropTarget::_CopyItems(IDataObject *pDO, IShellFolder * pSFFrom,
UINT cidl, LPCITEMIDLIST * apidl, BOOL bCopy)
{
HRESULT ret;
WCHAR wszDstPath[MAX_PATH + 1] = {0};
@@ -128,7 +137,7 @@ HRESULT CFSDropTarget::_CopyItems(IShellFolder * pSFFrom, UINT cidl,
fop.wFunc = bCopy ? FO_COPY : FO_MOVE;
fop.pFrom = pwszSrcPathsList;
fop.pTo = wszDstPath;
fop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
fop.fFlags = GetDefaultFileOpFlags(pDO);
if (bRenameOnCollision)
fop.fFlags |= FOF_RENAMEONCOLLISION;
@@ -725,7 +734,7 @@ HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
}
else
{
hr = _CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
hr = _CopyItems(pDataObject, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
}
SHFree(pidl);
@@ -760,7 +769,7 @@ HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
op.pTo = wszTargetPath;
op.hwnd = m_hwndSite;
op.wFunc = bCopy ? FO_COPY : FO_MOVE;
op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
op.fFlags = GetDefaultFileOpFlags(pDataObject);
int res = SHFileOperationW(&op);
if (res)
{
@@ -43,7 +43,7 @@ class CFSDropTarget :
BOOL _QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect);
HRESULT _DoDrop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT _CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy);
HRESULT _CopyItems(IDataObject *pDO, IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy);
BOOL _GetUniqueFileName(LPCWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut);
static DWORD WINAPI _DoDropThreadProc(LPVOID lpParameter);
HRESULT _GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, DWORD *pdwEffect, DWORD dwAvailableEffects);
+1 -1
View File
@@ -1683,7 +1683,7 @@ HRESULT WINAPI CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *p
switch (pscid->pid)
{
case PID_STG_NAME: // Handled directly here for faster performance
return SHELL_GetDetailsOfAsStringVariant(this, pidl, SHFSF_COL_NAME, pv);
return SHELL_GetDetailsOfAsStringVariant(static_cast<IShellFolder2*>(this), pidl, SHFSF_COL_NAME, pv);
case PID_STG_SIZE:
V_VT(pv) = VT_UI4;
V_UI4(pv) = _ILGetFileSize(pidl, NULL, 0);
+2
View File
@@ -311,6 +311,8 @@ HRESULT DataObject_GetHIDACount(IDataObject *pdo);
PIDLIST_ABSOLUTE SHELL_CIDA_ILCloneFull(_In_ const CIDA *pCIDA, _In_ UINT Index);
PIDLIST_ABSOLUTE SHELL_DataObject_ILCloneFullItem(_In_ IDataObject *pDO, _In_ UINT Index);
HRESULT SHELL_CloneDataObject(_In_ IDataObject *pDO, _Out_ IDataObject **ppDO);
DWORD DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD dwDefault);
HRESULT DataObj_SetDWORD(IDataObject *pdtobj, UINT cf, DWORD dwValue);
EXTERN_C HRESULT
IUnknown_InitializeCommand(
+80
View File
@@ -0,0 +1,80 @@
/*
* PROJECT: shell32
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
* PURPOSE: [PROP]VARIANT functions
* COPYRIGHT: Copyright 2026 Whindmar Saksit <[email protected]>
*/
#define SHELL32_PROP_IMPL
#include "precomp.h"
#include "prop.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell_prop);
static const struct SHELL32PKEYMAP
{
PCWSTR pszLegacyName;
const PROPERTYKEY *pkey;
} g_PkMap[] =
{
// learn.microsoft.com/en-us/windows/win32/api/propsys/nf-propsys-psgetpropertydescriptionbyname
#define MKSH32PKEYMAP(sysname, legacyname, pkey) { (L##legacyname), &(pkey) },
MKSH32PKEYMAP(?, "Name", PKEYSHELL32_Name)
MKSH32PKEYMAP("System.ItemTypeText", "Type", PKEY_ItemTypeText)
MKSH32PKEYMAP("System.Size", "Size", PKEY_Size)
MKSH32PKEYMAP("System.FileAttributes", "Attributes", PKEY_FileAttributes)
MKSH32PKEYMAP("System.DateModified", "Write", PKEY_DateModified)
MKSH32PKEYMAP("System.Comment", "DocComments", PKEYSHELL32_Comments)
};
static const PROPERTYKEY*
SHELL_GetPropertyKeyFromLegacyName(_In_ PCWSTR pszString)
{
for (SIZE_T i = 0; i < _countof(g_PkMap); ++i)
{
if (!_wcsicmp(g_PkMap[i].pszLegacyName, pszString))
return g_PkMap[i].pkey;
}
return NULL;
}
#if /*TODO*/0 && (NTDDI_VERSION >= NTDDI_VISTA)
#define SHELL_PropertyKeyFromPropertyKeyString PSPropertyKeyFromString
#else
static HRESULT
SHELL_PropertyKeyFromPropertyKeyString(_In_ PCWSTR pszString, _Out_ PROPERTYKEY *pkey)
{
if (GUIDFromStringW(pszString, &pkey->fmtid))
{
for (pszString += 38; *pszString == ',' || *pszString == ' ';)
++pszString;
pkey->pid = StrToInt(pszString);
if (pkey->pid)
return S_OK;
}
return E_INVALIDARG;
}
#endif
const PROPERTYKEY*
SHELL_GetPropertyKeyFromString(_In_ PCWSTR pszString, _Out_ PROPERTYKEY *pkey)
{
if (SUCCEEDED(SHELL_PropertyKeyFromPropertyKeyString(pszString, pkey)))
return pkey;
return SHELL_GetPropertyKeyFromLegacyName(pszString);
}
HRESULT
VariantToIdlist(_In_ VARIANT *pV, _Out_ LPITEMIDLIST *ppidl)
{
HRESULT hr = E_FAIL;
if (V_VT(pV) == VT_I4)
{
hr = SHGetSpecialFolderLocation(NULL, V_I4(pV), ppidl);
}
else if (V_VT(pV) == VT_BSTR)
{
hr = SHILCreateFromPathW(V_BSTR(pV), ppidl, NULL);
}
return hr;
}
+36
View File
@@ -0,0 +1,36 @@
/*
* PROJECT: shell32
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
* PURPOSE: [PROP]VARIANT header
* COPYRIGHT: Copyright 2026 Whindmar Saksit <[email protected]>
*/
#include "precomp.h"
#define SHELL32_NOPROPSYSLIB // PropSys does not yet have all the PKEY_'s we need
#ifdef SHELL32_NOPROPSYSLIB
#ifdef SHELL32_PROP_IMPL
#ifndef PSGUID_SUMMARYINFORMATION
#define PSGUID_SUMMARYINFORMATION { 0xf29f85e0L, 0x4ff9, 0x1068, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 }
#endif
#define DEFINE_SHELL32PROPERTYKEY(name, psguid, pid) \
EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY name = { psguid, pid }
#else
#define DEFINE_SHELL32PROPERTYKEY(name, psguid, pid) EXTERN_C const PROPERTYKEY name
#endif // SHELL32_PROP_IMPL
DEFINE_SHELL32PROPERTYKEY(PKEY_Size, PSGUID_STORAGE, PID_STG_SIZE);
DEFINE_SHELL32PROPERTYKEY(PKEY_FileAttributes, PSGUID_STORAGE, PID_STG_ATTRIBUTES);
DEFINE_SHELL32PROPERTYKEY(PKEY_DateModified, PSGUID_STORAGE, PID_STG_WRITETIME);
DEFINE_SHELL32PROPERTYKEY(PKEY_ItemTypeText, PSGUID_STORAGE, PID_STG_STORAGETYPE);
DEFINE_SHELL32PROPERTYKEY(PKEYSHELL32_Name, PSGUID_STORAGE, PID_STG_NAME);
DEFINE_SHELL32PROPERTYKEY(PKEYSHELL32_Comments, PSGUID_SUMMARYINFORMATION, PIDSI_COMMENTS);
#endif // SHELL32_NOPROPSYSLIB
const PROPERTYKEY*
SHELL_GetPropertyKeyFromString(_In_ PCWSTR pszString, _Out_ PROPERTYKEY *pkey);
HRESULT
VariantToIdlist(_In_ VARIANT *pV, _Out_ LPITEMIDLIST *ppidl);
+5
View File
@@ -106,12 +106,17 @@ MakeSCID(SHCOLUMNID &scid, REFCLSID fmtid, UINT pid)
HRESULT
SHELL_MapSCIDToColumn(IShellFolder2 *pSF, const SHCOLUMNID *pscid);
HRESULT
SHELL_GetDetailsOfAsStringVariant(IShellFolder *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar);
HRESULT
SHELL_GetDetailsOfAsStringVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar);
HRESULT
SHELL_GetDetailsOfColumnAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARTYPE vt, VARIANT *pVar);
HRESULT
SH32_GetDetailsOfPKeyAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pVar, BOOL UseFsColMap);
HRESULT
SHELL_QueryInfoTipAlloc(_In_ IShellFolder* pSF, _In_ DWORD dwFlags, _In_ LPCITEMIDLIST pidl, _Out_ PWSTR *ppTip);
HRESULT
SHELL_CreateAbsolutePidl(IShellFolder *pSF, PCUIDLIST_RELATIVE pidlChild, PIDLIST_ABSOLUTE *ppPidl);
+17
View File
@@ -142,3 +142,20 @@ HRESULT SHELL_CloneDataObject(_In_ IDataObject *pDO, _Out_ IDataObject **ppDO)
}
return hr;
}
static inline HRESULT DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD *pdwOut)
{
// learn.microsoft.com/en-us/windows/win32/shell/dataobject
return DataObject_GetData(pdtobj, (CLIPFORMAT)cf, pdwOut, sizeof(*pdwOut));
}
DWORD DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD dwDefault)
{
DWORD dwValue;
return DataObj_GetDWORD(pdtobj, cf, &dwValue) == S_OK ? dwValue : dwDefault;
}
HRESULT DataObj_SetDWORD(IDataObject *pdtobj, UINT cf, DWORD dwValue)
{
return DataObject_SetData(pdtobj, cf, &dwValue, sizeof(dwValue));
}
+34 -2
View File
@@ -91,8 +91,8 @@ SHELL_MapSCIDToColumn(IShellFolder2 *pSF, const SHCOLUMNID *pscid)
return E_FAIL;
}
HRESULT
SHELL_GetDetailsOfAsStringVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar)
template<class T> static inline HRESULT
GetDetailsOfAsStringVariant(T &pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar)
{
V_VT(pVar) = VT_EMPTY;
SHELLDETAILS sd;
@@ -106,6 +106,25 @@ SHELL_GetDetailsOfAsStringVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT
return hr;
}
HRESULT
SHELL_GetDetailsOfAsStringVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar)
{
return GetDetailsOfAsStringVariant(pSF, pidl, Column, pVar);
}
HRESULT
SHELL_GetDetailsOfAsStringVariant(IShellFolder *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar)
{
HRESULT hr;
CComPtr<IShellFolder2> pSF2;
if (SUCCEEDED(hr = pSF->QueryInterface(IID_PPV_ARG(IShellFolder2, &pSF2))))
return SHELL_GetDetailsOfAsStringVariant(pSF2, pidl, Column, pVar);
CComPtr<IShellDetails> pSD;
if (SUCCEEDED(hr = pSF->CreateViewObject(NULL, IID_PPV_ARG(IShellDetails, &pSD))))
return GetDetailsOfAsStringVariant(pSD, pidl, Column, pVar);
return hr;
}
HRESULT
SHELL_GetDetailsOfColumnAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARTYPE vt, VARIANT *pVar)
{
@@ -139,6 +158,19 @@ SH32_GetDetailsOfPKeyAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, const S
return SUCCEEDED(hr) ? SHELL_GetDetailsOfColumnAsVariant(pSF, pidl, hr, vt, pVar) : hr;
}
HRESULT
SHELL_QueryInfoTipAlloc(_In_ IShellFolder* pSF, _In_ DWORD dwFlags, _In_ LPCITEMIDLIST pidl, _Out_ PWSTR *ppTip)
{
if (!pidl)
return E_INVALIDARG;
CComPtr<IQueryInfo> pQI;
HRESULT hr = pSF->GetUIObjectOf(NULL, 1, &pidl, IID_NULL_PPV_ARG(IQueryInfo, &pQI));
if (FAILED(hr))
return hr;
hr = pQI->GetInfoTip(dwFlags, ppTip); // Note: *ppTip can be NULL if there is no tip
return SUCCEEDED(hr) && !*ppTip ? S_FALSE : hr;
}
HRESULT SHELL_CreateAbsolutePidl(IShellFolder *pSF, PCUIDLIST_RELATIVE pidlChild, PIDLIST_ABSOLUTE *ppPidl)
{
PIDLIST_ABSOLUTE pidlFolder;
+8
View File
@@ -255,6 +255,14 @@ HRESULT WINAPI DoRegisterServer(void);
HRESULT WINAPI DoUnregisterServer(void);
/* Property system */
static inline HRESULT
SHELL_SysAllocString(PCWSTR in, BSTR *out)
{
if (!out)
return E_INVALIDARG;
return (*out = SysAllocString(in ? in : L"")) ? S_OK : E_OUTOFMEMORY;
}
static inline HRESULT
SHELL_CreateVariantBufferEx(VARIANT *pVar, UINT cb, VARTYPE vt)
{