Created
February 16, 2024 10:31
-
-
Save latop2604/73bd7d8008e7ed925f5713fda9201ced to your computer and use it in GitHub Desktop.
Jumplist Native AOT Net8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Runtime.InteropServices.Marshalling; | |
using System.Runtime.Versioning; | |
using JumpListsAOT.Nati; | |
namespace JumpListsAOT; | |
[SupportedOSPlatform("windows")] | |
internal class JumpLists | |
{ | |
public static void Init() | |
{ | |
var targetExe = Path.Combine(AppContext.BaseDirectory, "JumpLists.exe"); | |
var profilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); | |
var dir = new DirectoryInfo(profilePath); | |
var files = ["fileA", "fileB", "fileB"]; | |
try | |
{ | |
ComWrappers cw = new StrategyBasedComWrappers(); | |
var cdl = ActivateClass<ICustomDestinationList>( | |
cw, | |
new Guid("77f10cf0-3db5-4966-b520-b7c54fd35ed6"), | |
new Guid("6332debf-87b5-4670-90c0-5e57b408a49e")); | |
var obj = cdl.BeginList(out uint pcMinSlots, typeof(IObjectArray).GUID); | |
var objArray = (IObjectArray)obj; | |
var removedObjs = ToArray<object>(cw, objArray); | |
var exceptions = new System.Collections.Generic.List<Exception>(); | |
var poc = ActivateClass<IObjectCollection>( | |
cw, | |
new Guid("2d3468c1-36a7-43b6-ac24-d3f02fd9607a"), | |
new Guid("5632b1a4-e38a-400a-928a-d4cd63230295")); | |
//var count = poc.GetCount(); | |
foreach (var profile in files) | |
{ | |
var psho = CreateTaskListShellObject(cw, profile, targetExe); | |
//if (!IsRemoved(psho.Item)) | |
poc.AddObject(psho); | |
} | |
//var pocCount = poc.GetCount(); | |
cdl.AddUserTasks(poc); | |
cdl.CommitList(); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine(ex.ToString()); | |
} | |
} | |
public static I ActivateClass<I>(ComWrappers cw, Guid clsid, Guid iid) | |
{ | |
Debug.Assert(iid == typeof(I).GUID); | |
int hr = NativeMethod.CoCreateInstance(ref clsid, IntPtr.Zero, /*CLSCTX_INPROC_SERVER*/ 1, ref iid, out IntPtr obj); | |
if (hr < 0) | |
{ | |
Marshal.ThrowExceptionForHR(hr); | |
} | |
return (I)cw.GetOrCreateObjectForComInstance(obj, CreateObjectFlags.None); | |
} | |
public static T[] ToArray<T>(ComWrappers cw, IObjectArray a) where T : class | |
{ | |
const string IID_IUnknown = "00000000-0000-0000-C000-000000000046"; | |
var gIUnk = typeof(T) == typeof(object) ? new Guid(IID_IUnknown) : typeof(T).GUID; | |
var c = a.GetCount(); | |
var ret = new T[c]; | |
for (var i = 0U; i < c; i++) | |
{ | |
var ppvObject = a.GetAt(i, gIUnk); | |
ret[i] = (T)ppvObject; | |
} | |
return ret; | |
} | |
public static IShellLinkW CreateTaskListShellObject(ComWrappers cw, string? profile, string targetExe) | |
{ | |
var link = ActivateClass<IShellLinkW>( | |
cw, | |
new Guid("00021401-0000-0000-C000-000000000046"), | |
new Guid("000214F9-0000-0000-C000-000000000046")); | |
link.SetPath(targetExe); | |
//if (!string.IsNullOrEmpty(AppUserModelID)) | |
// (link as IPropertyStore)?.SetValue(PROPERTYKEY.System.AppUserModel.ID, AppUserModelID); | |
//if (!string.IsNullOrEmpty(WorkingDirectory)) | |
// link.SetWorkingDirectory(WorkingDirectory); | |
if (!string.IsNullOrEmpty(profile)) | |
link.SetArguments(profile); | |
// -1 is a sentinel value indicating not to use the icon. | |
//if (IconResourceIndex != -1) | |
//link.SetIconLocation(IconResourcePath ?? ApplicationPath, IconResourceIndex); | |
//if (!string.IsNullOrEmpty(Description)) | |
link.SetDescription($"Open with profile {profile ?? "Default"}"); | |
//if (!string.IsNullOrEmpty(profile ?? "Default")) | |
var pv = new PROPVARIANT(profile ?? "Default"); | |
(link as IPropertyStore)?.SetValue(PROPERTYKEY.System.Title, pv); | |
NativeMethod.PropVariantClear(ref pv); | |
return link; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// <AllowUnsafeBlocks>true</AllowUnsafeBlocks> required in csproj | |
// Based on https://github.com/dahall/Vanara/blob/master/Windows.Shell.Common/TaskBar/JumpList.cs | |
// And https://github.com/jlnewton87/Programming/blob/master/C%23/Windows%20API%20Code%20Pack%201.1/source/WindowsAPICodePack/Core/PropertySystem/PropVariant.cs | |
using System; | |
using System.Runtime.InteropServices; | |
using System.Runtime.InteropServices.Marshalling; | |
using System.Runtime.Versioning; | |
[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling] | |
namespace JumpListsAOT.Nati; | |
[SupportedOSPlatform("windows")] | |
public static partial class NativeMethod | |
{ | |
[LibraryImport("Ole32")] | |
internal static partial int CoCreateInstance( | |
ref Guid rclsid, | |
IntPtr pUnkOuter, | |
int dwClsContext, | |
ref Guid riid, | |
out IntPtr ppObj); | |
[LibraryImport("Ole32")] // returns hresult | |
internal static partial int PropVariantClear(ref PROPVARIANT pvar); | |
} | |
/// <summary> | |
/// Exposes methods that allow an application to provide a custom Jump List, including destinations and tasks, for display in the taskbar. | |
/// </summary> | |
//[SuppressUnmanagedCodeSecurity] | |
//[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("6332debf-87b5-4670-90c0-5e57b408a49e"), CoClass(typeof(CDestinationList))] | |
//[PInvokeData("Shobjidl.h", MSDNShortId = "dd378402")] | |
[GeneratedComInterface] | |
[Guid("6332debf-87b5-4670-90c0-5e57b408a49e")] | |
public partial interface ICustomDestinationList | |
{ | |
/// <summary> | |
/// Specifies a unique Application User Model ID (AppUserModelID) for the application whose taskbar button will hold the custom | |
/// Jump List built through the methods of this interface. This method is optional. | |
/// </summary> | |
/// <param name="pszAppID"> | |
/// A pointer to the AppUserModelID of the process or application whose taskbar representation receives the Jump List. | |
/// </param> | |
void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); | |
/// <summary>Initiates a building session for a custom Jump List.</summary> | |
/// <param name="pcMaxSlots"> | |
/// A pointer that, when this method returns, points to the current user setting for the Number of recent items to display in | |
/// Jump Lists option in the Taskbar and Start Menu Properties window. The default value is 10. This is the maximum number of | |
/// destinations that will be shown, and it is a total of all destinations, regardless of category. More destinations can be | |
/// added, but they will not be shown in the UI. | |
/// <para>A Jump List will always show at least this many slots—destinations and, if there is room, tasks.</para> | |
/// <para> | |
/// This number does not include separators and section headers as long as the total number of separators and headers does not | |
/// exceed four. Separators and section headers beyond the first four might reduce the number of destinations displayed if space | |
/// is constrained. This number does not affect the standard command entries for pinning or unpinning, closing the window, or | |
/// launching a new instance. It also does not affect tasks or pinned items, the number of which that can be displayed is based | |
/// on the space available to the Jump List. | |
/// </para> | |
/// </param> | |
/// <param name="riid"> | |
/// A reference to the IID of an interface to be retrieved in ppv, typically IID_IObjectArray, that will represent all items | |
/// currently stored in the list of removed destinations for the application. This information is used to ensure that removed | |
/// items are not part of the new Jump List. | |
/// </param> | |
/// <returns> | |
/// When this method returns, contains the interface pointer requested in riid. This is typically an IObjectArray, which | |
/// represents a collection of IShellItem and IShellLink objects that represent the removed items. | |
/// </returns> | |
[return: MarshalAs(UnmanagedType.Interface)] | |
object BeginList(out uint pcMaxSlots, in Guid riid); | |
/// <summary>Defines a custom category and the destinations that it contains, for inclusion in a custom Jump List.</summary> | |
/// <param name="pszCategory"> | |
/// A pointer to a string that contains the display name of the custom category. This string is shown in the category's header in | |
/// the Jump List. The string can directly hold the display name or it can be an indirect string representation, such as | |
/// "@shell32.dll,-1324", to use a stored string. An indirect string enables the category header to be displayed in the user's | |
/// selected language. <note>Each custom category must have a unique name. Duplicate category names will cause presentation | |
/// issues in the Jump List.</note> | |
/// </param> | |
/// <param name="poa"> | |
/// A pointer to an IObjectArray that represents one or more IShellItem objects that represent the destinations in the category. | |
/// Some destinations in the list might also be represented by IShellLink objects, although less often. <note>Any IShellLink used | |
/// here must declare an argument list through SetArguments. Adding an IShellLink object with no arguments to a custom category | |
/// is not supported since a user cannot pin or unpin this type of item from a Jump List, nor can they be added or removed.</note> | |
/// </param> | |
void AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, IObjectArray poa); | |
/// <summary>Specifies that the Frequent or Recent category should be included in a custom Jump List.</summary> | |
/// <param name="category">One of the KNOWNDESTCATEGORY values that indicate which known category to add to the list.</param> | |
void AppendKnownCategory(KNOWNDESTCATEGORY category); | |
/// <summary>Specifies items to include in the Tasks category of a custom Jump List.</summary> | |
/// <param name="poa"> | |
/// A pointer to an IObjectArray that represents one or more IShellLink (or, more rarely, IShellItem) objects that represent the | |
/// tasks. <note>Any IShellLink used here must declare an argument list through SetArguments. Adding an IShellLink object with no | |
/// arguments to a custom category is not supported. A user cannot pin or unpin this type of item from a Jump List, nor can they | |
/// be added or removed.</note> | |
/// </param> | |
void AddUserTasks(IObjectArray poa); | |
/// <summary> | |
/// Declares that the Jump List initiated by a call to ICustomDestinationList::BeginList is complete and ready for display. | |
/// </summary> | |
void CommitList(); | |
/// <summary> | |
/// Retrieves the current list of destinations that have been removed by the user from the existing Jump List that this custom | |
/// Jump List is meant to replace. | |
/// </summary> | |
/// <param name="riid">A reference to the IID of the interface to retrieve through ppv, typically IID_IObjectArray.</param> | |
/// <returns> | |
/// When this method returns, contains the interface pointer requested in riid. This is typically an IObjectArray, which | |
/// represents a collection of IShellItem or IShellLink objects that represent the items in the list of removed destinations. | |
/// </returns> | |
[return: MarshalAs(UnmanagedType.Interface)] | |
object GetRemovedDestinations(in Guid riid); | |
/// <summary>Deletes a custom Jump List for a specified application.</summary> | |
/// <param name="pszAppID"> | |
/// A pointer to the AppUserModelID of the process whose taskbar button representation displays the custom Jump List. In the beta | |
/// release of Windows 7, this AppUserModelID must be explicitly provided because this method is intended to be called from an | |
/// uninstaller, which runs in a separate process. Because it is in a separate process, the system cannot reliably deduce the | |
/// AppUserModelID. This restriction is expected to be removed in later releases. | |
/// </param> | |
void DeleteList([Optional, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); | |
/// <summary> | |
/// Discontinues a Jump List building session initiated by ICustomDestinationList::BeginList without committing any changes. | |
/// </summary> | |
void AbortList(); | |
} | |
/// <summary> | |
/// <para>Exposes methods that enable clients to access items in a collection of objects that support IUnknown.</para> | |
/// </summary> | |
/// <remarks> | |
/// <para>When to Implement</para> | |
/// <para>Clients do not need to implement this interface.</para> | |
/// <para>When to Use</para> | |
/// <para>Use this interface to access generic objects in an array.</para> | |
/// </remarks> | |
// https://docs.microsoft.com/en-us/windows/desktop/api/objectarray/nn-objectarray-iobjectarray | |
//[PInvokeData("objectarray.h", MSDNShortId = "ab0bb213-dc9c-4853-98d7-668e7ca76583")] | |
//[SuppressUnmanagedCodeSecurity] | |
//[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")] | |
[GeneratedComInterface] | |
[Guid("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")] | |
public partial interface IObjectArray | |
{ | |
/// <summary>Provides a count of the objects in the collection.</summary> | |
/// <returns>The number of objects in the collection.</returns> | |
uint GetCount(); | |
/// <summary> | |
/// Provides a pointer to a specified object's interface. The object and interface are specified by index and interface ID. | |
/// </summary> | |
/// <param name="uiIndex">The index of the object</param> | |
/// <param name="riid">Reference to the desired interface ID.</param> | |
/// <returns>Receives the interface pointer requested in riid.</returns> | |
[return: MarshalAs(UnmanagedType.Interface)] | |
object GetAt(uint uiIndex, in Guid riid); | |
} | |
/// <summary> | |
/// <para> | |
/// Extends the IObjectArray interface by providing methods that enable clients to add and remove objects that support IUnknown in a collection. | |
/// </para> | |
/// </summary> | |
/// <remarks> | |
/// <para>When to Use</para> | |
/// <para>Use this interface to interact with a collection of generic objects.</para> | |
/// </remarks> | |
// https://docs.microsoft.com/en-us/windows/desktop/api/objectarray/nn-objectarray-iobjectcollection | |
//[PInvokeData("objectarray.h", MSDNShortId = "d7665b26-5839-4b08-a099-ef25a68c65db")] | |
//[SuppressUnmanagedCodeSecurity] | |
//[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("5632b1a4-e38a-400a-928a-d4cd63230295"), CoClass(typeof(CEnumerableObjectCollection))] | |
[GeneratedComInterface] | |
[Guid("5632B1A4-E38A-400A-928A-D4CD63230295")] | |
public partial interface IObjectCollection : IObjectArray | |
{ | |
/// <summary>Provides a count of the objects in the collection.</summary> | |
/// <returns>The number of objects in the collection.</returns> | |
//new uint GetCount(); | |
/// <summary> | |
/// Provides a pointer to a specified object's interface. The object and interface are specified by index and interface ID. | |
/// </summary> | |
/// <param name="uiIndex">The index of the object</param> | |
/// <param name="riid">Reference to the desired interface ID.</param> | |
/// <returns>Receives the interface pointer requested in riid.</returns> | |
//[return: MarshalAs(UnmanagedType.Interface)] | |
//new object GetAt(uint uiIndex, in Guid riid); | |
/// <summary>Adds a single object to the collection.</summary> | |
/// <param name="punk">Pointer to the IUnknown of the object to be added to the collection.</param> | |
void AddObject([MarshalAs(UnmanagedType.Interface)] object punk); | |
/// <summary>Adds the objects contained in an IObjectArray to the collection.</summary> | |
/// <param name="poaSource">Pointer to the IObjectArray whose contents are to be added to the collection.</param> | |
void AddFromArray(IObjectArray poaSource); | |
/// <summary>Removes a single, specified object from the collection.</summary> | |
/// <param name="uiIndex">A pointer to the index of the object within the collection.</param> | |
void RemoveObjectAt(uint uiIndex); | |
/// <summary>Removes all objects from the collection.</summary> | |
void Clear(); | |
} | |
/// <summary>Exposes methods that create, modify, and resolve Shell links.</summary> | |
//[SuppressUnmanagedCodeSecurity] | |
//[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046"), CoClass(typeof(CShellLinkW))] | |
//[PInvokeData("Shobjidl.h", MSDNShortId = "bb774950")] | |
[GeneratedComInterface(Options = ComInterfaceOptions.ComObjectWrapper)] | |
[Guid("000214F9-0000-0000-C000-000000000046")] | |
public partial interface IShellLinkW | |
{ | |
/// <summary>Gets the path and file name of the target of a Shell link object.</summary> | |
/// <param name="pszFile">The address of a buffer that receives the path and file name of the target of the Shell link object.</param> | |
/// <param name="cchMaxPath"> | |
/// The size, in characters, of the buffer pointed to by the pszFile parameter, including the terminating null character. The | |
/// maximum path size that can be returned is MAX_PATH. This parameter is commonly set by calling ARRAYSIZE(pszFile). The | |
/// ARRAYSIZE macro is defined in Winnt.h. | |
/// </param> | |
/// <param name="pfd"> | |
/// A pointer to a WIN32_FIND_DATA structure that receives information about the target of the Shell link object. If this | |
/// parameter is NULL, then no additional information is returned. | |
/// </param> | |
/// <param name="fFlags">Flags that specify the type of path information to retrieve.</param> | |
void GetPath([Out, MarshalAs(UnmanagedType.LPArray)] char[] pszFile, int cchMaxPath, out /*Vanara.PInvoke.WIN32_FIND_DATA*/ IntPtr pfd, /*SLGP*/uint fFlags); | |
/// <summary>Gets the list of item identifiers for the target of a Shell link object.</summary> | |
/// <returns>When this method returns, contains the address of a PIDL.</returns> | |
//Vanara.PInvoke.Shell32.PIDL GetIDList(); | |
IntPtr GetIDList(); | |
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary> | |
/// <param name="pidl">The object's fully qualified PIDL.</param> | |
//void SetIDList(PIDL pidl); | |
void SetIDList(IntPtr pidl); | |
/// <summary>Gets the description string for a Shell link object.</summary> | |
/// <param name="pszFile">A pointer to the buffer that receives the description string.</param> | |
/// <param name="cchMaxName">The maximum number of characters to copy to the buffer pointed to by the pszName parameter.</param> | |
void GetDescription([Out, MarshalAs(UnmanagedType.LPArray)] char[] pszFile, int cchMaxName); | |
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string.</summary> | |
/// <param name="pszName">A pointer to a buffer containing the new description string.</param> | |
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); | |
/// <summary>Gets the name of the working directory for a Shell link object.</summary> | |
/// <param name="pszDir">The address of a buffer that receives the name of the working directory.</param> | |
/// <param name="cchMaxPath"> | |
/// The maximum number of characters to copy to the buffer pointed to by the pszDir parameter. The name of the working directory | |
/// is truncated if it is longer than the maximum specified by this parameter. | |
/// </param> | |
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPArray)] char[] pszDir, int cchMaxPath); | |
/// <summary>Sets the name of the working directory for a Shell link object.</summary> | |
/// <param name="pszDir">The address of a buffer that contains the name of the new working directory.</param> | |
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); | |
/// <summary>Gets the command-line arguments associated with a Shell link object.</summary> | |
/// <param name="pszArgs">A pointer to the buffer that, when this method returns successfully, receives the command-line arguments.</param> | |
/// <param name="cchMaxPath"> | |
/// The maximum number of characters that can be copied to the buffer supplied by the pszArgs parameter. In the case of a Unicode | |
/// string, there is no limitation on maximum string length. In the case of an ANSI string, the maximum length of the returned | |
/// string varies depending on the version of Windows—MAX_PATH prior to Windows 2000 and INFOTIPSIZE (defined in Commctrl.h) in | |
/// Windows 2000 and later. | |
/// </param> | |
void GetArguments([Out, MarshalAs(UnmanagedType.LPArray)] char[] pszArgs, int cchMaxPath); | |
/// <summary>Sets the command-line arguments for a Shell link object.</summary> | |
/// <param name="pszArgs"> | |
/// A pointer to a buffer that contains the new command-line arguments. In the case of a Unicode string, there is no limitation | |
/// on maximum string length. In the case of an ANSI string, the maximum length of the returned string varies depending on the | |
/// version of Windows—MAX_PATH prior to Windows 2000 and INFOTIPSIZE (defined in Commctrl.h) in Windows 2000 and later. | |
/// </param> | |
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); | |
/// <summary>Gets the keyboard shortcut (hot key) for a Shell link object.</summary> | |
/// <returns> | |
/// <para> | |
/// The address of the keyboard shortcut. The virtual key code is in the low-order byte, and the modifier flags are in the | |
/// high-order byte. The modifier flags can be a combination of the following values. | |
/// </para> | |
/// <list type="table"> | |
/// <listheader> | |
/// <term>Value</term> | |
/// <term>Meaning</term> | |
/// </listheader> | |
/// <item> | |
/// <term><c>HOTKEYF_ALT</c> 0x04</term> | |
/// <term>ALT key</term> | |
/// </item> | |
/// <item> | |
/// <term><c>HOTKEYF_CONTROL</c> 0x02</term> | |
/// <term>CTRL key</term> | |
/// </item> | |
/// <item> | |
/// <term><c>HOTKEYF_EXT</c> 0x08</term> | |
/// <term>Extended key</term> | |
/// </item> | |
/// <item> | |
/// <term><c>HOTKEYF_SHIFT</c> 0x01</term> | |
/// <term>SHIFT key</term> | |
/// </item> | |
/// </list> | |
/// </returns> | |
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishelllinkw-gethotkey | |
// HRESULT GetHotkey( WORD *pwHotkey ); | |
ushort GetHotKey(); | |
/// <summary>Sets a keyboard shortcut (hot key) for a Shell link object.</summary> | |
/// <param name="wHotKey"> | |
/// The new keyboard shortcut. The virtual key code is in the low-order byte, and the modifier flags are in the high-order byte. | |
/// The modifier flags can be a combination of the values specified in the description of the IShellLink::GetHotkey method. | |
/// </param> | |
void SetHotKey(ushort wHotKey); | |
/// <summary>Gets the show command for a Shell link object.</summary> | |
/// <returns> | |
/// A pointer to the command. The following commands are supported. | |
/// <list> | |
/// <item> | |
/// <term>SW_SHOWNORMAL</term> | |
/// <description> | |
/// Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and | |
/// position. An application should specify this flag when displaying the window for the first time. | |
/// </description> | |
/// </item> | |
/// <item> | |
/// <term>SW_SHOWMAXIMIZED</term> | |
/// <description>Activates the window and displays it as a maximized window.</description> | |
/// </item> | |
/// <item> | |
/// <term>SW_SHOWMINIMIZED</term> | |
/// <description>Activates the window and displays it as a minimized window.</description> | |
/// </item> | |
/// </list> | |
/// </returns> | |
//ShowWindowCommand GetShowCmd(); | |
ShowWindowCommand GetShowCmd(); | |
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary> | |
/// <param name="iShowCmd"> | |
/// SetShowCmd accepts one of the following ShowWindow commands. | |
/// <list> | |
/// <item> | |
/// <term>SW_SHOWNORMAL</term> | |
/// <description> | |
/// Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and | |
/// position. An application should specify this flag when displaying the window for the first time. | |
/// </description> | |
/// </item> | |
/// <item> | |
/// <term>SW_SHOWMAXIMIZED</term> | |
/// <description>Activates the window and displays it as a maximized window.</description> | |
/// </item> | |
/// <item> | |
/// <term>SW_SHOWMINIMIZED</term> | |
/// <description>Activates the window and displays it as a minimized window.</description> | |
/// </item> | |
/// </list> | |
/// </param> | |
void SetShowCmd(ShowWindowCommand iShowCmd); | |
//void SetShowCmd(uint iShowCmd); | |
/// <summary>Gets the location (path and index) of the icon for a Shell link object.</summary> | |
/// <param name="pszIconPath">The address of a buffer that receives the path of the file containing the icon.</param> | |
/// <param name="cchIconPath">The maximum number of characters to copy to the buffer pointed to by the pszIconPath parameter.</param> | |
/// <param name="piIcon">The address of a value that receives the index of the icon.</param> | |
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPArray)] char[] pszIconPath, int cchIconPath, | |
out int piIcon); | |
/// <summary>Sets the location (path and index) of the icon for a Shell link object.</summary> | |
/// <param name="pszIconPath">The address of a buffer to contain the path of the file containing the icon.</param> | |
/// <param name="iIcon">The index of the icon.</param> | |
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); | |
/// <summary>Sets the relative path to the Shell link object.</summary> | |
/// <param name="pszPathRel"> | |
/// The address of a buffer that contains the fully-qualified path of the shortcut file, relative to which the shortcut | |
/// resolution should be performed. It should be a file name, not a folder name. | |
/// </param> | |
/// <param name="dwReserved">Reserved. Set this parameter to zero.</param> | |
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, [Optional] uint dwReserved); | |
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed.</summary> | |
/// <param name="hwnd"> | |
/// A handle to the window that the Shell will use as the parent for a dialog box. The Shell displays the dialog box if it needs | |
/// to prompt the user for more information while resolving a Shell link. | |
/// </param> | |
/// <param name="fFlags">Action flags.</param> | |
//void Resolve(HWND hwnd, SLR_FLAGS fFlags); | |
void Resolve(IntPtr hwnd, uint fFlags); | |
/// <summary>Sets the path and file name for the target of a Shell link object.</summary> | |
/// <param name="pszFile">The address of a buffer that contains the new path.</param> | |
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); | |
} | |
//[PInvokeData("propsys.h", MSDNShortId = "63afd5b1-87cc-4e0a-8964-2138c5fbff46")] | |
//[SuppressUnmanagedCodeSecurity] | |
//[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")] | |
[GeneratedComInterface(Options = ComInterfaceOptions.ComObjectWrapper)] | |
[Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")] | |
public partial interface IPropertyStore | |
{ | |
/// <summary>This method returns a count of the number of properties that are attached to the file.</summary> | |
/// <returns>A value that indicates the property count.</returns> | |
/// <remarks> | |
/// <para> | |
/// <c>IPropertyStore</c> provides an abstraction over an array of property keys via the and IPropertyStore::GetAt methods. The | |
/// property keys in this array represent the properties that are currently stored by the <c>IPropertyStore</c>. | |
/// </para> | |
/// <para> | |
/// When succeeds, the value pointed to by cProps is a count of property keys in the array. The caller can expect calls to | |
/// <c>IPropertyStore::GetAt</c> to succeed for values of iProp less than cProps. | |
/// </para> | |
/// <para> | |
/// In the case of failures such as E_OUTOFMEMORY, you should set cProps to zero. It is preferable that errors are discovered | |
/// during creation or initialization of the property store. | |
/// </para> | |
/// </remarks> | |
// https://docs.microsoft.com/en-us/windows/win32/api/propsys/nf-propsys-ipropertystore-getcount HRESULT GetCount( DWORD *cProps ); | |
uint GetCount(); | |
/// <summary>Gets a property key from an item's array of properties.</summary> | |
/// <param name="iProp"> | |
/// <para>[in] Type: <c>DWORD</c></para> | |
/// <para>The index of the property key in the array of <c>PROPERTYKEY</c> structures. This is a zero-based index.</para> | |
/// </param> | |
/// <returns> | |
/// <para>[out] Type: <c>PROPERTYKEY*</c></para> | |
/// <para>When this method returns, contains a <c>PROPERTYKEY</c> structure that receives the unique identifier for a property.</para> | |
/// </returns> | |
/// <remarks> | |
/// <para>The <c>PROPERTYKEY</c> returned in pkey can be used in subsequent calls to <c>IPropertyStore::GetValue</c> and <c>IPropertyStore::SetValue</c>.</para> | |
/// <para> | |
/// There is no specific order to an item's set of enumerated properties. To find a specific property, you must walk the array | |
/// until you find the property that matches your criteria. | |
/// </para> | |
/// <para> | |
/// iProp cannot be greater than or equal to the cProps parameter retrieved by <c>IPropertyStore::GetCount</c>. If it is greater | |
/// than or equal to that value, <c>IPropertyStore::GetAt</c> returns E_INVALIDARG and pkey is set to <c>NULL</c> by the | |
/// property handler. | |
/// </para> | |
/// </remarks> | |
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/bb761471(v=vs.85) HRESULT GetAt( [in] DWORD iProp, | |
// [out] PROPERTYKEY *pkey ); | |
PROPERTYKEY GetAt(uint iProp); | |
/// <summary>Gets data for a specific property.</summary> | |
/// <param name="pkey">The pkey.</param> | |
/// <param name="pv"> | |
/// <para>[out] Type: <c>PROPVARIANT*</c></para> | |
/// <para>When this method returns, contains a <c>PROPVARIANT</c> structure that contains the property data.</para> | |
/// </param> | |
/// <remarks> | |
/// <para> | |
/// If the <c>PROPERTYKEY</c> referenced in key is not present in the property store, this method returns <c>S_OK</c> and the | |
/// <c>vt</c> member of the structure pointed to by pv is set to VT_EMPTY. | |
/// </para> | |
/// <para> | |
/// File property handler implementers can use <c>IPropertyStore::GetValue</c> to retrieve the property value by using the | |
/// filestream with which <c>Initialize</c> initialized the property handler. The value can also be computed from an in-memory | |
/// cache, or other means. However, most consumers of the property system obtain <c>IPropertyStore</c> through | |
/// <c>GetPropertyStore</c> and are not—and have no need to be—aware of the method of initialization. | |
/// </para> | |
/// </remarks> | |
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/bb761473(v=vs.85) HRESULT GetValue( [in] | |
// REFPROPERTYKEY key, [out] PROPVARIANT *pv ); | |
void GetValue(in PROPERTYKEY pkey, out PROPVARIANT pv); | |
/// <summary>Sets a new property value, or replaces or removes an existing value.</summary> | |
/// <param name="pkey">The pkey.</param> | |
/// <param name="pv">The pv.</param> | |
/// <remarks> | |
/// <para> | |
/// <c>Note</c> When this method is implemented under <c>IPropertyStoreCache</c>, be aware that the interface is used only by | |
/// the in-memory store. Many of the following remarks may not apply in that case. | |
/// </para> | |
/// <para> | |
/// <c>SetValue</c> affects the current property store instance only. A property handler implements <c>SetValue</c> by | |
/// accumulating property changes in an in-memory data structure. Property changes are written to the stream only when | |
/// <c>IPropertyStore::Commit</c> is called. | |
/// </para> | |
/// <para>If <c>Commit</c> is called on a read-only property store, the property handler determines this and returns STG_E_ACCESSDENIED.</para> | |
/// <para> | |
/// In general, errors should be detected and reported by <c>SetValue</c>. However, when processing is deferred until | |
/// <c>Commit</c> is called, the same error semantics apply. | |
/// </para> | |
/// <para> | |
/// If a value was added or removed as a result of <c>SetValue</c>, subsequent enumerations by <c>IPropertyStore::GetCount</c> | |
/// and <c>IPropertyStore::GetAt</c> reflect that change and subsequent calls to <c>SetValue</c> reflect the changed value. | |
/// </para> | |
/// <para>Adding a New Property</para> | |
/// <para>If the property value pointed to by key does not exist in the store, <c>SetValue</c> adds the value to the store.</para> | |
/// <para>Replacing an Existing Property Value</para> | |
/// <para>If the property value pointed to by the key parameter already exists in the store, the stored value is replaced.</para> | |
/// <para>Removing an Existing Property</para> | |
/// <para>Removing a property values from a property store is not supported and could lead to unexpected results.</para> | |
/// <para>Support for Different Properties</para> | |
/// <para> | |
/// A property handler must handle three types of properties in <c>SetValue</c>: new properties introduced by the handler | |
/// author, pre-existing properties that are germane to the property handler, and other properties that do not fall in either of | |
/// those categories. | |
/// </para> | |
/// <list type="bullet"> | |
/// <item> | |
/// <term> | |
/// New properties introduced by the property handler author must be described in a property description XML file. Clients | |
/// consume a file property handler through a wrapping layer called the Windows Property Provider. This layer delegates calls to | |
/// <c>SetValue</c> to the property handler after it enforces restrictions on the new property according to the property | |
/// description XML. Therefore, a handler should not attempt to enforce restrictions itself and must store any values that | |
/// satisfy the property description XML. If the property description does not provide the necessary information to restrict | |
/// values for the new property, the handler must alter the value as necessary to store those values successfully. For example, | |
/// in the property description XML there is no way to specify that an integer-valued property can never be an odd number. If an | |
/// odd integer were provided to <c>SetValue</c>, the handler is still required to store a value successfully. It could | |
/// accomplish this by perhaps adding one to the value. If data is lost, <c>SetValue</c> must succeed with the return value INPLACE_S_TRUNCATED. | |
/// </term> | |
/// </item> | |
/// <item> | |
/// <term> | |
/// Pre-existing properties that are germane to the handler are those that have a representation in the handler's property | |
/// storage format. For example, Adobe Acrobat .pdf files have representations for PKEY_Author and PKEY_Comments. These | |
/// properties are described in a property description XML file provided by Windows. It is likely that the restrictions provided | |
/// by Windows do not exactly match how the equivalent property must be stored in the author's file format. For example, the | |
/// author value may be restricted to fewer characters in Acrobat files than in the property description for PKEY_Author. In | |
/// this case, the handler author must make a best-effort attempt to coerce the property value. If data is lost, <c>SetValue</c> | |
/// must succeed with the return value INPLACE_S_TRUNCATED. In the unusual case that the value cannot be coerced, | |
/// <c>SetValue</c> can return E_FAIL. If the author's file format is less restrictive than a property description provided by | |
/// Windows, the Windows Property Provider layer described earlier will already have returned an error and therefore the | |
/// property handler's <c>SetValue</c> will never be called to store the value. | |
/// </term> | |
/// </item> | |
/// <item> | |
/// <term> | |
/// Properties that are neither new nor pre-existing properties germane to the handler must still be stored by the property | |
/// handler. The utility class CLSID_InMemoryPropertyStore, provided by Windows, can be used by handler authors to temporarily | |
/// store such properties in memory and save those properties to a stream for storage in the file. | |
/// </term> | |
/// </item> | |
/// </list> | |
/// </remarks> | |
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/bb761475(v=vs.85) HRESULT SetValue( [in] | |
// REFPROPERTYKEY key, [in] REFPROPVARIANT propvar ); | |
void SetValue(in PROPERTYKEY pkey, in PROPVARIANT pv); | |
/// <summary>After a change has been made, this method saves the changes.</summary> | |
/// <remarks> | |
/// <para> | |
/// Before the method returns, it releases the file stream or path that was initialized to be used by the method. Therefore, no | |
/// <c>IPropertyStore</c> methods succeed after returns. At that point, they return E_FAIL. | |
/// </para> | |
/// <para> | |
/// Property handlers must ensure that property changes result in a valid destination file, even if the process terminates | |
/// abnormally, or encounters any errors. | |
/// </para> | |
/// </remarks> | |
// https://docs.microsoft.com/en-us/windows/win32/api/propsys/nf-propsys-ipropertystore-commit HRESULT Commit(); | |
void Commit(); | |
} | |
[StructLayout(LayoutKind.Explicit, Pack = 8)] | |
public struct PROPVARIANT | |
{ | |
/// <summary>Value type tag.</summary> | |
[FieldOffset(0)] public VarEnum vt; | |
/// <summary>Reserved for future use.</summary> | |
[FieldOffset(2)] public ushort wReserved1; | |
/// <summary>Reserved for future use.</summary> | |
[FieldOffset(4)] public ushort wReserved2; | |
/// <summary>Reserved for future use.</summary> | |
[FieldOffset(6)] public ushort wReserved3; | |
/// <summary>The decimal value when VT_DECIMAL.</summary> | |
[FieldOffset(0)] internal decimal _decimal; | |
/// <summary>The raw data pointer.</summary> | |
[FieldOffset(8)] internal IntPtr _ptr; | |
/// <summary>The FILETIME when VT_FILETIME.</summary> | |
[FieldOffset(8)] internal System.Runtime.InteropServices.ComTypes.FILETIME _ft; | |
/// <summary>The BLOB when VT_BLOB</summary> | |
[FieldOffset(8)] internal BLOB _blob; | |
/// <summary>The value when a numeric value less than 8 bytes.</summary> | |
[FieldOffset(8)] internal ulong _ulong; | |
/// <summary>Initializes a new instance of the <see cref="PROPVARIANT"/> class as VT_EMPTY.</summary> | |
//public PROPVARIANT() | |
//{ | |
//} | |
public PROPVARIANT(string value) | |
{ | |
ArgumentNullException.ThrowIfNull(value); | |
vt = VarEnum.VT_LPWSTR; | |
_ptr = Marshal.StringToCoTaskMemUni(value); | |
} | |
public VarEnum VarType { get => (VarEnum)vt; set => vt = (VarEnum)value; } | |
} | |
[StructLayout(LayoutKind.Sequential, Pack = 0)] | |
public struct BLOB | |
{ | |
/// <summary>The count of bytes</summary> | |
public uint cbSize; | |
/// <summary>A pointer to the allocated array of bytes.</summary> | |
public IntPtr pBlobData; | |
} | |
[StructLayout(LayoutKind.Sequential, Pack = 4)] | |
public partial struct PROPERTYKEY | |
{ | |
/// <summary> | |
/// <para>Type: <c>GUID</c></para> | |
/// <para>A unique GUID for the property.</para> | |
/// </summary> | |
public Guid fmtid; | |
/// <summary> | |
/// <para>Type: <c>DWORD</c></para> | |
/// <para> | |
/// A property identifier (PID). This parameter is not used as in SHCOLUMNID. It is recommended that you set this value to | |
/// PID_FIRST_USABLE. Any value greater than or equal to 2 is acceptable. | |
/// </para> | |
/// <para><c>Note</c> Values of 0 and 1 are reserved and should not be used.</para> | |
/// </summary> | |
public uint pid; | |
/// <summary>Initializes a new instance of the <see cref="PROPERTYKEY"/> struct.</summary> | |
/// <param name="key">The key.</param> | |
/// <param name="id">The identifier.</param> | |
public PROPERTYKEY(Guid key, uint id) | |
{ | |
fmtid = key; | |
pid = id; | |
} | |
public static class System | |
{ | |
/// <summary> | |
/// <para>Name: System.Title -- PKEY_Title</para> | |
/// <para>Description: Title of item.</para> | |
/// <para>Type: String -- VT_LPWSTR (For variants: VT_BSTR) Legacy code may treat this as VT_LPSTR.</para> | |
/// <para>FormatID: (FMTID_SummaryInformation) {F29F85E0-4FF9-1068-AB91-08002B27B3D9}, 2 (PIDSI_TITLE)</para> | |
/// </summary> | |
public static PROPERTYKEY Title | |
=> new(new Guid("{F29F85E0-4FF9-1068-AB91-08002B27B3D9}"), 2); | |
} | |
} | |
public enum ShowWindowCommand | |
{ | |
/// <summary>Hides the window and activates another window.</summary> | |
SW_HIDE = 0, | |
/// <summary> | |
/// Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. | |
/// An application should specify this flag when displaying the window for the first time. | |
/// </summary> | |
SW_SHOWNORMAL = 1, | |
/// <summary> | |
/// Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. | |
/// An application should specify this flag when displaying the window for the first time. | |
/// </summary> | |
SW_NORMAL = 1, | |
/// <summary>Activates the window and displays it as a minimized window.</summary> | |
SW_SHOWMINIMIZED = 2, | |
/// <summary>Activates the window and displays it as a maximized window.</summary> | |
SW_SHOWMAXIMIZED = 3, | |
/// <summary>Maximizes the specified window.</summary> | |
SW_MAXIMIZE = 3, | |
/// <summary>Displays a window in its most recent size and position. The active window remains active.</summary> | |
SW_SHOWNOACTIVATE = 4, | |
/// <summary>Activates the window and displays it in its current size and position.</summary> | |
SW_SHOW = 5, | |
/// <summary>Minimizes the specified window and activates the next top-level window in the z-order.</summary> | |
SW_MINIMIZE = 6, | |
/// <summary>Displays the window as a minimized window. The active window remains active.</summary> | |
SW_SHOWMINNOACTIVE = 7, | |
/// <summary>Displays the window in its current state. The active window remains active.</summary> | |
SW_SHOWNA = 8, | |
/// <summary> | |
/// Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and | |
/// position. An application should specify this flag when restoring a minimized window. | |
/// </summary> | |
SW_RESTORE = 9, | |
/// <summary> | |
/// Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the | |
/// program that started the application. An application should call ShowWindow with this flag to set the initial show state of its | |
/// main window. | |
/// </summary> | |
SW_SHOWDEFAULT = 10, | |
/// <summary> | |
/// Minimizes a window, even if the thread that owns the window is not responding. This flag should only be used when minimizing | |
/// windows from a different thread. | |
/// </summary> | |
SW_FORCEMINIMIZE = 11, | |
} | |
public enum KNOWNDESTCATEGORY | |
{ | |
/// <summary>Add the Frequent category.</summary> | |
KDC_FREQUENT = 1, | |
/// <summary>Add the Recent category.</summary> | |
KDC_RECENT = 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment