Fixes to ShellUtil based on testing

pull/187/head
dahall 2020-12-03 22:22:38 -07:00
parent 3aa3f9223d
commit 81ff24990c
2 changed files with 255 additions and 45 deletions

View File

@ -69,6 +69,11 @@ namespace Vanara.PInvoke
return GetKnownFolderFromGuid(ikfm.FindFolderFromPath(path, FFFP_MODE.FFFP_EXACTMATCH).GetId());
}
/// <summary>Gets the parent and item for the supplied IShellItem regardless of support by IShellItem.</summary>
/// <param name="psi">The IShellItem instance.</param>
/// <returns>An IParentAndItem reference for the shell item.</returns>
public static IParentAndItem GetParentAndItem(IShellItem psi) => psi is IParentAndItem pi ? pi : new ManualParentAndItem(psi);
/// <summary>Gets the path for a KNOWNFOLDERID Guid.</summary>
/// <param name="knownFolder">The KNOWNFOLDERID Guid.</param>
/// <returns>The file system path.</returns>
@ -126,8 +131,8 @@ namespace Vanara.PInvoke
/// <summary>Gets the icon for the item using the specified characteristics.</summary>
/// <param name="psf">The IShellFolder from which to request the IExtractIcon instance.</param>
/// <param name="pidl">The PIDL of the item within <paramref name="psf"/>.</param>
/// <param name="width">The width, in pixels, of the icon.</param>
/// <param name="hbmp">The resulting icon handle, on success, or <c>null</c> on failure.</param>
/// <param name="imgSz">The width, in pixels, of the icon.</param>
/// <param name="hico">The resulting icon handle, on success, or <c>null</c> on failure.</param>
/// <returns>The result of function.</returns>
public static HRESULT LoadIconFromExtractIcon(IShellFolder psf, PIDL pidl, ref uint imgSz, out SafeHICON hico)
{
@ -160,13 +165,13 @@ namespace Vanara.PInvoke
/// <summary>Gets the icon for the item using the specified characteristics.</summary>
/// <param name="iei">The IExtractIconW from which to retrieve the icon.</param>
/// <param name="width">The width, in pixels, of the icon.</param>
/// <param name="hbmp">The resulting icon handle, on success, or <c>null</c> on failure.</param>
/// <param name="imgSz">The width, in pixels, of the icon.</param>
/// <param name="hico">The resulting icon handle, on success, or <c>null</c> on failure.</param>
/// <returns>The result of function.</returns>
public static HRESULT LoadIconFromExtractIcon(IExtractIconW iei, ref uint imgSz, out SafeHICON hico)
{
var szIconFile = new StringBuilder(Kernel32.MAX_PATH);
var hr = iei.GetIconLocation(GetIconLocationFlags.GIL_FORSHELL, szIconFile, szIconFile.Capacity, out var iIdx, out var flags);
var hr = iei.GetIconLocation(GetIconLocationFlags.GIL_FORSHELL, szIconFile, szIconFile.Capacity, out var iIdx, out _);
if (hr.Succeeded)
{
if (szIconFile.ToString() != "*")
@ -187,7 +192,7 @@ namespace Vanara.PInvoke
public static HRESULT LoadIconFromExtractIcon(IExtractIconA iei, ref uint imgSz, out SafeHICON hico)
{
var szIconFile = new StringBuilder(Kernel32.MAX_PATH);
var hr = iei.GetIconLocation(GetIconLocationFlags.GIL_FORSHELL, szIconFile, szIconFile.Capacity, out var iIdx, out var flags);
var hr = iei.GetIconLocation(GetIconLocationFlags.GIL_FORSHELL, szIconFile, szIconFile.Capacity, out var iIdx, out _);
if (hr.Succeeded)
{
if (szIconFile.ToString() != "*")
@ -217,7 +222,7 @@ namespace Vanara.PInvoke
if (GetIconInfo(hico, icoInfo))
imgSz = (uint)GetObject<BITMAP>(icoInfo.hbmColor).bmWidth;
}
catch (System.Runtime.InteropServices.COMException e)
catch (COMException e)
{
hico = null;
return (HRESULT)e.ErrorCode;
@ -232,6 +237,35 @@ namespace Vanara.PInvoke
return hr;
}
/// <summary>Gets the image for the item using the specified characteristics.</summary>
/// <param name="psf">The IShellFolder from which to request the IExtractImage instance.</param>
/// <param name="pidl">The PIDL of the item within <paramref name="psf"/>.</param>
/// <param name="imgSz">The width, in pixels, of the Bitmap.</param>
/// <param name="hbmp">The resulting Bitmap, on success, or <c>null</c> on failure.</param>
/// <returns>The result of function.</returns>
public static HRESULT LoadImageFromExtractImage(IShellFolder psf, PIDL pidl, ref uint imgSz, out SafeHBITMAP hbmp)
{
HRESULT hr = psf.GetUIObjectOf<IExtractImage>((IntPtr)pidl, out var iei);
hbmp = default;
if (hr.Succeeded)
{
try
{
var szIconFile = new StringBuilder(Kernel32.MAX_PATH);
var sz = new SIZE((int)imgSz, (int)imgSz);
IEIFLAG flags = 0;
if ((hr = iei.GetLocation(szIconFile, (uint)szIconFile.Capacity, default, ref sz, 0, ref flags)).Succeeded && (hr = iei.Extract(out hbmp)).Succeeded)
imgSz = (uint)sz.cx;
return hr;
}
finally
{
Marshal.ReleaseComObject(iei);
}
}
return hr;
}
/// <summary>Gets the thumbnail image for the item using the specified characteristics.</summary>
/// <param name="psi">The IShellItem from which to request the IThumbnailProvider instance.</param>
/// <param name="imgSz">The width, in pixels, of the Bitmap.</param>
@ -241,13 +275,13 @@ namespace Vanara.PInvoke
{
try
{
var itp = psi.BindToHandler<IThumbnailProvider>(ShellUtil.CreateBindCtx(), BHID.BHID_ThumbnailHandler);
var itp = psi.BindToHandler<IThumbnailProvider>(null, BHID.BHID_ThumbnailHandler);
return LoadImageFromThumbnailProvider(itp, ref imgSz, out hbmp);
}
catch (System.Runtime.InteropServices.COMException e)
catch (COMException e)
{
hbmp = null;
return (HRESULT)e.ErrorCode;
return e.ErrorCode;
}
}
@ -287,35 +321,6 @@ namespace Vanara.PInvoke
}
}
/// <summary>Gets the image for the item using the specified characteristics.</summary>
/// <param name="psf">The IShellFolder from which to request the IExtractImage instance.</param>
/// <param name="pidl">The PIDL of the item within <paramref name="psf"/>.</param>
/// <param name="width">The width, in pixels, of the Bitmap.</param>
/// <param name="hbmp">The resulting Bitmap, on success, or <c>null</c> on failure.</param>
/// <returns>The result of function.</returns>
public static HRESULT LoadImageFromExtractImage(IShellFolder psf, PIDL pidl, ref uint imgSz, out SafeHBITMAP hbmp)
{
HRESULT hr = psf.GetUIObjectOf<IExtractImage>((IntPtr)pidl, out var iei);
hbmp = default;
if (hr.Succeeded)
{
try
{
var szIconFile = new StringBuilder(Kernel32.MAX_PATH);
var sz = new SIZE((int)imgSz, (int)imgSz);
IEIFLAG flags = 0;
if ((hr = iei.GetLocation(szIconFile, (uint)szIconFile.Capacity, default, ref sz, 0, ref flags)).Succeeded && (hr = iei.Extract(out hbmp)).Succeeded)
imgSz = (uint)sz.cx;
return hr;
}
finally
{
Marshal.ReleaseComObject(iei);
}
}
return hr;
}
/// <summary>Given a pixel size, return the ShellImageSize value with the closest size.</summary>
/// <param name="pixels">Size, in pixels, of the image list size to search for.</param>
/// <returns>An image list size.</returns>
@ -358,11 +363,19 @@ namespace Vanara.PInvoke
private WIN32_FIND_DATA fd;
private long fileId;
public IntFileSysBindData() { }
public IntFileSysBindData()
{
}
public HRESULT GetFileID(out long pliFileID) { pliFileID = fileId; return HRESULT.S_OK; }
public HRESULT GetFileID(out long pliFileID)
{
pliFileID = fileId; return HRESULT.S_OK;
}
public HRESULT GetFindData(out WIN32_FIND_DATA pfd) { pfd = fd; return HRESULT.S_OK; }
public HRESULT GetFindData(out WIN32_FIND_DATA pfd)
{
pfd = fd; return HRESULT.S_OK;
}
public HRESULT GetJunctionCLSID(out Guid pclsid)
{
@ -375,11 +388,50 @@ namespace Vanara.PInvoke
return HRESULT.E_FAIL;
}
public HRESULT SetFileID(long liFileID) { fileId = liFileID; return HRESULT.S_OK; }
public HRESULT SetFileID(long liFileID)
{
fileId = liFileID; return HRESULT.S_OK;
}
public HRESULT SetFindData(in WIN32_FIND_DATA pfd) { fd = pfd; return HRESULT.S_OK; }
public HRESULT SetFindData(in WIN32_FIND_DATA pfd)
{
fd = pfd; return HRESULT.S_OK;
}
public HRESULT SetJunctionCLSID(in Guid clsid) { clsidJunction = clsid; return HRESULT.S_OK; }
public HRESULT SetJunctionCLSID(in Guid clsid)
{
clsidJunction = clsid; return HRESULT.S_OK;
}
}
private class ManualParentAndItem : IParentAndItem, IDisposable
{
private readonly PIDL pChild;
private readonly IShellFolder psf;
public ManualParentAndItem(IShellItem psi)
{
psf = psi.BindToHandler<IShellFolder>(null, BHID.BHID_SFObject);
SHGetIDListFromObject(psi, out var pItem).ThrowIfFailed();
pChild = pItem.LastId;
pItem.Dispose();
}
void IDisposable.Dispose()
{
Marshal.ReleaseComObject(psf);
pChild.Dispose();
}
HRESULT IParentAndItem.GetParentAndItem(out PIDL ppidlParent, out IShellFolder ppsf, out PIDL ppidlChild)
{
SHGetIDListFromObject(psf, out ppidlParent).ThrowIfFailed();
ppsf = psf;
ppidlChild = new PIDL(pChild.GetBytes());
return HRESULT.S_OK;
}
HRESULT IParentAndItem.SetParentAndItem([In] PIDL pidlParent, [In] IShellFolder psf, [In] PIDL pidlChild) => HRESULT.E_NOTIMPL;
}
}
}

View File

@ -0,0 +1,158 @@
using NUnit.Framework;
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Vanara.InteropServices;
using static Vanara.PInvoke.Shell32;
using static Vanara.PInvoke.Shell32.ShellUtil;
namespace Vanara.PInvoke.Tests
{
[TestFixture()]
public class ShellUtilTests
{
[Test]
public void GetKnownFolderFromGuidTest()
{
const KNOWNFOLDERID id = KNOWNFOLDERID.FOLDERID_Desktop;
Assert.That(GetKnownFolderFromGuid(id.Guid()), Is.EqualTo(id));
}
[Test]
public void GetKnownFolderFromPathTest()
{
const KNOWNFOLDERID id = KNOWNFOLDERID.FOLDERID_Desktop;
Assert.That(GetKnownFolderFromPath(id.FullPath()), Is.EqualTo(id));
}
[Test]
public void GetPathForKnownFolderTest()
{
const KNOWNFOLDERID id = KNOWNFOLDERID.FOLDERID_Desktop;
Assert.That(GetPathForKnownFolder(id.Guid()), Is.EqualTo(id.FullPath()));
}
[Test]
public void GetPathFromShellItemTest()
{
IShellItem shi = null;
Assert.That(() => shi = GetShellItemForPath(TestCaseSources.SmallFile), Throws.Nothing);
try
{
Assert.NotNull(shi);
Assert.AreEqual(GetPathFromShellItem(shi), TestCaseSources.SmallFile);
}
finally
{
Marshal.ReleaseComObject(shi);
}
}
[Test]
public void SHILPixelConvTest()
{
Assert.That(SHILToPixels(SHIL.SHIL_SMALL), Is.EqualTo(16));
Assert.That(SHILToPixels(SHIL.SHIL_LARGE), Is.EqualTo(32));
Assert.That(SHILToPixels(SHIL.SHIL_EXTRALARGE), Is.EqualTo(48));
Assert.That(SHILToPixels(SHIL.SHIL_JUMBO), Is.EqualTo(256));
Assert.That(PixelsToSHIL(16), Is.EqualTo(SHIL.SHIL_SMALL).Or.EqualTo(SHIL.SHIL_SYSSMALL));
Assert.That(PixelsToSHIL(32), Is.EqualTo(SHIL.SHIL_LARGE));
Assert.That(PixelsToSHIL(48), Is.EqualTo(SHIL.SHIL_EXTRALARGE));
Assert.That(PixelsToSHIL(256), Is.EqualTo(SHIL.SHIL_JUMBO));
}
[Test]
public void LoadIconFromExtractIconTest()
{
IShellItem shi = null;
Assert.That(() => shi = GetShellItemForPath(TestCaseSources.WordDoc), Throws.Nothing);
try
{
var pi = GetParentAndItem(shi);
pi.GetParentAndItem(out _, out var psf, out var pChild);
uint sz = 32;
Assert.That(LoadIconFromExtractIcon(psf, pChild, ref sz, out var hIcon), ResultIs.Successful);
Assert.IsFalse(hIcon.IsInvalid);
Assert.That(sz, Is.EqualTo(32));
hIcon.Dispose();
}
finally
{
Marshal.ReleaseComObject(shi);
}
}
[Test]
public void LoadImageFromExtractImageTest()
{
IShellItem shi = null;
Assert.That(() => shi = GetShellItemForPath(TestCaseSources.ImageFile), Throws.Nothing);
try
{
var pi = GetParentAndItem(shi);
pi.GetParentAndItem(out _, out var psf, out var pChild);
uint sz = 32;
Assert.That(LoadImageFromExtractImage(psf, pChild, ref sz, out var hBmp), ResultIs.Successful);
Assert.IsFalse(hBmp.IsInvalid);
Assert.That(sz, Is.EqualTo(32));
hBmp.Dispose();
}
finally
{
Marshal.ReleaseComObject(shi);
}
}
[Test]
public void LoadImageFromThumbnailProviderTest()
{
IShellItem shi = null;
Assert.That(() => shi = GetShellItemForPath(TestCaseSources.ImageFile), Throws.Nothing);
try
{
uint sz = 32;
Assert.That(LoadImageFromThumbnailProvider(shi, ref sz, out var hBmp), ResultIs.Successful);
Assert.IsFalse(hBmp.IsInvalid);
Assert.That(sz, Is.EqualTo(32));
hBmp.Dispose();
}
finally
{
Marshal.ReleaseComObject(shi);
}
}
[Test]
public void LoadImageFromThumbnailProviderTest2()
{
IShellItem shi = null;
Assert.That(() => shi = GetShellItemForPath(TestCaseSources.ImageFile), Throws.Nothing);
try
{
var pi = GetParentAndItem(shi);
pi.GetParentAndItem(out _, out var psf, out var pChild);
uint sz = 32;
Assert.That(LoadImageFromThumbnailProvider(psf, pChild, ref sz, out var hBmp), ResultIs.Successful);
Assert.IsFalse(hBmp.IsInvalid);
Assert.That(sz, Is.EqualTo(32));
hBmp.Dispose();
}
finally
{
Marshal.ReleaseComObject(shi);
}
}
[Test]
public void LoadIconFromSystemImageListTest()
{
uint sz = 32;
Assert.That(LoadIconFromSystemImageList(2, ref sz, out var hIcon), ResultIs.Successful);
Assert.IsFalse(hIcon.IsInvalid);
Assert.That(sz, Is.EqualTo(32));
hIcon.Dispose();
}
}
}