Created
May 24, 2018 16:54
-
-
Save mlasson/eca5ec98553ad1ac5d71ce7b05f9bc20 to your computer and use it in GitHub Desktop.
Pinning to the taskbar a “chained process”
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.Windows.Forms; | |
using System.Runtime.InteropServices; | |
using System.Runtime.CompilerServices; | |
/* Source: https://stackoverflow.com/questions/48539789/pinning-to-the-taskbar-a-chained-process */ | |
internal struct PropertyKey | |
{ | |
Guid formatId; | |
int propertyId; | |
internal PropertyKey(Guid guid, int propertyId) | |
{ | |
this.formatId = guid; | |
this.propertyId = propertyId; | |
} | |
} | |
[StructLayout(LayoutKind.Explicit)] | |
internal struct PropVariant | |
{ | |
[FieldOffset(0)] internal ushort vt; | |
[FieldOffset(8)] internal IntPtr pv; | |
[FieldOffset(8)] internal UInt64 padding; | |
[DllImport("Ole32.dll", PreserveSig = false)] | |
internal static extern void PropVariantClear(ref PropVariant pvar); | |
internal PropVariant(string value) | |
{ | |
this.vt = (ushort)VarEnum.VT_LPWSTR; | |
this.padding = 0; | |
this.pv = Marshal.StringToCoTaskMemUni(value); | |
} | |
internal void Clear() | |
{ | |
PropVariantClear (ref this); | |
} | |
} | |
[ComImport, | |
Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), | |
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | |
interface IPropertyStore | |
{ | |
int GetCount([Out] out uint propertyCount); | |
void GetAt([In] uint propertyIndex, [Out, MarshalAs(UnmanagedType.Struct)] out PropertyKey key); | |
void GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PropertyKey key, [Out, MarshalAs(UnmanagedType.Struct)] out PropVariant pv); | |
void SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PropertyKey key, [In, MarshalAs(UnmanagedType.Struct)] ref PropVariant pv); | |
void Commit(); | |
} | |
internal static class TaskBar { | |
[DllImport("shell32.dll")] | |
static extern int SHGetPropertyStoreForWindow( | |
IntPtr hwnd, | |
ref Guid iid /*IID_IPropertyStore*/, | |
[Out(), MarshalAs(UnmanagedType.Interface)]out IPropertyStore propertyStore); | |
internal static class Key { | |
private static Guid propGuid = new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"); | |
internal static PropertyKey AppId = new PropertyKey(propGuid, 5); | |
internal static PropertyKey RelaunchCommand = new PropertyKey(propGuid, 2); | |
internal static PropertyKey DisplayName = new PropertyKey(propGuid, 4); | |
} | |
private static void ClearValue(IPropertyStore store, PropertyKey key) { | |
var prop = new PropVariant(); | |
prop.vt = (ushort)VarEnum.VT_EMPTY; | |
store.SetValue(ref key, ref prop); | |
} | |
private static void SetValue(IPropertyStore store, PropertyKey key, string value) { | |
var prop = new PropVariant(value); | |
store.SetValue(ref key, ref prop); | |
prop.Clear(); | |
} | |
internal static IPropertyStore Store(IntPtr handle) { | |
IPropertyStore store; | |
var store_guid = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"); | |
int rc = SHGetPropertyStoreForWindow(handle, ref store_guid, out store); | |
if (rc != 0) throw Marshal.GetExceptionForHR(rc); | |
return store; | |
} | |
internal static void SetupLauncher(Form form) { | |
IntPtr handle = form.Handle; | |
var store = Store(handle); | |
SetValue (store, Key.AppId, "Stackoverflow.chain.process.pinning"); | |
form.FormClosed += delegate { Cleanup(handle); }; | |
} | |
internal static void SetupLaunchee(Form form) { | |
IntPtr handle = form.Handle; | |
var store = Store(handle); | |
SetValue (store, Key.AppId, "Stackoverflow.chain.process.pinning"); | |
string exePath = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "launcher.exe"); | |
SetValue (store, Key.RelaunchCommand, exePath); | |
SetValue (store, Key.DisplayName, "Test"); | |
form.FormClosed += delegate { Cleanup(handle); }; | |
} | |
internal static void Cleanup(IntPtr handle) { | |
var store = Store(handle); | |
ClearValue (store, Key.AppId); | |
ClearValue (store, Key.RelaunchCommand); | |
ClearValue (store, Key.DisplayName); | |
} | |
} |
Thanks for this feedback !
This problem is no longer a problem I need to solve but it may be helpful to someone else.
Do you remember why you are doing:
form.FormClosed += delegate { Cleanup(handle); };
Is it needed? Why should we clean it as the window is closed?
No idea ! I would not be surprised if this is just a zealous and unnecessary cleanup.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When I compile my application in x64, the app crashes.
I found a clue in Windows-API-Code-Pack-1.1:
https://github.com/aybe/Windows-API-Code-Pack-1.1/blob/master/source/WindowsAPICodePack/Core/PropertySystem/PropVariant.cs#L209
The BLOB structure (which is part of the PROPVARIANT structure) means that the
PropVariant
structure must be 20 bytes long.There's 2 solutions: