mirror of https://github.com/dahall/Vanara.git
178 lines
6.1 KiB
C#
178 lines
6.1 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using Vanara.Extensions;
|
|
|
|
//using static Vanara.Shell32.PIDLUtil;
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
namespace Vanara.PInvoke
|
|
{
|
|
public static partial class Shell32
|
|
{
|
|
/// <summary>
|
|
/// Utilities to work with <see cref="PIDL"/> and raw ITEMIDLIST pointers.
|
|
/// </summary>
|
|
public static class PIDLUtil
|
|
{
|
|
/// <summary>Clones an ITEMIDLIST structure</summary>
|
|
public static PIDL ILClone(IntPtr pidl) => new PIDL(IntILClone(pidl));
|
|
|
|
/// <summary>
|
|
/// Clones the first SHITEMID structure in an ITEMIDLIST structure
|
|
/// </summary>
|
|
/// <param name="pidl">A pointer to the ITEMIDLIST structure that you want to clone.</param>
|
|
/// <returns>A pointer to an ITEMIDLIST structure that contains the first SHITEMID structure from the ITEMIDLIST structure specified by pidl. Returns NULL on failure.</returns>
|
|
public static PIDL ILCloneFirst(IntPtr pidl)
|
|
{
|
|
var size = ItemIdSize(pidl);
|
|
|
|
var bytes = new byte[size + 2];
|
|
Marshal.Copy(pidl, bytes, 0, size);
|
|
|
|
var newPidl = Marshal.AllocCoTaskMem(size + 2);
|
|
Marshal.Copy(bytes, 0, newPidl, size + 2);
|
|
|
|
return new PIDL(newPidl);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Combines two ITEMIDLIST structures.
|
|
/// </summary>
|
|
/// <param name="pidl1">A pointer to the first ITEMIDLIST structure.</param>
|
|
/// <param name="pidl2">A pointer to the second ITEMIDLIST structure. This structure is appended to the structure pointed to by pidl1.</param>
|
|
/// <returns>Returns an ITEMIDLIST containing the combined structures. If you set either pidl1 or pidl2 to NULL, the returned ITEMIDLIST structure is a clone of the non-NULL parameter. Returns NULL if pidl1 and pidl2 are both set to NULL.</returns>
|
|
public static PIDL ILCombine(IntPtr pidl1, IntPtr pidl2) => new PIDL(IntILCombine(pidl1, pidl2));
|
|
|
|
/// <summary>
|
|
/// Returns a pointer to the last SHITEMID structure in an ITEMIDLIST structure
|
|
/// </summary>
|
|
/// <param name="pidl">A pointer to an ITEMIDLIST structure.</param>
|
|
/// <returns>A pointer to the last SHITEMID structure in pidl.</returns>
|
|
public static IntPtr ILFindLastId(IntPtr pidl)
|
|
{
|
|
var ptr1 = pidl;
|
|
var ptr2 = ILGetNext(ptr1);
|
|
|
|
while (ItemIdSize(ptr2) > 0)
|
|
{
|
|
ptr1 = ptr2;
|
|
ptr2 = ILGetNext(ptr1);
|
|
}
|
|
|
|
return ptr1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the next SHITEMID structure in an ITEMIDLIST structure
|
|
/// </summary>
|
|
/// <param name="pidl">A pointer to a particular SHITEMID structure in a larger ITEMIDLIST structure.</param>
|
|
/// <returns>Returns a pointer to the SHITEMID structure that follows the one specified by pidl. Returns NULL if pidl points to the last SHITEMID structure.</returns>
|
|
public static IntPtr ILGetNext(IntPtr pidl)
|
|
{
|
|
var size = ItemIdSize(pidl);
|
|
return size == 0 ? IntPtr.Zero : pidl.Offset(size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes the last SHITEMID structure from an ITEMIDLIST structure
|
|
/// </summary>
|
|
/// <param name="pidl">A pointer to the ITEMIDLIST structure to be shortened. When the function returns, this variable points to the shortened structure.</param>
|
|
/// <returns>Returns TRUE if successful, FALSE otherwise.</returns>
|
|
public static bool ILRemoveLastId(IntPtr pidl)
|
|
{
|
|
var lastPidl = ILFindLastId(pidl);
|
|
|
|
if (lastPidl == pidl) return false;
|
|
|
|
var newSize = (int)lastPidl - (int)pidl + 2;
|
|
Marshal.ReAllocCoTaskMem(pidl, newSize);
|
|
Marshal.Copy(new byte[] { 0, 0 }, 0, pidl.Offset(newSize - 2), 2);
|
|
return true;
|
|
}
|
|
|
|
/// <summary>Determines whether the specified ITEMIDLIST has no children.</summary>
|
|
/// <param name="pidl">A pointer to the ITEMIDLIST structure to be evaluated.</param>
|
|
/// <returns><c>true</c> if the specified ITEMIDLIST is empty; otherwise, <c>false</c>.</returns>
|
|
public static bool ILIsEmpty(IntPtr pidl) => ItemIdListSize(pidl) == 0;
|
|
|
|
/// <summary>
|
|
/// Separates an ITEMIDLIST into the parent SHITEMID and the children SHITEMIDs
|
|
/// </summary>
|
|
/// <param name="pidl">A pointer to the ITEMIDLIST structure to be evaluated.</param>
|
|
/// <param name="parent">The parent.</param>
|
|
/// <param name="child">The children.</param>
|
|
/// <returns>Returns TRUE if successful, FALSE otherwise.</returns>
|
|
public static bool SplitPidl(IntPtr pidl, out IntPtr parent, out IntPtr child)
|
|
{
|
|
parent = IntILClone(pidl);
|
|
child = IntILClone(ILFindLastId(pidl));
|
|
|
|
if (ILRemoveLastId(parent)) return true;
|
|
|
|
Marshal.FreeCoTaskMem(parent);
|
|
Marshal.FreeCoTaskMem(child);
|
|
return false;
|
|
}
|
|
|
|
/// <summary>Clones an ITEMIDLIST structure</summary>
|
|
internal static IntPtr IntILClone(IntPtr pidl)
|
|
{
|
|
var size = ItemIdListSize(pidl);
|
|
|
|
var bytes = new byte[size + 2];
|
|
Marshal.Copy(pidl, bytes, 0, size);
|
|
|
|
var newPidl = Marshal.AllocCoTaskMem(size + 2);
|
|
Marshal.Copy(bytes, 0, newPidl, size + 2);
|
|
|
|
return newPidl;
|
|
}
|
|
|
|
/// <summary>Combines two ITEMIDLIST structures</summary>
|
|
internal static IntPtr IntILCombine(IntPtr pidl1, IntPtr pidl2)
|
|
{
|
|
var size1 = ItemIdListSize(pidl1);
|
|
var size2 = ItemIdListSize(pidl2);
|
|
|
|
var newPidl = Marshal.AllocCoTaskMem(size1 + size2 + 2);
|
|
var bytes = new byte[size1 + size2 + 2];
|
|
|
|
Marshal.Copy(pidl1, bytes, 0, size1);
|
|
Marshal.Copy(pidl2, bytes, size1, size2);
|
|
|
|
Marshal.Copy(bytes, 0, newPidl, bytes.Length);
|
|
|
|
return newPidl;
|
|
}
|
|
|
|
/*public static void WriteBytes(IntPtr handle)
|
|
{
|
|
var size = Marshal.ReadByte(handle, 0) + Marshal.ReadByte(handle, 1)*256 - 2;
|
|
|
|
for (var i = 0; i < size; i++)
|
|
{
|
|
Console.Out.WriteLine(Marshal.ReadByte(handle, i + 2));
|
|
}
|
|
|
|
Console.Out.WriteLine(Marshal.ReadByte(handle, size + 2));
|
|
Console.Out.WriteLine(Marshal.ReadByte(handle, size + 3));
|
|
}*/
|
|
|
|
internal static int ItemIdListSize(IntPtr handle)
|
|
{
|
|
if (handle.Equals(IntPtr.Zero))
|
|
return 0;
|
|
var size = ItemIdSize(handle);
|
|
var nextSize = Marshal.ReadInt16(handle, size);
|
|
while (nextSize > 0)
|
|
{
|
|
size += nextSize;
|
|
nextSize = Marshal.ReadInt16(handle, size);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
internal static int ItemIdSize(IntPtr handle) => handle.Equals(IntPtr.Zero) ? 0 : Marshal.ReadInt16(handle);
|
|
}
|
|
}
|
|
} |