diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/ShortcutUtil/AppResolver.cs b/ShortcutUtil/AppResolver.cs
new file mode 100755
index 0000000..6daf0b5
--- /dev/null
+++ b/ShortcutUtil/AppResolver.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.System.Update;
+
+namespace NativeHelpers
+{
+ // CLSID_StartMenuCacheAndAppResolver {660b90c8-73a9-4b58-8cae-355b7f55341b}
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("660b90c8-73a9-4b58-8cae-355b7f55341b")]
+ public class CStartMenuCacheAndAppResolver { }
+
+ public class AppResolver
+ {
+ IAppResolver_7 app7 = null;
+ IAppResolver_8 app8 = null;
+ public AppResolver()
+ {
+ Exception last = null;
+ try
+ {
+ app8 = (IAppResolver_8)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app8 = null;
+ }
+
+ if (app8 == null)
+ {
+ try
+ {
+ app7 = (IAppResolver_7)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app7 = null;
+ }
+ }
+
+ if (app7 == null && app8 == null)
+ {
+ throw last;
+ }
+ }
+
+ public string GetAppIDForWindow(IntPtr hWnd)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+
+ public string GetAppIDForProcess(UInt32 processId)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+ }
+
+ // IID_IAppResolver_7 {46a6eeff-908e-4dc6-92a6-64be9177b41c}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("46a6eeff-908e-4dc6-92a6-64be9177b41c")]
+ public interface IAppResolver_7
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+
+ // IID_IAppResolver_8 {de25675a-72de-44b4-9373-05170450c140}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("de25675a-72de-44b4-9373-05170450c140")]
+ public interface IAppResolver_8
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForShortcutObject();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+}
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/ShortcutUtil/AppResolver.cs b/ShortcutUtil/AppResolver.cs
new file mode 100755
index 0000000..6daf0b5
--- /dev/null
+++ b/ShortcutUtil/AppResolver.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.System.Update;
+
+namespace NativeHelpers
+{
+ // CLSID_StartMenuCacheAndAppResolver {660b90c8-73a9-4b58-8cae-355b7f55341b}
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("660b90c8-73a9-4b58-8cae-355b7f55341b")]
+ public class CStartMenuCacheAndAppResolver { }
+
+ public class AppResolver
+ {
+ IAppResolver_7 app7 = null;
+ IAppResolver_8 app8 = null;
+ public AppResolver()
+ {
+ Exception last = null;
+ try
+ {
+ app8 = (IAppResolver_8)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app8 = null;
+ }
+
+ if (app8 == null)
+ {
+ try
+ {
+ app7 = (IAppResolver_7)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app7 = null;
+ }
+ }
+
+ if (app7 == null && app8 == null)
+ {
+ throw last;
+ }
+ }
+
+ public string GetAppIDForWindow(IntPtr hWnd)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+
+ public string GetAppIDForProcess(UInt32 processId)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+ }
+
+ // IID_IAppResolver_7 {46a6eeff-908e-4dc6-92a6-64be9177b41c}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("46a6eeff-908e-4dc6-92a6-64be9177b41c")]
+ public interface IAppResolver_7
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+
+ // IID_IAppResolver_8 {de25675a-72de-44b4-9373-05170450c140}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("de25675a-72de-44b4-9373-05170450c140")]
+ public interface IAppResolver_8
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForShortcutObject();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+}
diff --git a/ShortcutUtil/MainForm.Designer.cs b/ShortcutUtil/MainForm.Designer.cs
index 5dbf023..8af74c7 100755
--- a/ShortcutUtil/MainForm.Designer.cs
+++ b/ShortcutUtil/MainForm.Designer.cs
@@ -48,6 +48,9 @@
//
// entryListBox
//
+ this.entryListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.entryListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
this.entryListBox.FormattingEnabled = true;
this.entryListBox.Location = new System.Drawing.Point(16, 98);
@@ -59,6 +62,7 @@
//
// createButton
//
+ this.createButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.createButton.Location = new System.Drawing.Point(644, 458);
this.createButton.Name = "createButton";
this.createButton.Size = new System.Drawing.Size(144, 40);
@@ -77,6 +81,8 @@
//
// appUserModelIdBox
//
+ this.appUserModelIdBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.appUserModelIdBox.Location = new System.Drawing.Point(16, 35);
this.appUserModelIdBox.Name = "appUserModelIdBox";
this.appUserModelIdBox.Size = new System.Drawing.Size(608, 26);
@@ -86,6 +92,7 @@
//
// appButton
//
+ this.appButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.appButton.Location = new System.Drawing.Point(633, 35);
this.appButton.Name = "appButton";
this.appButton.Size = new System.Drawing.Size(74, 31);
@@ -96,6 +103,7 @@
//
// hwndButton
//
+ this.hwndButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.hwndButton.Location = new System.Drawing.Point(712, 35);
this.hwndButton.MinimumSize = new System.Drawing.Size(76, 26);
this.hwndButton.Name = "hwndButton";
@@ -103,6 +111,7 @@
this.hwndButton.TabIndex = 6;
this.hwndButton.Text = "HWND";
this.hwndButton.UseVisualStyleBackColor = true;
+ this.hwndButton.Click += new System.EventHandler(this.hwndButton_Click);
//
// MainForm
//
@@ -119,8 +128,6 @@
this.Controls.Add(this.defaultShortcutLabel);
this.Name = "MainForm";
this.Text = "Form1";
- this.Shown += new System.EventHandler(this.MainForm_Shown);
- this.SizeChanged += new System.EventHandler(this.MainForm_SizeChanged);
this.ResumeLayout(false);
this.PerformLayout();
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/ShortcutUtil/AppResolver.cs b/ShortcutUtil/AppResolver.cs
new file mode 100755
index 0000000..6daf0b5
--- /dev/null
+++ b/ShortcutUtil/AppResolver.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.System.Update;
+
+namespace NativeHelpers
+{
+ // CLSID_StartMenuCacheAndAppResolver {660b90c8-73a9-4b58-8cae-355b7f55341b}
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("660b90c8-73a9-4b58-8cae-355b7f55341b")]
+ public class CStartMenuCacheAndAppResolver { }
+
+ public class AppResolver
+ {
+ IAppResolver_7 app7 = null;
+ IAppResolver_8 app8 = null;
+ public AppResolver()
+ {
+ Exception last = null;
+ try
+ {
+ app8 = (IAppResolver_8)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app8 = null;
+ }
+
+ if (app8 == null)
+ {
+ try
+ {
+ app7 = (IAppResolver_7)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app7 = null;
+ }
+ }
+
+ if (app7 == null && app8 == null)
+ {
+ throw last;
+ }
+ }
+
+ public string GetAppIDForWindow(IntPtr hWnd)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+
+ public string GetAppIDForProcess(UInt32 processId)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+ }
+
+ // IID_IAppResolver_7 {46a6eeff-908e-4dc6-92a6-64be9177b41c}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("46a6eeff-908e-4dc6-92a6-64be9177b41c")]
+ public interface IAppResolver_7
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+
+ // IID_IAppResolver_8 {de25675a-72de-44b4-9373-05170450c140}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("de25675a-72de-44b4-9373-05170450c140")]
+ public interface IAppResolver_8
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForShortcutObject();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+}
diff --git a/ShortcutUtil/MainForm.Designer.cs b/ShortcutUtil/MainForm.Designer.cs
index 5dbf023..8af74c7 100755
--- a/ShortcutUtil/MainForm.Designer.cs
+++ b/ShortcutUtil/MainForm.Designer.cs
@@ -48,6 +48,9 @@
//
// entryListBox
//
+ this.entryListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.entryListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
this.entryListBox.FormattingEnabled = true;
this.entryListBox.Location = new System.Drawing.Point(16, 98);
@@ -59,6 +62,7 @@
//
// createButton
//
+ this.createButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.createButton.Location = new System.Drawing.Point(644, 458);
this.createButton.Name = "createButton";
this.createButton.Size = new System.Drawing.Size(144, 40);
@@ -77,6 +81,8 @@
//
// appUserModelIdBox
//
+ this.appUserModelIdBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.appUserModelIdBox.Location = new System.Drawing.Point(16, 35);
this.appUserModelIdBox.Name = "appUserModelIdBox";
this.appUserModelIdBox.Size = new System.Drawing.Size(608, 26);
@@ -86,6 +92,7 @@
//
// appButton
//
+ this.appButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.appButton.Location = new System.Drawing.Point(633, 35);
this.appButton.Name = "appButton";
this.appButton.Size = new System.Drawing.Size(74, 31);
@@ -96,6 +103,7 @@
//
// hwndButton
//
+ this.hwndButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.hwndButton.Location = new System.Drawing.Point(712, 35);
this.hwndButton.MinimumSize = new System.Drawing.Size(76, 26);
this.hwndButton.Name = "hwndButton";
@@ -103,6 +111,7 @@
this.hwndButton.TabIndex = 6;
this.hwndButton.Text = "HWND";
this.hwndButton.UseVisualStyleBackColor = true;
+ this.hwndButton.Click += new System.EventHandler(this.hwndButton_Click);
//
// MainForm
//
@@ -119,8 +128,6 @@
this.Controls.Add(this.defaultShortcutLabel);
this.Name = "MainForm";
this.Text = "Form1";
- this.Shown += new System.EventHandler(this.MainForm_Shown);
- this.SizeChanged += new System.EventHandler(this.MainForm_SizeChanged);
this.ResumeLayout(false);
this.PerformLayout();
diff --git a/ShortcutUtil/MainForm.cs b/ShortcutUtil/MainForm.cs
index 680ed45..c654b19 100755
--- a/ShortcutUtil/MainForm.cs
+++ b/ShortcutUtil/MainForm.cs
@@ -1,5 +1,7 @@
using Entries;
+using NativeHelpers;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
@@ -23,11 +25,9 @@
private Font nameFont;
private Brush fontBrush;
- private bool shown = false;
- private Size listSizeOffset;
- private Point buttonOffset;
+ private AppResolver appResolver;
- public MainForm(EntryList entryList)
+ public MainForm(EntryList entryList, AppResolver appResolver)
{
InitializeComponent();
@@ -38,6 +38,7 @@
fontBrush = new SolidBrush(defaultShortcutLabel.ForeColor);
this.entryList = entryList;
+ this.appResolver = appResolver;
entryListBox.Items.AddRange(this.entryList.Entries.ToArray());
@@ -122,23 +123,6 @@
e.ItemHeight = Size.Add(IconSize, new Size(0, ItemPadding.Height * 2)).Height;
}
- private void MainForm_SizeChanged(object sender, EventArgs e)
- {
- if (shown)
- {
- entryListBox.Size = Size.Subtract(Size, listSizeOffset);
- createButton.Location = Point.Add(buttonOffset, entryListBox.Size);
- }
- }
-
- private void MainForm_Shown(object sender, EventArgs e)
- {
- listSizeOffset = Size.Subtract(Size, entryListBox.Size);
- buttonOffset = Point.Subtract(createButton.Location, entryListBox.Size);
-
- shown = true;
- }
-
private SearchForm search = new SearchForm();
private async void appButton_Click(object sender, EventArgs e)
{
@@ -166,5 +150,83 @@
appButton.Enabled = true;
}
+
+ private static bool GetWindowHandle(IntPtr windowHandle, ref object windowHandles)
+ {
+ ((ArrayList)windowHandles).Add(windowHandle);
+ return true;
+ }
+
+ private void hwndButton_Click(object sender, EventArgs e)
+ {
+ hwndButton.Enabled = false;
+
+ object handles = new ArrayList();
+ NativeCalls.EnumWindows(GetWindowHandle, ref handles);
+
+ List> titles = new List>();
+ foreach (object ptrObj in (ArrayList)handles)
+ {
+ IntPtr ptr = (IntPtr)ptrObj;
+ if (NativeCalls.IsAltTabWindow(ptr))
+ {
+ string title = NativeCalls.GetWindowTextManaged(ptr);
+ if (title != "")
+ {
+ /*
+ IPropertyStore store;
+ Guid guid = NativeValues.IID_IPropertyStore;
+ NativeCalls.VerifySucceeded((uint)NativeCalls.SHGetPropertyStoreForWindow(ptr, ref guid, out store));
+
+ using (PropVariant pv = new PropVariant())
+ {
+ NativeCalls.VerifySucceeded(store.GetValue(NativeValues.AppUserModelIDKey, pv));
+
+ string appUserModelId = pv.Value;
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ IntPtr handle = NativeCalls.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, (int)processId);
+
+ try
+ {
+ appUserModelId = NativeCalls.GetApplicationUserModelIdManaged(handle);
+ }
+ catch (Exception) { }
+ }
+
+
+ }
+ */
+
+ string appUserModelId = appResolver.GetAppIDForWindow(ptr);
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ appUserModelId = appResolver.GetAppIDForProcess(processId);
+ }
+
+ if (appUserModelId != null)
+ {
+ titles.Add(new Tuple(ptr, title, appUserModelId == null ? "NULL" : appUserModelId));
+ }
+ }
+
+ }
+ }
+
+ string selectedAppUserModelId = search.GetSelection("Select Window", "Available Windows:", titles.Select(t => new Tuple(t.Item3, t.Item2 + ": " + t.Item3)).ToList());
+
+ if (selectedAppUserModelId != null)
+ {
+ appUserModelIdBox.Text = selectedAppUserModelId;
+ }
+
+ hwndButton.Enabled = true;
+ }
}
}
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/ShortcutUtil/AppResolver.cs b/ShortcutUtil/AppResolver.cs
new file mode 100755
index 0000000..6daf0b5
--- /dev/null
+++ b/ShortcutUtil/AppResolver.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.System.Update;
+
+namespace NativeHelpers
+{
+ // CLSID_StartMenuCacheAndAppResolver {660b90c8-73a9-4b58-8cae-355b7f55341b}
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("660b90c8-73a9-4b58-8cae-355b7f55341b")]
+ public class CStartMenuCacheAndAppResolver { }
+
+ public class AppResolver
+ {
+ IAppResolver_7 app7 = null;
+ IAppResolver_8 app8 = null;
+ public AppResolver()
+ {
+ Exception last = null;
+ try
+ {
+ app8 = (IAppResolver_8)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app8 = null;
+ }
+
+ if (app8 == null)
+ {
+ try
+ {
+ app7 = (IAppResolver_7)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app7 = null;
+ }
+ }
+
+ if (app7 == null && app8 == null)
+ {
+ throw last;
+ }
+ }
+
+ public string GetAppIDForWindow(IntPtr hWnd)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+
+ public string GetAppIDForProcess(UInt32 processId)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+ }
+
+ // IID_IAppResolver_7 {46a6eeff-908e-4dc6-92a6-64be9177b41c}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("46a6eeff-908e-4dc6-92a6-64be9177b41c")]
+ public interface IAppResolver_7
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+
+ // IID_IAppResolver_8 {de25675a-72de-44b4-9373-05170450c140}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("de25675a-72de-44b4-9373-05170450c140")]
+ public interface IAppResolver_8
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForShortcutObject();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+}
diff --git a/ShortcutUtil/MainForm.Designer.cs b/ShortcutUtil/MainForm.Designer.cs
index 5dbf023..8af74c7 100755
--- a/ShortcutUtil/MainForm.Designer.cs
+++ b/ShortcutUtil/MainForm.Designer.cs
@@ -48,6 +48,9 @@
//
// entryListBox
//
+ this.entryListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.entryListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
this.entryListBox.FormattingEnabled = true;
this.entryListBox.Location = new System.Drawing.Point(16, 98);
@@ -59,6 +62,7 @@
//
// createButton
//
+ this.createButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.createButton.Location = new System.Drawing.Point(644, 458);
this.createButton.Name = "createButton";
this.createButton.Size = new System.Drawing.Size(144, 40);
@@ -77,6 +81,8 @@
//
// appUserModelIdBox
//
+ this.appUserModelIdBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.appUserModelIdBox.Location = new System.Drawing.Point(16, 35);
this.appUserModelIdBox.Name = "appUserModelIdBox";
this.appUserModelIdBox.Size = new System.Drawing.Size(608, 26);
@@ -86,6 +92,7 @@
//
// appButton
//
+ this.appButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.appButton.Location = new System.Drawing.Point(633, 35);
this.appButton.Name = "appButton";
this.appButton.Size = new System.Drawing.Size(74, 31);
@@ -96,6 +103,7 @@
//
// hwndButton
//
+ this.hwndButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.hwndButton.Location = new System.Drawing.Point(712, 35);
this.hwndButton.MinimumSize = new System.Drawing.Size(76, 26);
this.hwndButton.Name = "hwndButton";
@@ -103,6 +111,7 @@
this.hwndButton.TabIndex = 6;
this.hwndButton.Text = "HWND";
this.hwndButton.UseVisualStyleBackColor = true;
+ this.hwndButton.Click += new System.EventHandler(this.hwndButton_Click);
//
// MainForm
//
@@ -119,8 +128,6 @@
this.Controls.Add(this.defaultShortcutLabel);
this.Name = "MainForm";
this.Text = "Form1";
- this.Shown += new System.EventHandler(this.MainForm_Shown);
- this.SizeChanged += new System.EventHandler(this.MainForm_SizeChanged);
this.ResumeLayout(false);
this.PerformLayout();
diff --git a/ShortcutUtil/MainForm.cs b/ShortcutUtil/MainForm.cs
index 680ed45..c654b19 100755
--- a/ShortcutUtil/MainForm.cs
+++ b/ShortcutUtil/MainForm.cs
@@ -1,5 +1,7 @@
using Entries;
+using NativeHelpers;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
@@ -23,11 +25,9 @@
private Font nameFont;
private Brush fontBrush;
- private bool shown = false;
- private Size listSizeOffset;
- private Point buttonOffset;
+ private AppResolver appResolver;
- public MainForm(EntryList entryList)
+ public MainForm(EntryList entryList, AppResolver appResolver)
{
InitializeComponent();
@@ -38,6 +38,7 @@
fontBrush = new SolidBrush(defaultShortcutLabel.ForeColor);
this.entryList = entryList;
+ this.appResolver = appResolver;
entryListBox.Items.AddRange(this.entryList.Entries.ToArray());
@@ -122,23 +123,6 @@
e.ItemHeight = Size.Add(IconSize, new Size(0, ItemPadding.Height * 2)).Height;
}
- private void MainForm_SizeChanged(object sender, EventArgs e)
- {
- if (shown)
- {
- entryListBox.Size = Size.Subtract(Size, listSizeOffset);
- createButton.Location = Point.Add(buttonOffset, entryListBox.Size);
- }
- }
-
- private void MainForm_Shown(object sender, EventArgs e)
- {
- listSizeOffset = Size.Subtract(Size, entryListBox.Size);
- buttonOffset = Point.Subtract(createButton.Location, entryListBox.Size);
-
- shown = true;
- }
-
private SearchForm search = new SearchForm();
private async void appButton_Click(object sender, EventArgs e)
{
@@ -166,5 +150,83 @@
appButton.Enabled = true;
}
+
+ private static bool GetWindowHandle(IntPtr windowHandle, ref object windowHandles)
+ {
+ ((ArrayList)windowHandles).Add(windowHandle);
+ return true;
+ }
+
+ private void hwndButton_Click(object sender, EventArgs e)
+ {
+ hwndButton.Enabled = false;
+
+ object handles = new ArrayList();
+ NativeCalls.EnumWindows(GetWindowHandle, ref handles);
+
+ List> titles = new List>();
+ foreach (object ptrObj in (ArrayList)handles)
+ {
+ IntPtr ptr = (IntPtr)ptrObj;
+ if (NativeCalls.IsAltTabWindow(ptr))
+ {
+ string title = NativeCalls.GetWindowTextManaged(ptr);
+ if (title != "")
+ {
+ /*
+ IPropertyStore store;
+ Guid guid = NativeValues.IID_IPropertyStore;
+ NativeCalls.VerifySucceeded((uint)NativeCalls.SHGetPropertyStoreForWindow(ptr, ref guid, out store));
+
+ using (PropVariant pv = new PropVariant())
+ {
+ NativeCalls.VerifySucceeded(store.GetValue(NativeValues.AppUserModelIDKey, pv));
+
+ string appUserModelId = pv.Value;
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ IntPtr handle = NativeCalls.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, (int)processId);
+
+ try
+ {
+ appUserModelId = NativeCalls.GetApplicationUserModelIdManaged(handle);
+ }
+ catch (Exception) { }
+ }
+
+
+ }
+ */
+
+ string appUserModelId = appResolver.GetAppIDForWindow(ptr);
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ appUserModelId = appResolver.GetAppIDForProcess(processId);
+ }
+
+ if (appUserModelId != null)
+ {
+ titles.Add(new Tuple(ptr, title, appUserModelId == null ? "NULL" : appUserModelId));
+ }
+ }
+
+ }
+ }
+
+ string selectedAppUserModelId = search.GetSelection("Select Window", "Available Windows:", titles.Select(t => new Tuple(t.Item3, t.Item2 + ": " + t.Item3)).ToList());
+
+ if (selectedAppUserModelId != null)
+ {
+ appUserModelIdBox.Text = selectedAppUserModelId;
+ }
+
+ hwndButton.Enabled = true;
+ }
}
}
diff --git a/ShortcutUtil/Program.cs b/ShortcutUtil/Program.cs
index 9b6f955..a46ce5b 100755
--- a/ShortcutUtil/Program.cs
+++ b/ShortcutUtil/Program.cs
@@ -5,6 +5,8 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
+using NativeHelpers;
+using System.Runtime.InteropServices;
namespace ShortcutUtil
{
@@ -16,6 +18,8 @@
[STAThread]
static void Main()
{
+ AppResolver appResolver = new AppResolver();
+
string[] args = Environment.GetCommandLineArgs();
if (args.Length < 2)
@@ -46,7 +50,7 @@
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new MainForm(entryList));
+ Application.Run(new MainForm(entryList, appResolver));
}
}
}
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/ShortcutUtil/AppResolver.cs b/ShortcutUtil/AppResolver.cs
new file mode 100755
index 0000000..6daf0b5
--- /dev/null
+++ b/ShortcutUtil/AppResolver.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.System.Update;
+
+namespace NativeHelpers
+{
+ // CLSID_StartMenuCacheAndAppResolver {660b90c8-73a9-4b58-8cae-355b7f55341b}
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("660b90c8-73a9-4b58-8cae-355b7f55341b")]
+ public class CStartMenuCacheAndAppResolver { }
+
+ public class AppResolver
+ {
+ IAppResolver_7 app7 = null;
+ IAppResolver_8 app8 = null;
+ public AppResolver()
+ {
+ Exception last = null;
+ try
+ {
+ app8 = (IAppResolver_8)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app8 = null;
+ }
+
+ if (app8 == null)
+ {
+ try
+ {
+ app7 = (IAppResolver_7)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app7 = null;
+ }
+ }
+
+ if (app7 == null && app8 == null)
+ {
+ throw last;
+ }
+ }
+
+ public string GetAppIDForWindow(IntPtr hWnd)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+
+ public string GetAppIDForProcess(UInt32 processId)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+ }
+
+ // IID_IAppResolver_7 {46a6eeff-908e-4dc6-92a6-64be9177b41c}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("46a6eeff-908e-4dc6-92a6-64be9177b41c")]
+ public interface IAppResolver_7
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+
+ // IID_IAppResolver_8 {de25675a-72de-44b4-9373-05170450c140}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("de25675a-72de-44b4-9373-05170450c140")]
+ public interface IAppResolver_8
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForShortcutObject();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+}
diff --git a/ShortcutUtil/MainForm.Designer.cs b/ShortcutUtil/MainForm.Designer.cs
index 5dbf023..8af74c7 100755
--- a/ShortcutUtil/MainForm.Designer.cs
+++ b/ShortcutUtil/MainForm.Designer.cs
@@ -48,6 +48,9 @@
//
// entryListBox
//
+ this.entryListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.entryListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
this.entryListBox.FormattingEnabled = true;
this.entryListBox.Location = new System.Drawing.Point(16, 98);
@@ -59,6 +62,7 @@
//
// createButton
//
+ this.createButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.createButton.Location = new System.Drawing.Point(644, 458);
this.createButton.Name = "createButton";
this.createButton.Size = new System.Drawing.Size(144, 40);
@@ -77,6 +81,8 @@
//
// appUserModelIdBox
//
+ this.appUserModelIdBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.appUserModelIdBox.Location = new System.Drawing.Point(16, 35);
this.appUserModelIdBox.Name = "appUserModelIdBox";
this.appUserModelIdBox.Size = new System.Drawing.Size(608, 26);
@@ -86,6 +92,7 @@
//
// appButton
//
+ this.appButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.appButton.Location = new System.Drawing.Point(633, 35);
this.appButton.Name = "appButton";
this.appButton.Size = new System.Drawing.Size(74, 31);
@@ -96,6 +103,7 @@
//
// hwndButton
//
+ this.hwndButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.hwndButton.Location = new System.Drawing.Point(712, 35);
this.hwndButton.MinimumSize = new System.Drawing.Size(76, 26);
this.hwndButton.Name = "hwndButton";
@@ -103,6 +111,7 @@
this.hwndButton.TabIndex = 6;
this.hwndButton.Text = "HWND";
this.hwndButton.UseVisualStyleBackColor = true;
+ this.hwndButton.Click += new System.EventHandler(this.hwndButton_Click);
//
// MainForm
//
@@ -119,8 +128,6 @@
this.Controls.Add(this.defaultShortcutLabel);
this.Name = "MainForm";
this.Text = "Form1";
- this.Shown += new System.EventHandler(this.MainForm_Shown);
- this.SizeChanged += new System.EventHandler(this.MainForm_SizeChanged);
this.ResumeLayout(false);
this.PerformLayout();
diff --git a/ShortcutUtil/MainForm.cs b/ShortcutUtil/MainForm.cs
index 680ed45..c654b19 100755
--- a/ShortcutUtil/MainForm.cs
+++ b/ShortcutUtil/MainForm.cs
@@ -1,5 +1,7 @@
using Entries;
+using NativeHelpers;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
@@ -23,11 +25,9 @@
private Font nameFont;
private Brush fontBrush;
- private bool shown = false;
- private Size listSizeOffset;
- private Point buttonOffset;
+ private AppResolver appResolver;
- public MainForm(EntryList entryList)
+ public MainForm(EntryList entryList, AppResolver appResolver)
{
InitializeComponent();
@@ -38,6 +38,7 @@
fontBrush = new SolidBrush(defaultShortcutLabel.ForeColor);
this.entryList = entryList;
+ this.appResolver = appResolver;
entryListBox.Items.AddRange(this.entryList.Entries.ToArray());
@@ -122,23 +123,6 @@
e.ItemHeight = Size.Add(IconSize, new Size(0, ItemPadding.Height * 2)).Height;
}
- private void MainForm_SizeChanged(object sender, EventArgs e)
- {
- if (shown)
- {
- entryListBox.Size = Size.Subtract(Size, listSizeOffset);
- createButton.Location = Point.Add(buttonOffset, entryListBox.Size);
- }
- }
-
- private void MainForm_Shown(object sender, EventArgs e)
- {
- listSizeOffset = Size.Subtract(Size, entryListBox.Size);
- buttonOffset = Point.Subtract(createButton.Location, entryListBox.Size);
-
- shown = true;
- }
-
private SearchForm search = new SearchForm();
private async void appButton_Click(object sender, EventArgs e)
{
@@ -166,5 +150,83 @@
appButton.Enabled = true;
}
+
+ private static bool GetWindowHandle(IntPtr windowHandle, ref object windowHandles)
+ {
+ ((ArrayList)windowHandles).Add(windowHandle);
+ return true;
+ }
+
+ private void hwndButton_Click(object sender, EventArgs e)
+ {
+ hwndButton.Enabled = false;
+
+ object handles = new ArrayList();
+ NativeCalls.EnumWindows(GetWindowHandle, ref handles);
+
+ List> titles = new List>();
+ foreach (object ptrObj in (ArrayList)handles)
+ {
+ IntPtr ptr = (IntPtr)ptrObj;
+ if (NativeCalls.IsAltTabWindow(ptr))
+ {
+ string title = NativeCalls.GetWindowTextManaged(ptr);
+ if (title != "")
+ {
+ /*
+ IPropertyStore store;
+ Guid guid = NativeValues.IID_IPropertyStore;
+ NativeCalls.VerifySucceeded((uint)NativeCalls.SHGetPropertyStoreForWindow(ptr, ref guid, out store));
+
+ using (PropVariant pv = new PropVariant())
+ {
+ NativeCalls.VerifySucceeded(store.GetValue(NativeValues.AppUserModelIDKey, pv));
+
+ string appUserModelId = pv.Value;
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ IntPtr handle = NativeCalls.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, (int)processId);
+
+ try
+ {
+ appUserModelId = NativeCalls.GetApplicationUserModelIdManaged(handle);
+ }
+ catch (Exception) { }
+ }
+
+
+ }
+ */
+
+ string appUserModelId = appResolver.GetAppIDForWindow(ptr);
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ appUserModelId = appResolver.GetAppIDForProcess(processId);
+ }
+
+ if (appUserModelId != null)
+ {
+ titles.Add(new Tuple(ptr, title, appUserModelId == null ? "NULL" : appUserModelId));
+ }
+ }
+
+ }
+ }
+
+ string selectedAppUserModelId = search.GetSelection("Select Window", "Available Windows:", titles.Select(t => new Tuple(t.Item3, t.Item2 + ": " + t.Item3)).ToList());
+
+ if (selectedAppUserModelId != null)
+ {
+ appUserModelIdBox.Text = selectedAppUserModelId;
+ }
+
+ hwndButton.Enabled = true;
+ }
}
}
diff --git a/ShortcutUtil/Program.cs b/ShortcutUtil/Program.cs
index 9b6f955..a46ce5b 100755
--- a/ShortcutUtil/Program.cs
+++ b/ShortcutUtil/Program.cs
@@ -5,6 +5,8 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
+using NativeHelpers;
+using System.Runtime.InteropServices;
namespace ShortcutUtil
{
@@ -16,6 +18,8 @@
[STAThread]
static void Main()
{
+ AppResolver appResolver = new AppResolver();
+
string[] args = Environment.GetCommandLineArgs();
if (args.Length < 2)
@@ -46,7 +50,7 @@
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new MainForm(entryList));
+ Application.Run(new MainForm(entryList, appResolver));
}
}
}
diff --git a/ShortcutUtil/SearchForm.Designer.cs b/ShortcutUtil/SearchForm.Designer.cs
index 93f58bf..350f243 100755
--- a/ShortcutUtil/SearchForm.Designer.cs
+++ b/ShortcutUtil/SearchForm.Designer.cs
@@ -55,6 +55,9 @@
//
// optionsList
//
+ this.optionsList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.optionsList.FormattingEnabled = true;
this.optionsList.ItemHeight = 20;
this.optionsList.Location = new System.Drawing.Point(17, 104);
@@ -64,6 +67,7 @@
//
// selectButton
//
+ this.selectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.selectButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.selectButton.Location = new System.Drawing.Point(661, 414);
this.selectButton.Name = "selectButton";
@@ -74,6 +78,8 @@
//
// searchBox
//
+ this.searchBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.searchBox.Location = new System.Drawing.Point(17, 37);
this.searchBox.Name = "searchBox";
this.searchBox.Size = new System.Drawing.Size(771, 26);
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/ShortcutUtil/AppResolver.cs b/ShortcutUtil/AppResolver.cs
new file mode 100755
index 0000000..6daf0b5
--- /dev/null
+++ b/ShortcutUtil/AppResolver.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.System.Update;
+
+namespace NativeHelpers
+{
+ // CLSID_StartMenuCacheAndAppResolver {660b90c8-73a9-4b58-8cae-355b7f55341b}
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("660b90c8-73a9-4b58-8cae-355b7f55341b")]
+ public class CStartMenuCacheAndAppResolver { }
+
+ public class AppResolver
+ {
+ IAppResolver_7 app7 = null;
+ IAppResolver_8 app8 = null;
+ public AppResolver()
+ {
+ Exception last = null;
+ try
+ {
+ app8 = (IAppResolver_8)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app8 = null;
+ }
+
+ if (app8 == null)
+ {
+ try
+ {
+ app7 = (IAppResolver_7)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app7 = null;
+ }
+ }
+
+ if (app7 == null && app8 == null)
+ {
+ throw last;
+ }
+ }
+
+ public string GetAppIDForWindow(IntPtr hWnd)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+
+ public string GetAppIDForProcess(UInt32 processId)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+ }
+
+ // IID_IAppResolver_7 {46a6eeff-908e-4dc6-92a6-64be9177b41c}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("46a6eeff-908e-4dc6-92a6-64be9177b41c")]
+ public interface IAppResolver_7
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+
+ // IID_IAppResolver_8 {de25675a-72de-44b4-9373-05170450c140}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("de25675a-72de-44b4-9373-05170450c140")]
+ public interface IAppResolver_8
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForShortcutObject();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+}
diff --git a/ShortcutUtil/MainForm.Designer.cs b/ShortcutUtil/MainForm.Designer.cs
index 5dbf023..8af74c7 100755
--- a/ShortcutUtil/MainForm.Designer.cs
+++ b/ShortcutUtil/MainForm.Designer.cs
@@ -48,6 +48,9 @@
//
// entryListBox
//
+ this.entryListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.entryListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
this.entryListBox.FormattingEnabled = true;
this.entryListBox.Location = new System.Drawing.Point(16, 98);
@@ -59,6 +62,7 @@
//
// createButton
//
+ this.createButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.createButton.Location = new System.Drawing.Point(644, 458);
this.createButton.Name = "createButton";
this.createButton.Size = new System.Drawing.Size(144, 40);
@@ -77,6 +81,8 @@
//
// appUserModelIdBox
//
+ this.appUserModelIdBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.appUserModelIdBox.Location = new System.Drawing.Point(16, 35);
this.appUserModelIdBox.Name = "appUserModelIdBox";
this.appUserModelIdBox.Size = new System.Drawing.Size(608, 26);
@@ -86,6 +92,7 @@
//
// appButton
//
+ this.appButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.appButton.Location = new System.Drawing.Point(633, 35);
this.appButton.Name = "appButton";
this.appButton.Size = new System.Drawing.Size(74, 31);
@@ -96,6 +103,7 @@
//
// hwndButton
//
+ this.hwndButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.hwndButton.Location = new System.Drawing.Point(712, 35);
this.hwndButton.MinimumSize = new System.Drawing.Size(76, 26);
this.hwndButton.Name = "hwndButton";
@@ -103,6 +111,7 @@
this.hwndButton.TabIndex = 6;
this.hwndButton.Text = "HWND";
this.hwndButton.UseVisualStyleBackColor = true;
+ this.hwndButton.Click += new System.EventHandler(this.hwndButton_Click);
//
// MainForm
//
@@ -119,8 +128,6 @@
this.Controls.Add(this.defaultShortcutLabel);
this.Name = "MainForm";
this.Text = "Form1";
- this.Shown += new System.EventHandler(this.MainForm_Shown);
- this.SizeChanged += new System.EventHandler(this.MainForm_SizeChanged);
this.ResumeLayout(false);
this.PerformLayout();
diff --git a/ShortcutUtil/MainForm.cs b/ShortcutUtil/MainForm.cs
index 680ed45..c654b19 100755
--- a/ShortcutUtil/MainForm.cs
+++ b/ShortcutUtil/MainForm.cs
@@ -1,5 +1,7 @@
using Entries;
+using NativeHelpers;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
@@ -23,11 +25,9 @@
private Font nameFont;
private Brush fontBrush;
- private bool shown = false;
- private Size listSizeOffset;
- private Point buttonOffset;
+ private AppResolver appResolver;
- public MainForm(EntryList entryList)
+ public MainForm(EntryList entryList, AppResolver appResolver)
{
InitializeComponent();
@@ -38,6 +38,7 @@
fontBrush = new SolidBrush(defaultShortcutLabel.ForeColor);
this.entryList = entryList;
+ this.appResolver = appResolver;
entryListBox.Items.AddRange(this.entryList.Entries.ToArray());
@@ -122,23 +123,6 @@
e.ItemHeight = Size.Add(IconSize, new Size(0, ItemPadding.Height * 2)).Height;
}
- private void MainForm_SizeChanged(object sender, EventArgs e)
- {
- if (shown)
- {
- entryListBox.Size = Size.Subtract(Size, listSizeOffset);
- createButton.Location = Point.Add(buttonOffset, entryListBox.Size);
- }
- }
-
- private void MainForm_Shown(object sender, EventArgs e)
- {
- listSizeOffset = Size.Subtract(Size, entryListBox.Size);
- buttonOffset = Point.Subtract(createButton.Location, entryListBox.Size);
-
- shown = true;
- }
-
private SearchForm search = new SearchForm();
private async void appButton_Click(object sender, EventArgs e)
{
@@ -166,5 +150,83 @@
appButton.Enabled = true;
}
+
+ private static bool GetWindowHandle(IntPtr windowHandle, ref object windowHandles)
+ {
+ ((ArrayList)windowHandles).Add(windowHandle);
+ return true;
+ }
+
+ private void hwndButton_Click(object sender, EventArgs e)
+ {
+ hwndButton.Enabled = false;
+
+ object handles = new ArrayList();
+ NativeCalls.EnumWindows(GetWindowHandle, ref handles);
+
+ List> titles = new List>();
+ foreach (object ptrObj in (ArrayList)handles)
+ {
+ IntPtr ptr = (IntPtr)ptrObj;
+ if (NativeCalls.IsAltTabWindow(ptr))
+ {
+ string title = NativeCalls.GetWindowTextManaged(ptr);
+ if (title != "")
+ {
+ /*
+ IPropertyStore store;
+ Guid guid = NativeValues.IID_IPropertyStore;
+ NativeCalls.VerifySucceeded((uint)NativeCalls.SHGetPropertyStoreForWindow(ptr, ref guid, out store));
+
+ using (PropVariant pv = new PropVariant())
+ {
+ NativeCalls.VerifySucceeded(store.GetValue(NativeValues.AppUserModelIDKey, pv));
+
+ string appUserModelId = pv.Value;
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ IntPtr handle = NativeCalls.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, (int)processId);
+
+ try
+ {
+ appUserModelId = NativeCalls.GetApplicationUserModelIdManaged(handle);
+ }
+ catch (Exception) { }
+ }
+
+
+ }
+ */
+
+ string appUserModelId = appResolver.GetAppIDForWindow(ptr);
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ appUserModelId = appResolver.GetAppIDForProcess(processId);
+ }
+
+ if (appUserModelId != null)
+ {
+ titles.Add(new Tuple(ptr, title, appUserModelId == null ? "NULL" : appUserModelId));
+ }
+ }
+
+ }
+ }
+
+ string selectedAppUserModelId = search.GetSelection("Select Window", "Available Windows:", titles.Select(t => new Tuple(t.Item3, t.Item2 + ": " + t.Item3)).ToList());
+
+ if (selectedAppUserModelId != null)
+ {
+ appUserModelIdBox.Text = selectedAppUserModelId;
+ }
+
+ hwndButton.Enabled = true;
+ }
}
}
diff --git a/ShortcutUtil/Program.cs b/ShortcutUtil/Program.cs
index 9b6f955..a46ce5b 100755
--- a/ShortcutUtil/Program.cs
+++ b/ShortcutUtil/Program.cs
@@ -5,6 +5,8 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
+using NativeHelpers;
+using System.Runtime.InteropServices;
namespace ShortcutUtil
{
@@ -16,6 +18,8 @@
[STAThread]
static void Main()
{
+ AppResolver appResolver = new AppResolver();
+
string[] args = Environment.GetCommandLineArgs();
if (args.Length < 2)
@@ -46,7 +50,7 @@
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new MainForm(entryList));
+ Application.Run(new MainForm(entryList, appResolver));
}
}
}
diff --git a/ShortcutUtil/SearchForm.Designer.cs b/ShortcutUtil/SearchForm.Designer.cs
index 93f58bf..350f243 100755
--- a/ShortcutUtil/SearchForm.Designer.cs
+++ b/ShortcutUtil/SearchForm.Designer.cs
@@ -55,6 +55,9 @@
//
// optionsList
//
+ this.optionsList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.optionsList.FormattingEnabled = true;
this.optionsList.ItemHeight = 20;
this.optionsList.Location = new System.Drawing.Point(17, 104);
@@ -64,6 +67,7 @@
//
// selectButton
//
+ this.selectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.selectButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.selectButton.Location = new System.Drawing.Point(661, 414);
this.selectButton.Name = "selectButton";
@@ -74,6 +78,8 @@
//
// searchBox
//
+ this.searchBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.searchBox.Location = new System.Drawing.Point(17, 37);
this.searchBox.Name = "searchBox";
this.searchBox.Size = new System.Drawing.Size(771, 26);
diff --git a/ShortcutUtil/ShortcutUtil.csproj b/ShortcutUtil/ShortcutUtil.csproj
index 975a545..3428eaa 100755
--- a/ShortcutUtil/ShortcutUtil.csproj
+++ b/ShortcutUtil/ShortcutUtil.csproj
@@ -35,6 +35,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Costura.Fody.4.1.0\lib\net40\Costura.dll
@@ -90,6 +112,10 @@
EntryList.cs
+
+ NativeHelpers.cs
+
+
Form
@@ -105,6 +131,7 @@
SearchForm.cs
+
Component
diff --git a/JumpListUtil.sln b/JumpListUtil.sln
index 165a98a..1c5678b 100755
--- a/JumpListUtil.sln
+++ b/JumpListUtil.sln
@@ -12,21 +12,35 @@
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.ActiveCfg = Debug|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Debug|x86.Build.0 = Debug|x86
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.ActiveCfg = Release|x86
+ {66F50737-A71D-4D5B-83F2-4F06B9F9F9B2}.Release|x86.Build.0 = Release|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.ActiveCfg = Debug|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Debug|x86.Build.0 = Debug|x86
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{443B8959-7F3D-4199-838C-7A805427CE42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.ActiveCfg = Release|x86
+ {443B8959-7F3D-4199-838C-7A805427CE42}.Release|x86.Build.0 = Release|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.ActiveCfg = Debug|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Debug|x86.Build.0 = Debug|x86
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.ActiveCfg = Release|x86
+ {91BAC03D-BBBB-403C-A8B0-2F70497F39BA}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JumpListUtil/JumpListUtil.csproj b/JumpListUtil/JumpListUtil.csproj
index 052af6c..378d940 100755
--- a/JumpListUtil/JumpListUtil.csproj
+++ b/JumpListUtil/JumpListUtil.csproj
@@ -47,6 +47,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
@@ -93,6 +115,9 @@
EntryList.cs
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/JumpListUtil/Program.cs b/JumpListUtil/Program.cs
index 6b8192c..2c1c3ff 100755
--- a/JumpListUtil/Program.cs
+++ b/JumpListUtil/Program.cs
@@ -8,15 +8,13 @@
using System.Threading;
using System.Windows.Forms;
using System.Windows.Shell;
+using NativeHelpers;
namespace JumpListUtil
{
static class Program
- {
- [DllImport("shell32.dll", SetLastError = true)]
- static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
-
+ {
///
/// The main entry point for the application.
///
@@ -97,7 +95,7 @@
}
}
- SetCurrentProcessExplicitAppUserModelID(appUserModelId);
+ NativeCalls.SetCurrentProcessExplicitAppUserModelID(appUserModelId);
List jumpItems = new List();
diff --git a/NativeHelpers.cs b/NativeHelpers.cs
new file mode 100755
index 0000000..154d692
--- /dev/null
+++ b/NativeHelpers.cs
@@ -0,0 +1,609 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Runtime.InteropServices.ComTypes;
+using ComTypes = System.Runtime.InteropServices.ComTypes;
+
+namespace NativeHelpers
+{
+ [Flags]
+ public enum ProcessAccessFlags : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VirtualMemoryOperation = 0x00000008,
+ VirtualMemoryRead = 0x00000010,
+ VirtualMemoryWrite = 0x00000020,
+ DuplicateHandle = 0x00000040,
+ CreateProcess = 0x000000080,
+ SetQuota = 0x00000100,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ QueryLimitedInformation = 0x00001000,
+ Synchronize = 0x00100000
+ }
+
+ public delegate bool EnumedWindow(IntPtr handleWindow, ref object lParam);
+ public enum GetAncestorFlags
+ {
+ ///
+ /// Retrieves the parent window. This does not include the owner, as it does with the GetParent function.
+ ///
+ GetParent = 1,
+ ///
+ /// Retrieves the root window by walking the chain of parent windows.
+ ///
+ GetRoot = 2,
+ ///
+ /// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
+ ///
+ GetRootOwner = 3
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TITLEBARINFO
+ {
+ public const int CCHILDREN_TITLEBAR = 5;
+ public uint cbSize;
+ public RECT rcTitleBar;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
+ public uint[] rgstate;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+ public Rectangle ToRectangle()
+ {
+ return Rectangle.FromLTRB(Left, Top, Right, Bottom);
+ }
+ public override string ToString()
+ {
+ return "Rect: " + ToRectangle().ToString();
+ }
+ }
+
+ public enum TBBStates
+ {
+ STATE_SYSTEM_UNAVAILABLE = 0x1,
+ STATE_SYSTEM_PRESSED = 0x8,
+ STATE_SYSTEM_INVISIBLE = 0x8000,
+ STATE_SYSTEM_OFFSCREEN = 0x10000,
+ STATE_SYSTEM_FOCUSABLE = 0x100000
+ }
+
+ public enum WindowLongParam
+ {
+ /// Sets a new address for the window procedure.
+ /// You cannot change this attribute if the window does not belong to the same process as the calling thread.
+ GWL_WNDPROC = -4,
+
+ /// Sets a new application instance handle.
+ GWLP_HINSTANCE = -6,
+
+ GWLP_HWNDPARENT = -8,
+
+ /// Sets a new identifier of the child window.
+ /// The window cannot be a top-level window.
+ GWL_ID = -12,
+
+ /// Sets a new window style.
+ GWL_STYLE = -16,
+
+ /// Sets a new extended window style.
+ /// See .
+ GWL_EXSTYLE = -20,
+
+ /// Sets the user data associated with the window.
+ /// This data is intended for use by the application that created the window. Its value is initially zero.
+ GWL_USERDATA = -21,
+
+ /// Sets the return value of a message processed in the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_MSGRESULT = 0,
+
+ /// Sets new extra information that is private to the application, such as handles or pointers.
+ /// Only applies to dialog boxes.
+ DWLP_USER = 8,
+
+ /// Sets the new address of the dialog box procedure.
+ /// Only applies to dialog boxes.
+ DWLP_DLGPROC = 4
+ }
+
+ [Flags]
+ public enum WindowStylesEx : uint
+ {
+ /// Specifies a window that accepts drag-drop files.
+ WS_EX_ACCEPTFILES = 0x00000010,
+
+ /// Forces a top-level window onto the taskbar when the window is visible.
+ WS_EX_APPWINDOW = 0x00040000,
+
+ /// Specifies a window that has a border with a sunken edge.
+ WS_EX_CLIENTEDGE = 0x00000200,
+
+ ///
+ /// Specifies a window that paints all descendants in bottom-to-top painting order using double-buffering.
+ /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. This style is not supported in Windows 2000.
+ ///
+ ///
+ /// With WS_EX_COMPOSITED set, all descendants of a window get bottom-to-top painting order using double-buffering.
+ /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects,
+ /// but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
+ /// Double-buffering allows the window and its descendents to be painted without flicker.
+ ///
+ WS_EX_COMPOSITED = 0x02000000,
+
+ ///
+ /// Specifies a window that includes a question mark in the title bar. When the user clicks the question mark,
+ /// the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
+ /// The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command.
+ /// The Help application displays a pop-up window that typically contains help for the child window.
+ /// WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+ ///
+ WS_EX_CONTEXTHELP = 0x00000400,
+
+ ///
+ /// Specifies a window which contains child windows that should take part in dialog box navigation.
+ /// If this style is specified, the dialog manager recurses into children of this window when performing navigation operations
+ /// such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+ ///
+ WS_EX_CONTROLPARENT = 0x00010000,
+
+ /// Specifies a window that has a double border.
+ WS_EX_DLGMODALFRAME = 0x00000001,
+
+ ///
+ /// Specifies a window that is a layered window.
+ /// This cannot be used for child windows or if the window has a class style of either CS_OWNDC or CS_CLASSDC.
+ ///
+ WS_EX_LAYERED = 0x00080000,
+
+ ///
+ /// Specifies a window with the horizontal origin on the right edge. Increasing horizontal values advance to the left.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LAYOUTRTL = 0x00400000,
+
+ /// Specifies a window that has generic left-aligned properties. This is the default.
+ WS_EX_LEFT = 0x00000000,
+
+ ///
+ /// Specifies a window with the vertical scroll bar (if present) to the left of the client area.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_LEFTSCROLLBAR = 0x00004000,
+
+ ///
+ /// Specifies a window that displays text using left-to-right reading-order properties. This is the default.
+ ///
+ WS_EX_LTRREADING = 0x00000000,
+
+ ///
+ /// Specifies a multiple-document interface (MDI) child window.
+ ///
+ WS_EX_MDICHILD = 0x00000040,
+
+ ///
+ /// Specifies a top-level window created with this style does not become the foreground window when the user clicks it.
+ /// The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
+ /// The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+ /// To activate the window, use the SetActiveWindow or SetForegroundWindow function.
+ ///
+ WS_EX_NOACTIVATE = 0x08000000,
+
+ ///
+ /// Specifies a window which does not pass its window layout to its child windows.
+ ///
+ WS_EX_NOINHERITLAYOUT = 0x00100000,
+
+ ///
+ /// Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+ ///
+ WS_EX_NOPARENTNOTIFY = 0x00000004,
+
+ ///
+ /// The window does not render to a redirection surface.
+ /// This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+ ///
+ WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
+
+ /// Specifies an overlapped window.
+ WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
+
+ /// Specifies a palette window, which is a modeless dialog box that presents an array of commands.
+ WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
+
+ ///
+ /// Specifies a window that has generic "right-aligned" properties. This depends on the window class.
+ /// The shell language must support reading-order alignment for this to take effect.
+ /// Using the WS_EX_RIGHT style has the same effect as using the SS_RIGHT (static), ES_RIGHT (edit), and BS_RIGHT/BS_RIGHTBUTTON (button) control styles.
+ ///
+ WS_EX_RIGHT = 0x00001000,
+
+ /// Specifies a window with the vertical scroll bar (if present) to the right of the client area. This is the default.
+ WS_EX_RIGHTSCROLLBAR = 0x00000000,
+
+ ///
+ /// Specifies a window that displays text using right-to-left reading-order properties.
+ /// The shell language must support reading-order alignment for this to take effect.
+ ///
+ WS_EX_RTLREADING = 0x00002000,
+
+ /// Specifies a window with a three-dimensional border style intended to be used for items that do not accept user input.
+ WS_EX_STATICEDGE = 0x00020000,
+
+ ///
+ /// Specifies a window that is intended to be used as a floating toolbar.
+ /// A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font.
+ /// A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
+ /// If a tool window has a system menu, its icon is not displayed on the title bar.
+ /// However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+ ///
+ WS_EX_TOOLWINDOW = 0x00000080,
+
+ ///
+ /// Specifies a window that should be placed above all non-topmost windows and should stay above them, even when the window is deactivated.
+ /// To add or remove this style, use the SetWindowPos function.
+ ///
+ WS_EX_TOPMOST = 0x00000008,
+
+ ///
+ /// Specifies a window that should not be painted until siblings beneath the window (that were created by the same thread) have been painted.
+ /// The window appears transparent because the bits of underlying sibling windows have already been painted.
+ /// To achieve transparency without these restrictions, use the SetWindowRgn function.
+ ///
+ WS_EX_TRANSPARENT = 0x00000020,
+
+ /// Specifies a window that has a border with a raised edge.
+ WS_EX_WINDOWEDGE = 0x00000100
+ }
+
+ // IShellLink Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("000214F9-0000-0000-C000-000000000046")]
+ public interface IShellLinkW
+ {
+ uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
+ int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
+ uint GetIDList(out IntPtr ppidl);
+ uint SetIDList(IntPtr pidl);
+ uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
+ int cchMaxName);
+ uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
+ uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
+ int cchMaxPath);
+ uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
+ uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
+ int cchMaxPath);
+ uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
+ uint GetHotKey(out ushort pwHotkey);
+ uint SetHotKey(ushort wHotKey);
+ uint GetShowCmd(out int piShowCmd);
+ uint SetShowCmd(int iShowCmd);
+ uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
+ int cchIconPath, out int piIcon);
+ uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
+ uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
+ uint dwReserved);
+ uint Resolve(IntPtr hwnd, uint fFlags);
+ uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
+ }
+
+ // ShellLink CoClass (ShellLink object)
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("00021401-0000-0000-C000-000000000046")]
+ public class CShellLink { }
+
+ // WIN32_FIND_DATAW Structure
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ public struct WIN32_FIND_DATAW
+ {
+ public uint dwFileAttributes;
+ public ComTypes.FILETIME ftCreationTime;
+ public ComTypes.FILETIME ftLastAccessTime;
+ public ComTypes.FILETIME ftLastWriteTime;
+ public uint nFileSizeHigh;
+ public uint nFileSizeLow;
+ public uint dwReserved0;
+ public uint dwReserved1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeValues.MAX_PATH)]
+ public string cFileName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string cAlternateFileName;
+ }
+
+ // IPropertyStore Interface
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
+ public interface IPropertyStore
+ {
+ uint GetCount([Out] out uint cProps);
+ uint GetAt([In] uint iProp, out PropertyKey pkey);
+ uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
+ uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
+ uint Commit();
+ }
+
+ // PropertyKey Structure
+ // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ public struct PropertyKey
+ {
+ #region Fields
+
+ private Guid formatId; // Unique GUID for property
+ private Int32 propertyId; // Property identifier (PID)
+
+ #endregion
+
+ #region Public Properties
+
+ public Guid FormatId
+ {
+ get
+ {
+ return formatId;
+ }
+ }
+
+ public Int32 PropertyId
+ {
+ get
+ {
+ return propertyId;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropertyKey(Guid formatId, Int32 propertyId)
+ {
+ this.formatId = formatId;
+ this.propertyId = propertyId;
+ }
+
+ public PropertyKey(string formatId, Int32 propertyId)
+ {
+ this.formatId = new Guid(formatId);
+ this.propertyId = propertyId;
+ }
+
+ #endregion
+ }
+
+ // PropVariant Class (only for string value)
+ // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
+ // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
+ // /interop-with-propvariants-in-net.aspx
+ [StructLayout(LayoutKind.Explicit)]
+ public sealed class PropVariant : IDisposable
+ {
+ #region Fields
+
+ [FieldOffset(0)]
+ ushort valueType; // Value type
+
+ // [FieldOffset(2)]
+ // ushort wReserved1; // Reserved field
+ // [FieldOffset(4)]
+ // ushort wReserved2; // Reserved field
+ // [FieldOffset(6)]
+ // ushort wReserved3; // Reserved field
+
+ [FieldOffset(8)]
+ IntPtr ptr; // Value
+
+ #endregion
+
+ #region Public Properties
+
+ // Value type (System.Runtime.InteropServices.VarEnum)
+ public VarEnum VarType
+ {
+ get { return (VarEnum)valueType; }
+ set { valueType = (ushort)value; }
+ }
+
+ // Whether value is empty or null
+ public bool IsNullOrEmpty
+ {
+ get
+ {
+ return (valueType == (ushort)VarEnum.VT_EMPTY ||
+ valueType == (ushort)VarEnum.VT_NULL);
+ }
+ }
+
+ // Value (only for string value)
+ public string Value
+ {
+ get
+ {
+ return Marshal.PtrToStringUni(ptr);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public PropVariant()
+ { }
+
+ // Construct with string value
+ public PropVariant(string value)
+ {
+ if (value == null)
+ throw new ArgumentException("Failed to set value.");
+
+ valueType = (ushort)VarEnum.VT_LPWSTR;
+ ptr = Marshal.StringToCoTaskMemUni(value);
+ }
+
+ #endregion
+
+ #region Destructor
+
+ ~PropVariant()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ NativeCalls.PropVariantClear(this);
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+ }
+
+ public static class NativeValues
+ {
+ public const int MAX_PATH = 260;
+ public const int INFOTIPSIZE = 1024;
+
+ public const int STGM_READ = 0x00000000; // STGM constants
+ public const int STGM_WRITE= 0x00000001; // STGM constants
+ public const int STGM_READWRITE = 0x00000002; // STGM constants
+ public const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
+
+ // Name = System.AppUserModel.ID
+ // ShellPKey = PKEY_AppUserModel_ID
+ // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
+ // PropID = 5
+ // Type = String (VT_LPWSTR)
+ public static readonly PropertyKey AppUserModelIDKey =
+ new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
+
+ public static readonly Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
+ }
+
+ public static class NativeCalls
+ {
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
+
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ref object lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetLastActivePopup(IntPtr hWnd);
+
+
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
+ public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ public static string GetWindowTextManaged(IntPtr hWnd)
+ {
+ // Allocate correct string length first
+ int length = GetWindowTextLength(hWnd);
+ StringBuilder sb = new StringBuilder(length + 1);
+ GetWindowText(hWnd, sb, sb.Capacity);
+ return sb.ToString();
+ }
+
+ public static bool IsAltTabWindow(IntPtr hwnd)
+ {
+ TITLEBARINFO ti = new TITLEBARINFO();
+
+ if (!IsWindowVisible(hwnd)) return false;
+
+ IntPtr hwndWalk = IntPtr.Zero;
+ IntPtr hwndTry = GetAncestor(hwnd, GetAncestorFlags.GetRootOwner);
+
+ while (hwndTry != hwndWalk)
+ {
+ hwndWalk = hwndTry;
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (IsWindowVisible(hwndTry)) break;
+ }
+ if (hwndWalk != hwnd) return false;
+
+ // the following removes some task tray programs and "Program Manager"
+ ti.cbSize = (uint)Marshal.SizeOf(typeof(TITLEBARINFO));
+ GetTitleBarInfo(hwnd, ref ti);
+ if ((ti.rgstate[0] & (uint)TBBStates.STATE_SYSTEM_INVISIBLE) == (uint)TBBStates.STATE_SYSTEM_INVISIBLE) return false;
+
+ // Tool windows should not be displayed either, these do not appear in the
+ // task bar.
+ if (((WindowStylesEx)GetWindowLongPtr(hwnd, (int)WindowLongParam.GWL_EXSTYLE) & WindowStylesEx.WS_EX_TOOLWINDOW) == WindowStylesEx.WS_EX_TOOLWINDOW) return false;
+
+ return true;
+ }
+
+ [DllImport("Ole32.dll", PreserveSig = false)]
+ public extern static void PropVariantClear([In, Out] PropVariant pvar);
+
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ public static extern int SHGetPropertyStoreForWindow(IntPtr handle, ref Guid riid, out IPropertyStore propertyStore);
+
+ // Verify if operation succeeded.
+ public static void VerifySucceeded(uint hresult)
+ {
+ if (hresult > 1)
+ throw new InvalidOperationException("Failed with HRESULT: " +
+ hresult.ToString("X"));
+ }
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetApplicationUserModelId(IntPtr hProcess, ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetApplicationUserModelIdManaged(IntPtr hProcess)
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetApplicationUserModelId(hProcess, ref size, sb));
+ return sb.ToString();
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ public static extern Int32 GetCurrentApplicationUserModelId(ref UInt32 AppModelIDLength, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
+
+ public static string GetCurrentApplicationUserModelIdManaged()
+ {
+ UInt32 size = 256;
+ StringBuilder sb = new StringBuilder((int)size);
+ VerifySucceeded((uint)GetCurrentApplicationUserModelId(ref size, sb));
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/SetLnkApp/MainForm.cs b/SetLnkApp/MainForm.cs
index bfdb731..3c98b40 100755
--- a/SetLnkApp/MainForm.cs
+++ b/SetLnkApp/MainForm.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
diff --git a/SetLnkApp/Program.cs b/SetLnkApp/Program.cs
index 023999d..d32eac1 100755
--- a/SetLnkApp/Program.cs
+++ b/SetLnkApp/Program.cs
@@ -1,4 +1,4 @@
-using ShellLinkPlus;
+using NativeHelpers;
using System;
using System.Collections.Generic;
using System.IO;
@@ -29,7 +29,7 @@
{
shortcut = new ShellLink(args[1]);
}
- catch (Exception e)
+ catch (Exception)
{
Usage();
return;
diff --git a/SetLnkApp/SetLnkApp.csproj b/SetLnkApp/SetLnkApp.csproj
index ec4d625..379cd46 100755
--- a/SetLnkApp/SetLnkApp.csproj
+++ b/SetLnkApp/SetLnkApp.csproj
@@ -32,6 +32,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
@@ -46,6 +68,9 @@
+
+ NativeHelpers.cs
+
ShellLink.cs
diff --git a/ShellLink.cs b/ShellLink.cs
index 6d13f4e..ba4d16d 100755
--- a/ShellLink.cs
+++ b/ShellLink.cs
@@ -1,15 +1,15 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
+
using System.Text;
-using ComTypes = System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices.ComTypes;
/****************************************************************************
* Code From: https://emoacht.wordpress.com/2012/11/14/csharp-appusermodelid/
***************************************************************************/
-namespace ShellLinkPlus
+namespace NativeHelpers
{
// Modified from http://smdn.jp/programming/tips/createlnk/
// Originally from http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects
@@ -17,236 +17,10 @@
// Partly based on Sending toast notifications from desktop apps sample
public class ShellLink : IDisposable
{
- #region Win32 and COM
-
- // IShellLink Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("000214F9-0000-0000-C000-000000000046")]
- private interface IShellLinkW
- {
- uint GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
- int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
- uint GetIDList(out IntPtr ppidl);
- uint SetIDList(IntPtr pidl);
- uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName,
- int cchMaxName);
- uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
- uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
- int cchMaxPath);
- uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
- uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
- int cchMaxPath);
- uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
- uint GetHotKey(out ushort pwHotkey);
- uint SetHotKey(ushort wHotKey);
- uint GetShowCmd(out int piShowCmd);
- uint SetShowCmd(int iShowCmd);
- uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
- int cchIconPath, out int piIcon);
- uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
- uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
- uint dwReserved);
- uint Resolve(IntPtr hwnd, uint fFlags);
- uint SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
- }
-
- // ShellLink CoClass (ShellLink object)
- [ComImport,
- ClassInterface(ClassInterfaceType.None),
- Guid("00021401-0000-0000-C000-000000000046")]
- private class CShellLink { }
-
- // WIN32_FIND_DATAW Structure
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
- private struct WIN32_FIND_DATAW
- {
- public uint dwFileAttributes;
- public ComTypes.FILETIME ftCreationTime;
- public ComTypes.FILETIME ftLastAccessTime;
- public ComTypes.FILETIME ftLastWriteTime;
- public uint nFileSizeHigh;
- public uint nFileSizeLow;
- public uint dwReserved0;
- public uint dwReserved1;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
- public string cFileName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
- public string cAlternateFileName;
- }
-
- // IPropertyStore Interface
- [ComImport,
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
- Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
- private interface IPropertyStore
- {
- uint GetCount([Out] out uint cProps);
- uint GetAt([In] uint iProp, out PropertyKey pkey);
- uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
- uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
- uint Commit();
- }
-
- // PropertyKey Structure
- // Narrowed down from PropertyKey.cs of Windows API Code Pack 1.1
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct PropertyKey
- {
- #region Fields
-
- private Guid formatId; // Unique GUID for property
- private Int32 propertyId; // Property identifier (PID)
-
- #endregion
-
- #region Public Properties
-
- public Guid FormatId
- {
- get
- {
- return formatId;
- }
- }
-
- public Int32 PropertyId
- {
- get
- {
- return propertyId;
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropertyKey(Guid formatId, Int32 propertyId)
- {
- this.formatId = formatId;
- this.propertyId = propertyId;
- }
-
- public PropertyKey(string formatId, Int32 propertyId)
- {
- this.formatId = new Guid(formatId);
- this.propertyId = propertyId;
- }
-
- #endregion
- }
-
- // PropVariant Class (only for string value)
- // Narrowed down from PropVariant.cs of Windows API Code Pack 1.1
- // Originally from http://blogs.msdn.com/b/adamroot/archive/2008/04/11
- // /interop-with-propvariants-in-net.aspx
- [StructLayout(LayoutKind.Explicit)]
- private sealed class PropVariant : IDisposable
- {
- #region Fields
-
- [FieldOffset(0)]
- ushort valueType; // Value type
-
- // [FieldOffset(2)]
- // ushort wReserved1; // Reserved field
- // [FieldOffset(4)]
- // ushort wReserved2; // Reserved field
- // [FieldOffset(6)]
- // ushort wReserved3; // Reserved field
-
- [FieldOffset(8)]
- IntPtr ptr; // Value
-
- #endregion
-
- #region Public Properties
-
- // Value type (System.Runtime.InteropServices.VarEnum)
- public VarEnum VarType
- {
- get { return (VarEnum)valueType; }
- set { valueType = (ushort)value; }
- }
-
- // Whether value is empty or null
- public bool IsNullOrEmpty
- {
- get
- {
- return (valueType == (ushort)VarEnum.VT_EMPTY ||
- valueType == (ushort)VarEnum.VT_NULL);
- }
- }
-
- // Value (only for string value)
- public string Value
- {
- get
- {
- return Marshal.PtrToStringUni(ptr);
- }
- }
-
- #endregion
-
- #region Constructor
-
- public PropVariant()
- { }
-
- // Construct with string value
- public PropVariant(string value)
- {
- if (value == null)
- throw new ArgumentException("Failed to set value.");
-
- valueType = (ushort)VarEnum.VT_LPWSTR;
- ptr = Marshal.StringToCoTaskMemUni(value);
- }
-
- #endregion
-
- #region Destructor
-
- ~PropVariant()
- {
- Dispose();
- }
-
- public void Dispose()
- {
- PropVariantClear(this);
- GC.SuppressFinalize(this);
- }
-
- #endregion
- }
-
- [DllImport("Ole32.dll", PreserveSig = false)]
- private extern static void PropVariantClear([In, Out] PropVariant pvar);
-
- #endregion
-
#region Fields
private IShellLinkW shellLinkW = null;
- // Name = System.AppUserModel.ID
- // ShellPKey = PKEY_AppUserModel_ID
- // FormatID = 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3
- // PropID = 5
- // Type = String (VT_LPWSTR)
- private readonly PropertyKey AppUserModelIDKey =
- new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
-
- private const int MAX_PATH = 260;
- private const int INFOTIPSIZE = 1024;
-
- private const int STGM_READ = 0x00000000; // STGM constants
- private const uint SLGP_UNCPRIORITY = 0x0002; // SLGP flags
-
#endregion
#region Private Properties (Interfaces)
@@ -300,18 +74,18 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder targetPath = new StringBuilder(MAX_PATH);
+ StringBuilder targetPath = new StringBuilder(NativeValues.MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
- VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
- SLGP_UNCPRIORITY));
+ NativeCalls.VerifySucceeded(shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data,
+ NativeValues.SLGP_UNCPRIORITY));
return targetPath.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetPath(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetPath(value));
}
}
@@ -320,15 +94,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder arguments = new StringBuilder(INFOTIPSIZE);
+ StringBuilder arguments = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(arguments, arguments.Capacity));
return arguments.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetArguments(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetArguments(value));
}
}
@@ -337,15 +111,15 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder description = new StringBuilder(INFOTIPSIZE);
+ StringBuilder description = new StringBuilder(NativeValues.INFOTIPSIZE);
- VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
+ NativeCalls.VerifySucceeded(shellLinkW.GetArguments(description, description.Capacity));
return description.ToString();
}
set
{
- VerifySucceeded(shellLinkW.SetDescription(value));
+ NativeCalls.VerifySucceeded(shellLinkW.SetDescription(value));
}
}
@@ -354,16 +128,16 @@
get
{
// No limitation to length of buffer string in the case of Unicode though.
- StringBuilder icon = new StringBuilder(INFOTIPSIZE);
+ StringBuilder icon = new StringBuilder(NativeValues.INFOTIPSIZE);
int index;
- VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
+ NativeCalls.VerifySucceeded(shellLinkW.GetIconLocation(icon, icon.Capacity, out index));
return new Tuple(icon.ToString(), index);
}
set
{
- VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
+ NativeCalls.VerifySucceeded(shellLinkW.SetIconLocation(value.Item1, value.Item2));
}
}
@@ -374,7 +148,7 @@
{
using (PropVariant pv = new PropVariant())
{
- VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.GetValue(NativeValues.AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
@@ -386,8 +160,8 @@
{
using (PropVariant pv = new PropVariant(value))
{
- VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
- VerifySucceeded(PropertyStore.Commit());
+ NativeCalls.VerifySucceeded(PropertyStore.SetValue(NativeValues.AppUserModelIDKey, pv));
+ NativeCalls.VerifySucceeded(PropertyStore.Commit());
}
}
}
@@ -470,15 +244,7 @@
if (!File.Exists(file))
throw new FileNotFoundException("File is not found.", file);
else
- PersistFile.Load(file, STGM_READ);
- }
-
- // Verify if operation succeeded.
- public static void VerifySucceeded(uint hresult)
- {
- if (hresult > 1)
- throw new InvalidOperationException("Failed with HRESULT: " +
- hresult.ToString("X"));
+ PersistFile.Load(file, NativeValues.STGM_READWRITE);
}
#endregion
diff --git a/ShortcutUtil/AppResolver.cs b/ShortcutUtil/AppResolver.cs
new file mode 100755
index 0000000..6daf0b5
--- /dev/null
+++ b/ShortcutUtil/AppResolver.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.System.Update;
+
+namespace NativeHelpers
+{
+ // CLSID_StartMenuCacheAndAppResolver {660b90c8-73a9-4b58-8cae-355b7f55341b}
+ [ComImport,
+ ClassInterface(ClassInterfaceType.None),
+ Guid("660b90c8-73a9-4b58-8cae-355b7f55341b")]
+ public class CStartMenuCacheAndAppResolver { }
+
+ public class AppResolver
+ {
+ IAppResolver_7 app7 = null;
+ IAppResolver_8 app8 = null;
+ public AppResolver()
+ {
+ Exception last = null;
+ try
+ {
+ app8 = (IAppResolver_8)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app8 = null;
+ }
+
+ if (app8 == null)
+ {
+ try
+ {
+ app7 = (IAppResolver_7)new CStartMenuCacheAndAppResolver();
+ }
+ catch (Exception e)
+ {
+ last = e;
+ app7 = null;
+ }
+ }
+
+ if (app7 == null && app8 == null)
+ {
+ throw last;
+ }
+ }
+
+ public string GetAppIDForWindow(IntPtr hWnd)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForWindow(hWnd, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+
+ public string GetAppIDForProcess(UInt32 processId)
+ {
+ IntPtr output = IntPtr.Zero;
+ if (app7 != null)
+ {
+ app7.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+ else if (app8 != null)
+ {
+ app8.GetAppIDForProcess(processId, ref output, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ if (output != IntPtr.Zero)
+ {
+ return Marshal.PtrToStringUni(output);
+ }
+ return null;
+ }
+ }
+
+ // IID_IAppResolver_7 {46a6eeff-908e-4dc6-92a6-64be9177b41c}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("46a6eeff-908e-4dc6-92a6-64be9177b41c")]
+ public interface IAppResolver_7
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+
+ // IID_IAppResolver_8 {de25675a-72de-44b4-9373-05170450c140}
+ [ComImport,
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
+ Guid("de25675a-72de-44b4-9373-05170450c140")]
+ public interface IAppResolver_8
+ {
+ uint GetAppIDForShortcut();
+ uint GetAppIDForShortcutObject();
+ uint GetAppIDForWindow(IntPtr hWnd, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ uint GetAppIDForProcess(UInt32 dwProcessId, ref IntPtr pszAppId, IntPtr pUnknown1, IntPtr pUnknown2, IntPtr pUnknown3);
+ }
+}
diff --git a/ShortcutUtil/MainForm.Designer.cs b/ShortcutUtil/MainForm.Designer.cs
index 5dbf023..8af74c7 100755
--- a/ShortcutUtil/MainForm.Designer.cs
+++ b/ShortcutUtil/MainForm.Designer.cs
@@ -48,6 +48,9 @@
//
// entryListBox
//
+ this.entryListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.entryListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
this.entryListBox.FormattingEnabled = true;
this.entryListBox.Location = new System.Drawing.Point(16, 98);
@@ -59,6 +62,7 @@
//
// createButton
//
+ this.createButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.createButton.Location = new System.Drawing.Point(644, 458);
this.createButton.Name = "createButton";
this.createButton.Size = new System.Drawing.Size(144, 40);
@@ -77,6 +81,8 @@
//
// appUserModelIdBox
//
+ this.appUserModelIdBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.appUserModelIdBox.Location = new System.Drawing.Point(16, 35);
this.appUserModelIdBox.Name = "appUserModelIdBox";
this.appUserModelIdBox.Size = new System.Drawing.Size(608, 26);
@@ -86,6 +92,7 @@
//
// appButton
//
+ this.appButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.appButton.Location = new System.Drawing.Point(633, 35);
this.appButton.Name = "appButton";
this.appButton.Size = new System.Drawing.Size(74, 31);
@@ -96,6 +103,7 @@
//
// hwndButton
//
+ this.hwndButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.hwndButton.Location = new System.Drawing.Point(712, 35);
this.hwndButton.MinimumSize = new System.Drawing.Size(76, 26);
this.hwndButton.Name = "hwndButton";
@@ -103,6 +111,7 @@
this.hwndButton.TabIndex = 6;
this.hwndButton.Text = "HWND";
this.hwndButton.UseVisualStyleBackColor = true;
+ this.hwndButton.Click += new System.EventHandler(this.hwndButton_Click);
//
// MainForm
//
@@ -119,8 +128,6 @@
this.Controls.Add(this.defaultShortcutLabel);
this.Name = "MainForm";
this.Text = "Form1";
- this.Shown += new System.EventHandler(this.MainForm_Shown);
- this.SizeChanged += new System.EventHandler(this.MainForm_SizeChanged);
this.ResumeLayout(false);
this.PerformLayout();
diff --git a/ShortcutUtil/MainForm.cs b/ShortcutUtil/MainForm.cs
index 680ed45..c654b19 100755
--- a/ShortcutUtil/MainForm.cs
+++ b/ShortcutUtil/MainForm.cs
@@ -1,5 +1,7 @@
using Entries;
+using NativeHelpers;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
@@ -23,11 +25,9 @@
private Font nameFont;
private Brush fontBrush;
- private bool shown = false;
- private Size listSizeOffset;
- private Point buttonOffset;
+ private AppResolver appResolver;
- public MainForm(EntryList entryList)
+ public MainForm(EntryList entryList, AppResolver appResolver)
{
InitializeComponent();
@@ -38,6 +38,7 @@
fontBrush = new SolidBrush(defaultShortcutLabel.ForeColor);
this.entryList = entryList;
+ this.appResolver = appResolver;
entryListBox.Items.AddRange(this.entryList.Entries.ToArray());
@@ -122,23 +123,6 @@
e.ItemHeight = Size.Add(IconSize, new Size(0, ItemPadding.Height * 2)).Height;
}
- private void MainForm_SizeChanged(object sender, EventArgs e)
- {
- if (shown)
- {
- entryListBox.Size = Size.Subtract(Size, listSizeOffset);
- createButton.Location = Point.Add(buttonOffset, entryListBox.Size);
- }
- }
-
- private void MainForm_Shown(object sender, EventArgs e)
- {
- listSizeOffset = Size.Subtract(Size, entryListBox.Size);
- buttonOffset = Point.Subtract(createButton.Location, entryListBox.Size);
-
- shown = true;
- }
-
private SearchForm search = new SearchForm();
private async void appButton_Click(object sender, EventArgs e)
{
@@ -166,5 +150,83 @@
appButton.Enabled = true;
}
+
+ private static bool GetWindowHandle(IntPtr windowHandle, ref object windowHandles)
+ {
+ ((ArrayList)windowHandles).Add(windowHandle);
+ return true;
+ }
+
+ private void hwndButton_Click(object sender, EventArgs e)
+ {
+ hwndButton.Enabled = false;
+
+ object handles = new ArrayList();
+ NativeCalls.EnumWindows(GetWindowHandle, ref handles);
+
+ List> titles = new List>();
+ foreach (object ptrObj in (ArrayList)handles)
+ {
+ IntPtr ptr = (IntPtr)ptrObj;
+ if (NativeCalls.IsAltTabWindow(ptr))
+ {
+ string title = NativeCalls.GetWindowTextManaged(ptr);
+ if (title != "")
+ {
+ /*
+ IPropertyStore store;
+ Guid guid = NativeValues.IID_IPropertyStore;
+ NativeCalls.VerifySucceeded((uint)NativeCalls.SHGetPropertyStoreForWindow(ptr, ref guid, out store));
+
+ using (PropVariant pv = new PropVariant())
+ {
+ NativeCalls.VerifySucceeded(store.GetValue(NativeValues.AppUserModelIDKey, pv));
+
+ string appUserModelId = pv.Value;
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ IntPtr handle = NativeCalls.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, (int)processId);
+
+ try
+ {
+ appUserModelId = NativeCalls.GetApplicationUserModelIdManaged(handle);
+ }
+ catch (Exception) { }
+ }
+
+
+ }
+ */
+
+ string appUserModelId = appResolver.GetAppIDForWindow(ptr);
+ if (appUserModelId == null)
+ {
+ uint processId;
+ NativeCalls.GetWindowThreadProcessId(ptr, out processId);
+
+ appUserModelId = appResolver.GetAppIDForProcess(processId);
+ }
+
+ if (appUserModelId != null)
+ {
+ titles.Add(new Tuple(ptr, title, appUserModelId == null ? "NULL" : appUserModelId));
+ }
+ }
+
+ }
+ }
+
+ string selectedAppUserModelId = search.GetSelection("Select Window", "Available Windows:", titles.Select(t => new Tuple(t.Item3, t.Item2 + ": " + t.Item3)).ToList());
+
+ if (selectedAppUserModelId != null)
+ {
+ appUserModelIdBox.Text = selectedAppUserModelId;
+ }
+
+ hwndButton.Enabled = true;
+ }
}
}
diff --git a/ShortcutUtil/Program.cs b/ShortcutUtil/Program.cs
index 9b6f955..a46ce5b 100755
--- a/ShortcutUtil/Program.cs
+++ b/ShortcutUtil/Program.cs
@@ -5,6 +5,8 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
+using NativeHelpers;
+using System.Runtime.InteropServices;
namespace ShortcutUtil
{
@@ -16,6 +18,8 @@
[STAThread]
static void Main()
{
+ AppResolver appResolver = new AppResolver();
+
string[] args = Environment.GetCommandLineArgs();
if (args.Length < 2)
@@ -46,7 +50,7 @@
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new MainForm(entryList));
+ Application.Run(new MainForm(entryList, appResolver));
}
}
}
diff --git a/ShortcutUtil/SearchForm.Designer.cs b/ShortcutUtil/SearchForm.Designer.cs
index 93f58bf..350f243 100755
--- a/ShortcutUtil/SearchForm.Designer.cs
+++ b/ShortcutUtil/SearchForm.Designer.cs
@@ -55,6 +55,9 @@
//
// optionsList
//
+ this.optionsList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.optionsList.FormattingEnabled = true;
this.optionsList.ItemHeight = 20;
this.optionsList.Location = new System.Drawing.Point(17, 104);
@@ -64,6 +67,7 @@
//
// selectButton
//
+ this.selectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.selectButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.selectButton.Location = new System.Drawing.Point(661, 414);
this.selectButton.Name = "selectButton";
@@ -74,6 +78,8 @@
//
// searchBox
//
+ this.searchBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.searchBox.Location = new System.Drawing.Point(17, 37);
this.searchBox.Name = "searchBox";
this.searchBox.Size = new System.Drawing.Size(771, 26);
diff --git a/ShortcutUtil/ShortcutUtil.csproj b/ShortcutUtil/ShortcutUtil.csproj
index 975a545..3428eaa 100755
--- a/ShortcutUtil/ShortcutUtil.csproj
+++ b/ShortcutUtil/ShortcutUtil.csproj
@@ -35,6 +35,28 @@
prompt
4
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ 7.3
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
..\packages\Costura.Fody.4.1.0\lib\net40\Costura.dll
@@ -90,6 +112,10 @@
EntryList.cs
+
+ NativeHelpers.cs
+
+
Form
@@ -105,6 +131,7 @@
SearchForm.cs
+
Component
diff --git a/ShortcutUtil/TTLib.cs b/ShortcutUtil/TTLib.cs
new file mode 100755
index 0000000..1b1823e
--- /dev/null
+++ b/ShortcutUtil/TTLib.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NativeHelpers
+{
+ public static class TTLib
+ {
+
+ // Errors returned by TTLib_Init
+ public enum InitResult : UInt32
+ {
+ OK = 0,
+ ERR_INIT_ALREADY_INITIALIZED,
+ ERR_INIT_REGISTER_MESSAGE,
+ ERR_INIT_FILE_MAPPING,
+ ERR_INIT_VIEW_MAPPING,
+ }
+
+ // Errors returned by TTLib_LoadIntoExplorer
+ public enum LoadIntoExplorerResult : UInt32
+ {
+ OK = 0,
+ ERR_EXE_NOT_INITIALIZED,
+ ERR_EXE_ALREADY_LOADED,
+ ERR_EXE_FIND_TASKBAR,
+ ERR_EXE_OPEN_PROCESS,
+ ERR_EXE_VIRTUAL_ALLOC,
+ ERR_EXE_WRITE_PROC_MEM,
+ ERR_EXE_CREATE_REMOTE_THREAD,
+ ERR_EXE_READ_PROC_MEM,
+
+ ERR_INJ_BEFORE_RUN = 101,
+ ERR_INJ_BEFORE_GETMODULEHANDLE,
+ ERR_INJ_BEFORE_LOADLIBRARY,
+ ERR_INJ_BEFORE_GETPROCADDR,
+ ERR_INJ_BEFORE_LIBINIT,
+ ERR_INJ_GETMODULEHANDLE,
+ ERR_INJ_LOADLIBRARY,
+ ERR_INJ_GETPROCADDR,
+
+ ERR_LIB_INIT_ALREADY_CALLED = 201,
+ ERR_LIB_LIB_VER_MISMATCH,
+ ERR_LIB_WIN_VER_MISMATCH,
+ ERR_LIB_VIEW_MAPPING,
+ ERR_LIB_FIND_IMPORT,
+ ERR_LIB_WND_TASKBAR,
+ ERR_LIB_WND_TASKSW,
+ ERR_LIB_WND_TASKLIST,
+ ERR_LIB_WND_THUMB,
+ ERR_LIB_MSG_DLL_INIT,
+ ERR_LIB_WAITTHREAD,
+
+ ERR_LIB_EXTHREAD_MINHOOK = 301,
+ ERR_LIB_EXTHREAD_MINHOOK_PRELOADED,
+ ERR_LIB_EXTHREAD_COMFUNCHOOK,
+ ERR_LIB_EXTHREAD_REFRESHTASKBAR,
+ ERR_LIB_EXTHREAD_MINHOOK_APPLY,
+ }
+
+ public enum GroupType : UInt32
+ {
+ UNKNOWN = 0,
+ NORMAL,
+ PINNED,
+ COMBINED,
+ TEMPORARY,
+ }
+
+ public enum List : UInt32
+ {
+ LABEL = 0,
+ GROUP,
+ GROUPPINNED,
+ COMBINE,
+ }
+
+ public enum ListValue : UInt32
+ {
+ LABEL_NEVER = 0,
+ LABEL_ALWAYS,
+
+ GROUP_NEVER = 0,
+ GROUP_ALWAYS,
+
+ GROUPPINNED_NEVER = 0,
+ GROUPPINNED_ALWAYS,
+
+ COMBINE_NEVER = 0,
+ COMBINE_ALWAYS,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left, Top, Right, Bottom;
+
+ public RECT(int left, int top, int right, int bottom)
+ {
+ Left = left;
+ Top = top;
+ Right = right;
+ Bottom = bottom;
+ }
+
+ public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { }
+
+ public int X
+ {
+ get { return Left; }
+ set { Right -= (Left - value); Left = value; }
+ }
+
+ public int Y
+ {
+ get { return Top; }
+ set { Bottom -= (Top - value); Top = value; }
+ }
+
+ public int Height
+ {
+ get { return Bottom - Top; }
+ set { Bottom = value + Top; }
+ }
+
+ public int Width
+ {
+ get { return Right - Left; }
+ set { Right = value + Left; }
+ }
+
+ public System.Drawing.Point Location
+ {
+ get { return new System.Drawing.Point(Left, Top); }
+ set { X = value.X; Y = value.Y; }
+ }
+
+ public System.Drawing.Size Size
+ {
+ get { return new System.Drawing.Size(Width, Height); }
+ set { Width = value.Width; Height = value.Height; }
+ }
+
+ public static implicit operator System.Drawing.Rectangle(RECT r)
+ {
+ return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
+ }
+
+ public static implicit operator RECT(System.Drawing.Rectangle r)
+ {
+ return new RECT(r);
+ }
+
+ public static bool operator ==(RECT r1, RECT r2)
+ {
+ return r1.Equals(r2);
+ }
+
+ public static bool operator !=(RECT r1, RECT r2)
+ {
+ return !r1.Equals(r2);
+ }
+
+ public bool Equals(RECT r)
+ {
+ return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is RECT)
+ return Equals((RECT)obj);
+ else if (obj is System.Drawing.Rectangle)
+ return Equals(new RECT((System.Drawing.Rectangle)obj));
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return ((System.Drawing.Rectangle)this).GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
+ }
+ }
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_Init", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern InitResult Init();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_Uninit", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool Uninit();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_LoadIntoExplorer", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern LoadIntoExplorerResult LoadIntoExplorer();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_IsLoadedIntoExplorer", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool IsLoadedIntoExplorer();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_UnloadFromExplorer", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool UnloadFromExplorer();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_ManipulationStart", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool ManipulationStart();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_ManipulationEnd", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool ManipulationEnd();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetMainTaskbar", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetMainTaskbar();
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetSecondaryTaskbarCount", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool GetSecondaryTaskbarCount(out Int32 pnCount);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetSecondaryTaskbar", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetSecondaryTaskbar(Int32 nIndex);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetTaskListWindow", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetTaskListWindow(IntPtr hTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetTaskbarWindow", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetTaskbarWindow(IntPtr hTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetTaskbarMonitor", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetTaskbarMonitor(IntPtr hTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonGroupCount", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool GetButtonGroupCount(IntPtr hTaskbar, out Int32 pnCount);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonGroup", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetButtonGroup(IntPtr hTaskbar, Int32 nIndex);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetActiveButtonGroup", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetActiveButtonGroup(IntPtr hTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetTrackedButtonGroup", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetTrackedButtonGroup(IntPtr hTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_ButtonGroupMove", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool ButtonGroupMove(IntPtr hTaskbar, Int32 nIndexFrom, Int32 nIndexTo);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonGroupTaskbar", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool GetButtonGroupTaskbar(IntPtr hButtonGroup, out IntPtr phTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonGroupRect", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool GetButtonGroupRect(IntPtr hButtonGroup, out RECT pRect);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonGroupType", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool GetButtonGroupType(IntPtr hButtonGroup, out GroupType pnType);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonGroupAppId", SetLastError = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
+ public static extern UInt32 GetButtonGroupAppId(IntPtr hButtonGroup, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszAppId, UInt32 nMaxSize);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonCount", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool GetButtonCount(IntPtr hButtonGroup, out Int32 pnCount);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButton", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetButton(IntPtr hButtonGroup, Int32 nIndex);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetActiveButton", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetActiveButton(IntPtr hTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetTrackedButton", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetTrackedButton(IntPtr hTaskbar);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_ButtonMoveInButtonGroup", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool ButtonMoveInButtonGroup(IntPtr hButtonGroup, Int32 nIndexFrom, Int32 nIndexTo);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetButtonWindow", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr GetButtonWindow(IntPtr hButton);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_AddAppIdToList", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool AddAppIdToList(List nList, [MarshalAs(UnmanagedType.LPWStr)] string pszAppId, ListValue nListValue);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_RemoveAppIdFromList", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool RemoveAppIdFromList(List nList, [MarshalAs(UnmanagedType.LPWStr)] string pszAppId);
+
+ [DllImport("ttlib32.dll", EntryPoint = "TTLib_GetAppIdListValue", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ public static extern bool GetAppIdListValue(List nList, [MarshalAs(UnmanagedType.LPWStr)] string pszAppId, out ListValue pnListValue);
+ }
+}