mirror of https://github.com/dahall/Vanara.git
BREAKING CHANGE: Fixed problems with STRRET and its use in IShellFolder::GetDisplayNameOf. #73
parent
42771630ad
commit
37b9f50288
|
@ -351,16 +351,57 @@ namespace Vanara.PInvoke
|
||||||
object GetUIObjectOf(HWND hwndOwner, uint cidl, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] IntPtr[] apidl, in Guid riid, IntPtr rgfReserved = default);
|
object GetUIObjectOf(HWND hwndOwner, uint cidl, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] IntPtr[] apidl, in Guid riid, IntPtr rgfReserved = default);
|
||||||
|
|
||||||
/// <summary>Retrieves the display name for the specified file object or subfolder.</summary>
|
/// <summary>Retrieves the display name for the specified file object or subfolder.</summary>
|
||||||
/// <param name="pidl">PIDL that uniquely identifies the file object or subfolder relative to the parent folder.</param>
|
/// <param name="pidl">
|
||||||
|
/// <para>Type: <c>PCUITEMID_CHILD</c></para>
|
||||||
|
/// <para>PIDL that uniquely identifies the file object or subfolder relative to the parent folder.</para>
|
||||||
|
/// </param>
|
||||||
/// <param name="uFlags">
|
/// <param name="uFlags">
|
||||||
|
/// <para>Type: <c>SHGDNF</c></para>
|
||||||
|
/// <para>
|
||||||
/// Flags used to request the type of display name to return. For a list of possible values, see the SHGDNF enumerated type.
|
/// Flags used to request the type of display name to return. For a list of possible values, see the SHGDNF enumerated type.
|
||||||
|
/// </para>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="pName">
|
||||||
|
/// <para>
|
||||||
|
/// When this method returns, contains the display name. The type of name returned in this structure can be the requested type,
|
||||||
|
/// but the Shell folder might return a different type.
|
||||||
|
/// </para>
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// When this method returns, contains a pointer to a STRRET structure in which to return the display name. The type of name
|
/// <para>Type: <c>HRESULT</c></para>
|
||||||
/// returned in this structure can be the requested type, but the Shell folder might return a different type.
|
/// <para>If this method succeeds, it returns <c>S_OK</c>. Otherwise, it returns an <c>HRESULT</c> error code.</para>
|
||||||
/// </returns>
|
/// </returns>
|
||||||
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(STRRETMarshaler))]
|
/// <remarks>
|
||||||
string GetDisplayNameOf([In] PIDL pidl, SHGDNF uFlags);
|
/// <para>
|
||||||
|
/// Normally, pidl can refer only to items contained by the parent folder. The PIDL must be single-level and contain exactly one
|
||||||
|
/// SHITEMID structure followed by a terminating zero. If you want to retrieve the display name of an item that is deeper than
|
||||||
|
/// one level away from the parent folder, use SHBindToParent to bind with the item's immediate parent folder and then pass the
|
||||||
|
/// item's single-level PIDL to <c>IShellFolder::GetDisplayNameOf</c>.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Also, if the SHGDN_FORPARSING flag is set in uFlags and the SHGDN_INFOLDER flag is not set, pidl can refer to an object at
|
||||||
|
/// any level below the parent folder in the namespace hierarchy. At one time, pidl could be a multilevel PIDL, relative to the
|
||||||
|
/// parent folder, and could contain multiple SHITEMID structures. However, this is no longer supported and pidl should now
|
||||||
|
/// refer only to a single child item.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The flags specified in uFlags are hints about the intended use of the name. They do not guarantee that IShellFolder will
|
||||||
|
/// return the requested form of the name. If that form is not available, a different one might be returned. In particular,
|
||||||
|
/// there is no guarantee that the name returned by the SHGDN_FORPARSING flag will be successfully parsed by
|
||||||
|
/// IShellFolder::ParseDisplayName. There are also some combinations of flags that might cause the <c>GetDisplayNameOf</c>/
|
||||||
|
/// <c>ParseDisplayName</c> round trip to not return the original identifier list. This occurrence is exceptional, but you
|
||||||
|
/// should check to be sure.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// <c>Note</c> The parsing name that is returned when uFlags has the SHGDN_FORPARSING flag set is not necessarily a normal text
|
||||||
|
/// string. Virtual folders such as My Computer might return a string containing the folder object's GUID in the form
|
||||||
|
/// "::{GUID}". Developers who implement <c>IShellFolder::GetDisplayNameOf</c> are encouraged to return parse names that are as
|
||||||
|
/// close to the display names as possible, because the end user often needs to type or edit these names.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishellfolder-getdisplaynameof
|
||||||
|
// HRESULT GetDisplayNameOf( PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pName );
|
||||||
|
void GetDisplayNameOf([In] PIDL pidl, SHGDNF uFlags, out STRRET pName); //[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(STRRETMarshaler))] out string pName);
|
||||||
|
|
||||||
/// <summary>Sets the display name of a file object or subfolder, changing the item identifier in the process.</summary>
|
/// <summary>Sets the display name of a file object or subfolder, changing the item identifier in the process.</summary>
|
||||||
/// <param name="hwnd">A handle to the owner window of any dialog or message box that the client displays.</param>
|
/// <param name="hwnd">A handle to the owner window of any dialog or message box that the client displays.</param>
|
||||||
|
|
|
@ -152,9 +152,15 @@ namespace Vanara.PInvoke
|
||||||
[FieldOffset(4)]
|
[FieldOffset(4)]
|
||||||
public StrPtrAnsi cStr;
|
public StrPtrAnsi cStr;
|
||||||
|
|
||||||
/// <summary>Returns a <see cref="System.String"/> that represents this instance.</summary>
|
/// <summary>Performs an implicit conversion from <see cref="STRRET"/> to <see cref="System.String"/>.</summary>
|
||||||
/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
|
/// <param name="s">The <see cref="STRRET"/> instance.</param>
|
||||||
public override string ToString() => (uType == STRRET_TYPE.STRRET_CSTR ? cStr : (uType == STRRET_TYPE.STRRET_WSTR ? pOleStr : (string)null)) ?? string.Empty;
|
/// <returns>The result of the conversion.</returns>
|
||||||
|
public static implicit operator string(in STRRET s) =>
|
||||||
|
ShlwApi.StrRetToBSTR(new PinnedObject(s), default, out var ret).Succeeded ? ret : null;
|
||||||
|
|
||||||
|
/// <summary>Returns a <see cref="string"/> that represents this instance.</summary>
|
||||||
|
/// <returns>A <see cref="string"/> that represents this instance.</returns>
|
||||||
|
public override string ToString() => (string)this ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class STRRETMarshaler : ICustomMarshaler
|
internal class STRRETMarshaler : ICustomMarshaler
|
||||||
|
@ -182,15 +188,8 @@ namespace Vanara.PInvoke
|
||||||
return sr.MarshalToPtr(Marshal.AllocCoTaskMem, out var _);
|
return sr.MarshalToPtr(Marshal.AllocCoTaskMem, out var _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object MarshalNativeToManaged(IntPtr pNativeData)
|
public object MarshalNativeToManaged(IntPtr pNativeData) =>
|
||||||
{
|
pNativeData != IntPtr.Zero && ShlwApi.StrRetToBSTR(pNativeData, default, out var ret).Succeeded ? ret : null;
|
||||||
if (pNativeData == IntPtr.Zero) return null;
|
|
||||||
var sr = pNativeData.ToStructure<STRRET>();
|
|
||||||
var s = sr.ToString().Clone() as string;
|
|
||||||
if (sr.uType == STRRET_TYPE.STRRET_WSTR)
|
|
||||||
sr.pOleStr.Free();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using static Vanara.PInvoke.Shell32;
|
using static Vanara.PInvoke.Shell32;
|
||||||
|
|
||||||
namespace Vanara.PInvoke.Tests
|
namespace Vanara.PInvoke.Tests
|
||||||
|
@ -35,6 +37,22 @@ namespace Vanara.PInvoke.Tests
|
||||||
//Assert.That(AssocGetDetailsOfPropKey(), Is.Zero);
|
//Assert.That(AssocGetDetailsOfPropKey(), Is.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SHGetDesktopFolderTest()
|
||||||
|
{
|
||||||
|
Assert.That(SHGetDesktopFolder(out var sf), ResultIs.Successful);
|
||||||
|
var eo = sf.EnumObjects(HWND.NULL, SHCONTF.SHCONTF_NONFOLDERS);
|
||||||
|
Assert.That(eo, Is.Not.Null);
|
||||||
|
foreach (var sub in new Collections.IEnumFromNext<IntPtr>((out IntPtr p) => eo.Next(1, out p, out var f).Succeeded && f == 1, () => { try { eo.Reset(); } catch { } }))
|
||||||
|
{
|
||||||
|
STRRET name = default;
|
||||||
|
Assert.That(() => sf.GetDisplayNameOf(sub, SHGDNF.SHGDN_NORMAL | SHGDNF.SHGDN_INFOLDER, out name), Throws.Nothing);
|
||||||
|
TestContext.WriteLine(name);
|
||||||
|
}
|
||||||
|
Marshal.ReleaseComObject(eo);
|
||||||
|
Marshal.ReleaseComObject(sf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AssocCreateForClasses
|
AssocCreateForClasses
|
||||||
AssocGetDetailsOfPropKey
|
AssocGetDetailsOfPropKey
|
||||||
|
@ -136,7 +154,6 @@ namespace Vanara.PInvoke.Tests
|
||||||
SHFreeNameMappings
|
SHFreeNameMappings
|
||||||
SHGetAttributesFromDataObject
|
SHGetAttributesFromDataObject
|
||||||
SHGetDataFromIDList
|
SHGetDataFromIDList
|
||||||
SHGetDesktopFolder
|
|
||||||
SHGetDiskFreeSpaceA
|
SHGetDiskFreeSpaceA
|
||||||
SHGetDiskFreeSpaceEx
|
SHGetDiskFreeSpaceEx
|
||||||
SHGetDiskFreeSpaceW
|
SHGetDiskFreeSpaceW
|
||||||
|
|
Loading…
Reference in New Issue