diff --git a/Rectify11Installer/Core/TreeViewExtension.cs b/Rectify11Installer/Core/TreeViewExtension.cs index bafbdccd2..25c91ddae 100644 --- a/Rectify11Installer/Core/TreeViewExtension.cs +++ b/Rectify11Installer/Core/TreeViewExtension.cs @@ -6,11 +6,6 @@ namespace Rectify11Installer.Core { public static class TreeViewExtension { - public static List Descendants(this TreeView tree) - { - var nodes = tree.Nodes.Cast(); - return nodes.SelectMany(x => x.Descendants()).Concat(nodes).ToList(); - } public static List Descendants(this TreeNode node) { var nodes = node.Nodes.Cast().ToList(); diff --git a/Rectify11Installer/Rectify11Installer.csproj b/Rectify11Installer/Rectify11Installer.csproj index d61cce075..459f7f33d 100644 --- a/Rectify11Installer/Rectify11Installer.csproj +++ b/Rectify11Installer/Rectify11Installer.csproj @@ -1,6 +1,5 @@  - Debug @@ -101,9 +100,6 @@ - - ..\packages\KPreisser.UI.TaskDialog.1.0.0\lib\net472\TaskDialog.dll - @@ -239,13 +235,12 @@ - Component - + ResXFileCodeGenerator Designer @@ -316,7 +311,6 @@ Rectify11.zh-TW.Designer.cs - SettingsSingleFileGenerator Settings.Designer.cs @@ -383,13 +377,15 @@ + + + 1.0.0 + + + 2.2.0 + + - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - diff --git a/Rectify11Installer/Win32/DarkMode.cs b/Rectify11Installer/Win32/DarkMode.cs index 2814ca3f4..17736dab1 100644 --- a/Rectify11Installer/Win32/DarkMode.cs +++ b/Rectify11Installer/Win32/DarkMode.cs @@ -4,134 +4,134 @@ namespace Rectify11Installer.Win32 { - public class DarkMode - { - #region P/Invoke - [DllImport("uxtheme.dll", EntryPoint = "#135")] - internal static extern int SetPreferredAppMode(PreferredAppMode appMode); - [DllImport("uxtheme.dll", EntryPoint = "#135")] - internal static extern int AllowDarkModeForApp(bool allow); - [DllImport("uxtheme.dll", EntryPoint = "#133")] - internal static extern int AllowDarkModeForWindow(IntPtr handle, bool allow); - [DllImport("user32.dll")] - public static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WINDOWCOMPOSITIONATTRIBDATA data); - [DllImport("user32.dll", SetLastError = true)] - private static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData); - [DllImport("dwmapi.dll")] - internal static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMATTRIB dwAttribute, ref int pvAttribute, int cbAttribute); - #endregion - #region Flags - internal enum PreferredAppMode - { - Default, - AllowDark, - ForceDark, - ForceLight, - Max - } - public enum WINDOWCOMPOSITIONATTRIB - { - // ... - WCA_USEDARKMODECOLORS = 26, - // ... - }; - public enum DWMATTRIB - { - DWMWA_SYSTEMBACKDROP_TYPE = 38, - DWMWA_MICA_EFFECT = 1029 - } - [StructLayout(LayoutKind.Sequential)] - public struct WINDOWCOMPOSITIONATTRIBDATA - { - public WINDOWCOMPOSITIONATTRIB Attrib; - public IntPtr pvData; - public int cbData; - }; - #endregion - #region Public Methods - public static void RefreshTitleBarColor(IntPtr hWnd) - { - if (Environment.OSVersion.Version.Build < 18362) - { - SetProp(hWnd, "UseImmersiveDarkModeColors", new IntPtr(Theme.IsUsingDarkMode ? 1 : 0)); - } - else - { - var size = Marshal.SizeOf(Theme.IsUsingDarkMode); - var ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(Theme.IsUsingDarkMode, ptr, false); - var data = new WINDOWCOMPOSITIONATTRIBDATA - { - Attrib = WINDOWCOMPOSITIONATTRIB.WCA_USEDARKMODECOLORS, - pvData = ptr, - cbData = size - }; - SetWindowCompositionAttribute(hWnd, ref data); - } - } - public static void UpdateFrame(FrmWizard frm, bool yes) - { - var extend = Theme.IsUsingDarkMode; + public class DarkMode + { + #region P/Invoke + [DllImport("uxtheme.dll", EntryPoint = "#135")] + internal static extern int SetPreferredAppMode(PreferredAppMode appMode); + [DllImport("uxtheme.dll", EntryPoint = "#135")] + internal static extern int AllowDarkModeForApp(bool allow); + [DllImport("uxtheme.dll", EntryPoint = "#133")] + internal static extern int AllowDarkModeForWindow(IntPtr handle, bool allow); + [DllImport("user32.dll")] + public static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WINDOWCOMPOSITIONATTRIBDATA data); + [DllImport("user32.dll", SetLastError = true)] + private static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData); + [DllImport("dwmapi.dll")] + internal static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMATTRIB dwAttribute, ref int pvAttribute, int cbAttribute); + #endregion + #region Flags + internal enum PreferredAppMode + { + Default, + AllowDark, + ForceDark, + ForceLight, + Max + } + public enum WINDOWCOMPOSITIONATTRIB + { + // ... + WCA_USEDARKMODECOLORS = 26, + // ... + }; + public enum DWMATTRIB + { + DWMWA_SYSTEMBACKDROP_TYPE = 38, + DWMWA_MICA_EFFECT = 1029 + } + [StructLayout(LayoutKind.Sequential)] + public struct WINDOWCOMPOSITIONATTRIBDATA + { + public WINDOWCOMPOSITIONATTRIB Attrib; + public IntPtr pvData; + public int cbData; + }; + #endregion + #region Public Methods + public static void RefreshTitleBarColor(IntPtr hWnd) + { + if (Environment.OSVersion.Version.Build < 18362) + { + SetProp(hWnd, "UseImmersiveDarkModeColors", new IntPtr(Theme.IsUsingDarkMode ? 1 : 0)); + } + else + { + var size = Marshal.SizeOf(Theme.IsUsingDarkMode); + var ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(Theme.IsUsingDarkMode, ptr, false); + var data = new WINDOWCOMPOSITIONATTRIBDATA + { + Attrib = WINDOWCOMPOSITIONATTRIB.WCA_USEDARKMODECOLORS, + pvData = ptr, + cbData = size + }; + SetWindowCompositionAttribute(hWnd, ref data); + } + } + public static void UpdateFrame(FrmWizard frm, bool yes) + { + var extend = Theme.IsUsingDarkMode; - if (Environment.OSVersion.Version.Build >= 22523) - { - var micaValue = 0x02; - var tabbedvalue = 0x04; - if (extend) - { - DwmSetWindowAttribute(frm.Handle, DWMATTRIB.DWMWA_SYSTEMBACKDROP_TYPE, ref micaValue, Marshal.SizeOf(typeof(int))); - } - else - { - DwmSetWindowAttribute(frm.Handle, DWMATTRIB.DWMWA_SYSTEMBACKDROP_TYPE, ref tabbedvalue, Marshal.SizeOf(typeof(int))); - } - } + if (Environment.OSVersion.Version.Build >= 22523) + { + var micaValue = 0x02; + var tabbedvalue = 0x04; + if (extend) + { + DwmSetWindowAttribute(frm.Handle, DWMATTRIB.DWMWA_SYSTEMBACKDROP_TYPE, ref micaValue, Marshal.SizeOf(typeof(int))); + } + else + { + DwmSetWindowAttribute(frm.Handle, DWMATTRIB.DWMWA_SYSTEMBACKDROP_TYPE, ref tabbedvalue, Marshal.SizeOf(typeof(int))); + } + } - else - { - var trueValue = 0x01; - DwmSetWindowAttribute(frm.Handle, DWMATTRIB.DWMWA_MICA_EFFECT, ref trueValue, Marshal.SizeOf(typeof(int))); - } - var DarkMode = Theme.IsUsingDarkMode; - var m = new NativeMethods.MARGINS(); + else + { + var trueValue = 0x01; + DwmSetWindowAttribute(frm.Handle, DWMATTRIB.DWMWA_MICA_EFFECT, ref trueValue, Marshal.SizeOf(typeof(int))); + } + var DarkMode = Theme.IsUsingDarkMode; + var m = new NativeMethods.MARGINS(); - if (DarkMode) - { - m.cyTopHeight = frm.Height; - } - else - { - m.cyTopHeight = frm.tableLayoutPanel1.Height + 1; - m.cyBottomHeight = frm.tableLayoutPanel2.Height + 5; - } - if (yes) - { - if ((NativeMethods.GetUbr() != -1 - && NativeMethods.GetUbr() >= 51 - && Environment.OSVersion.Version.Build == 22000) - || Environment.OSVersion.Version.Build is > 22000 or < 21996) - { - NativeMethods.DwmExtendFrameIntoClientArea(frm.Handle, ref m); - } - } - else - { - NativeMethods.MARGINS mar = new() - { - cxLeftWidth = 0, - cxRightWidth = 0, - cyBottomHeight = 0, - cyTopHeight = 0 - }; - if ((NativeMethods.GetUbr() != -1 - && NativeMethods.GetUbr() >= 51 - && Environment.OSVersion.Version.Build == 22000) - || Environment.OSVersion.Version.Build is > 22000 or < 21996) - { - NativeMethods.DwmExtendFrameIntoClientArea(frm.Handle, ref mar); - } - } - } - #endregion - } + if (DarkMode) + { + m.cyTopHeight = frm.Height; + } + else + { + m.cyTopHeight = frm.tableLayoutPanel1.Height + 1; + m.cyBottomHeight = frm.tableLayoutPanel2.Height + 5; + } + if (yes) + { + if ((NativeMethods.GetUbr() != -1 + && NativeMethods.GetUbr() >= 51 + && Environment.OSVersion.Version.Build == 22000) + || Environment.OSVersion.Version.Build is > 22000 or < 21996) + { + NativeMethods.DwmExtendFrameIntoClientArea(frm.Handle, ref m); + } + } + else + { + NativeMethods.MARGINS mar = new() + { + cxLeftWidth = 0, + cxRightWidth = 0, + cyBottomHeight = 0, + cyTopHeight = 0 + }; + if ((NativeMethods.GetUbr() != -1 + && NativeMethods.GetUbr() >= 51 + && Environment.OSVersion.Version.Build == 22000) + || Environment.OSVersion.Version.Build is > 22000 or < 21996) + { + NativeMethods.DwmExtendFrameIntoClientArea(frm.Handle, ref mar); + } + } + } + #endregion + } } diff --git a/Rectify11Installer/Win32/NativeMethods.cs b/Rectify11Installer/Win32/NativeMethods.cs index 3bbe06a4f..2b90af259 100644 --- a/Rectify11Installer/Win32/NativeMethods.cs +++ b/Rectify11Installer/Win32/NativeMethods.cs @@ -7,58 +7,58 @@ namespace Rectify11Installer.Win32 { - public class NativeMethods - { - #region P/Invoke - [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool LookupPrivilegeValue(string? lpSystemName, string lpName, out LUID lpLuid); + public class NativeMethods + { + #region P/Invoke + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool LookupPrivilegeValue(string? lpSystemName, string lpName, out LUID lpLuid); - [DllImport("advapi32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, UInt32 Zero, IntPtr Null1, IntPtr Null2); + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, UInt32 Zero, IntPtr Null1, IntPtr Null2); - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool CloseHandle(IntPtr hObject); + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseHandle(IntPtr hObject); - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason); + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason); - [DllImport("advapi32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); - [DllImport("user32.dll")] - public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool revert); + [DllImport("user32.dll")] + public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool revert); - [DllImport("user32.dll")] - public static extern int EnableMenuItem(IntPtr hMenu, int IDEnableItem, int enable); + [DllImport("user32.dll")] + public static extern int EnableMenuItem(IntPtr hMenu, int IDEnableItem, int enable); - [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern IntPtr CreateCompatibleDC(IntPtr hDC); - [DllImport("gdi32.dll")] - internal static extern unsafe IntPtr CreateDIBSection(IntPtr hdc, BITMAPINFO pbmi, uint iUsage, out int* ppvBits, IntPtr hSection, uint dwOffset); + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr CreateCompatibleDC(IntPtr hDC); + [DllImport("gdi32.dll")] + internal static extern unsafe IntPtr CreateDIBSection(IntPtr hdc, BITMAPINFO pbmi, uint iUsage, out int* ppvBits, IntPtr hSection, uint dwOffset); - [DllImport("gdi32.dll", EntryPoint = "SelectObject")] - internal static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj); + [DllImport("gdi32.dll", EntryPoint = "SelectObject")] + internal static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj); - [DllImport("uxtheme.dll", CharSet = CharSet.Unicode)] - internal static extern int DrawThemeTextEx(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, string pszText, int iCharCount, uint flags, ref RECT rect, ref DTTOPTS poptions); + [DllImport("uxtheme.dll", CharSet = CharSet.Unicode)] + internal static extern int DrawThemeTextEx(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, string pszText, int iCharCount, uint flags, ref RECT rect, ref DTTOPTS poptions); - [DllImport("gdi32.dll")] - internal static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop); + [DllImport("gdi32.dll")] + internal static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop); - [DllImport("dwmapi.dll")] - public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); + [DllImport("dwmapi.dll")] + public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool IsWow64Process2( - IntPtr process, - out ushort processMachine, - out ushort nativeMachine - ); + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool IsWow64Process2( + IntPtr process, + out ushort processMachine, + out ushort nativeMachine + ); [return: MarshalAs(UnmanagedType.Bool)] [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); @@ -68,101 +68,101 @@ out ushort nativeMachine #endregion #region Flags public const int SC_CLOSE = 0xF060; - public const int MF_BYCOMMAND = 0; - public const int MF_ENABLED = 0; - public const int MF_GRAYED = 1; - public const int WP_CAPTION = 1; - public const int CS_ACTIVE = 1; - private const UInt32 TOKEN_QUERY = 0x0008; - private const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020; - private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002; - private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; - [StructLayout(LayoutKind.Sequential)] - public class BITMAPINFO - { - public int biSize; - public int biWidth; - public int biHeight; - public short biPlanes; - public short biBitCount; - public int biCompression; - public int biSizeImage; - public int biXPelsPerMeter; - public int biYPelsPerMeter; - public int biClrUsed; - public int biClrImportant; - public byte bmiColors_rgbBlue; - public byte bmiColors_rgbGreen; - public byte bmiColors_rgbRed; - public byte bmiColors_rgbReserved; - } - [StructLayout(LayoutKind.Sequential)] - public struct DTTOPTS - { - public int dwSize; - public int dwFlags; - public int crText; - public int crBorder; - public int crShadow; - public int iTextShadowType; - public int ptShadowOffsetX; - public int ptShadowOffsetY; - public int iBorderSize; - public int iFontPropId; - public int iColorPropId; - public int iStateId; - public bool fApplyOverlay; - public int iGlowSize; - public IntPtr pfnDrawTextCallback; - public IntPtr lParam; - } - [StructLayout(LayoutKind.Sequential)] - public struct MARGINS - { - public int cxLeftWidth; // width of left border that retains its size - public int cxRightWidth; // width of right border that retains its size - public int cyTopHeight; // height of top border that retains its size - public int cyBottomHeight; // height of bottom border that retains its size - }; - [Flags] - private enum ExitWindows : uint - { - LogOff = 0x00, - ShutDown = 0x01, - Reboot = 0x02, - PowerOff = 0x08, - RestartApps = 0x40, - Force = 0x04, - ForceIfHung = 0x10, - } + public const int MF_BYCOMMAND = 0; + public const int MF_ENABLED = 0; + public const int MF_GRAYED = 1; + public const int WP_CAPTION = 1; + public const int CS_ACTIVE = 1; + private const UInt32 TOKEN_QUERY = 0x0008; + private const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020; + private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002; + private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; + [StructLayout(LayoutKind.Sequential)] + public class BITMAPINFO + { + public int biSize; + public int biWidth; + public int biHeight; + public short biPlanes; + public short biBitCount; + public int biCompression; + public int biSizeImage; + public int biXPelsPerMeter; + public int biYPelsPerMeter; + public int biClrUsed; + public int biClrImportant; + public byte bmiColors_rgbBlue; + public byte bmiColors_rgbGreen; + public byte bmiColors_rgbRed; + public byte bmiColors_rgbReserved; + } + [StructLayout(LayoutKind.Sequential)] + public struct DTTOPTS + { + public int dwSize; + public int dwFlags; + public int crText; + public int crBorder; + public int crShadow; + public int iTextShadowType; + public int ptShadowOffsetX; + public int ptShadowOffsetY; + public int iBorderSize; + public int iFontPropId; + public int iColorPropId; + public int iStateId; + public bool fApplyOverlay; + public int iGlowSize; + public IntPtr pfnDrawTextCallback; + public IntPtr lParam; + } + [StructLayout(LayoutKind.Sequential)] + public struct MARGINS + { + public int cxLeftWidth; // width of left border that retains its size + public int cxRightWidth; // width of right border that retains its size + public int cyTopHeight; // height of top border that retains its size + public int cyBottomHeight; // height of bottom border that retains its size + }; + [Flags] + private enum ExitWindows : uint + { + LogOff = 0x00, + ShutDown = 0x01, + Reboot = 0x02, + PowerOff = 0x08, + RestartApps = 0x40, + Force = 0x04, + ForceIfHung = 0x10, + } - [Flags] - private enum ShutdownReason : uint - { - MajorOther = 0x00000000, - MinorOther = 0x00000000, - FlagPlanned = 0x80000000 - } + [Flags] + private enum ShutdownReason : uint + { + MajorOther = 0x00000000, + MinorOther = 0x00000000, + FlagPlanned = 0x80000000 + } - [StructLayout(LayoutKind.Sequential)] - private struct LUID - { - public uint LowPart; - public int HighPart; - } + [StructLayout(LayoutKind.Sequential)] + private struct LUID + { + public uint LowPart; + public int HighPart; + } - [StructLayout(LayoutKind.Sequential)] - private struct LUID_AND_ATTRIBUTES - { - public LUID Luid; - public UInt32 Attributes; - } - private struct TOKEN_PRIVILEGES - { - public UInt32 PrivilegeCount; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public LUID_AND_ATTRIBUTES[] Privileges; - } + [StructLayout(LayoutKind.Sequential)] + private struct LUID_AND_ATTRIBUTES + { + public LUID Luid; + public UInt32 Attributes; + } + private struct TOKEN_PRIVILEGES + { + public UInt32 PrivilegeCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public LUID_AND_ATTRIBUTES[] Privileges; + } [Flags] public enum MoveFileFlags @@ -194,119 +194,104 @@ public struct STATEMGRSTATUS #endregion #region Public Methods public static bool SetCloseButton(FrmWizard frm, bool enable) - { - var hMenu = NativeMethods.GetSystemMenu(frm.Handle, false); - if (hMenu != IntPtr.Zero) - { - NativeMethods.EnableMenuItem(hMenu, - NativeMethods.SC_CLOSE, - NativeMethods.MF_BYCOMMAND | (enable ? NativeMethods.MF_ENABLED : NativeMethods.MF_GRAYED)); - return true; - } - return false; - } - public static void Reboot() - { - var tokenHandle = IntPtr.Zero; - try - { - // get process token - if (!OpenProcessToken(Process.GetCurrentProcess().Handle, - TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, - out tokenHandle)) - { - throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token handle"); - } - - // lookup the shutdown privilege - TOKEN_PRIVILEGES tokenPrivs = new(); - tokenPrivs.PrivilegeCount = 1; - tokenPrivs.Privileges = new LUID_AND_ATTRIBUTES[1]; - tokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + { + var hMenu = GetSystemMenu(frm.Handle, false); + if (hMenu != IntPtr.Zero) + { + EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED)); + return true; + } + return false; + } + public static void Reboot() + { + var tokenHandle = IntPtr.Zero; + try + { + // get process token + if (!OpenProcessToken(Process.GetCurrentProcess().Handle, + TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, + out tokenHandle)) + { + throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token handle"); + } - if (!LookupPrivilegeValue(null, - SE_SHUTDOWN_NAME, - out tokenPrivs.Privileges[0].Luid)) - { - throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open lookup shutdown privilege"); - } + // lookup the shutdown privilege + TOKEN_PRIVILEGES tokenPrivs = new() + { + PrivilegeCount = 1, + Privileges = new LUID_AND_ATTRIBUTES[1] + }; + tokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - // add the shutdown privilege to the process token - if (!AdjustTokenPrivileges(tokenHandle, - false, - ref tokenPrivs, - 0, - IntPtr.Zero, - IntPtr.Zero)) - { - throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to adjust process token privileges"); - } + if (!LookupPrivilegeValue(null, + SE_SHUTDOWN_NAME, + out tokenPrivs.Privileges[0].Luid)) + { + throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open lookup shutdown privilege"); + } - // reboot - if (!ExitWindowsEx(ExitWindows.Reboot, - ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned)) - { - throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to reboot system"); - } - } - finally - { - // close the process token - if (tokenHandle != IntPtr.Zero) - { - CloseHandle(tokenHandle); - } - } - } - public static bool IsArm64() - { - var handle = Process.GetCurrentProcess().Handle; - try - { - IsWow64Process2(handle, out var processMachine, out var nativeMachine); - if (nativeMachine == 0xaa64) - { - return true; - } - else - { - return false; - } - } - catch - { + // add the shutdown privilege to the process token + if (!AdjustTokenPrivileges(tokenHandle, + false, + ref tokenPrivs, + 0, + IntPtr.Zero, + IntPtr.Zero)) + { + throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to adjust process token privileges"); + } - return false; - } - } - public static int GetUbr() - { - using var key = Registry.LocalMachine.OpenSubKey(@"software\microsoft\Windows NT\CurrentVersion"); - if (key != null) - { - return Convert.ToInt32(key.GetValue("UBR")); - } - return -1; - } - public static bool CreateSystemRestorePoint(bool finish) - { + // reboot + if (!ExitWindowsEx(ExitWindows.Reboot, + ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned)) + { + throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to reboot system"); + } + } + finally + { + // close the process token + if (tokenHandle != IntPtr.Zero) + { + CloseHandle(tokenHandle); + } + } + } + public static bool IsArm64() + { + var handle = Process.GetCurrentProcess().Handle; + try + { + IsWow64Process2(handle, out var processMachine, out var nativeMachine); + if (nativeMachine == 0xaa64) return true; + else return false; + } + catch { return false; } + } + public static int GetUbr() + { + using var key = Registry.LocalMachine.OpenSubKey(@"software\microsoft\Windows NT\CurrentVersion"); + return Convert.ToInt32(key?.GetValue("UBR")); + } + public static bool CreateSystemRestorePoint(bool finish) + { RegistryKey SystemRestoreKey = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\SystemRestore", true); SystemRestoreKey.SetValue("SystemRestorePointCreationFrequency", 0, RegistryValueKind.DWord); RESTOREPOINTINFO RPInfo = new(); STATEMGRSTATUS RPStatus = new(); RPInfo.dwEventType = 100; - if (finish) RPInfo.dwEventType = 101; + if (finish) RPInfo.dwEventType = 101; RPInfo.dwRestorePtType = 0; RPInfo.llSequenceNumber = 0; RPInfo.szDescription = "Rectify11"; - - bool result = SRSetRestorePoint(ref RPInfo, ref RPStatus); + _ = SRSetRestorePoint(ref RPInfo, ref RPStatus); SystemRestoreKey.DeleteValue("SystemRestorePointCreationFrequency"); SystemRestoreKey.Dispose(); - return true; + return true; } - #endregion - } + #endregion + } } diff --git a/Rectify11Installer/Win32/RECT.cs b/Rectify11Installer/Win32/RECT.cs index 440fae16a..1ebbc0589 100644 --- a/Rectify11Installer/Win32/RECT.cs +++ b/Rectify11Installer/Win32/RECT.cs @@ -2,105 +2,41 @@ namespace Rectify11Installer.Win32 { - [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); - } - } - + [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 Height + { + get { return Bottom - Top; } + set { Bottom = value + Top; } + } + + public int Width + { + get { return Right - Left; } + set { Right = value + Left; } + } + + 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); + } + } } \ No newline at end of file diff --git a/Rectify11Installer/Win32/SafeHGlobalHandle.cs b/Rectify11Installer/Win32/SafeHGlobalHandle.cs deleted file mode 100644 index 1a863a8da..000000000 --- a/Rectify11Installer/Win32/SafeHGlobalHandle.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics; - -namespace System.Runtime.InteropServices -{ - internal class SafeHGlobalHandle : SafeHandle - { - /// - /// Maintains reference to other SafeHGlobalHandle objects, the pointer to which are referred to by this object. This is to ensure - /// that such objects being referred to wouldn't be unreferenced until this object is active. - /// - private List references; - - public SafeHGlobalHandle() : this(IntPtr.Zero, 0, false) - { - } - - public SafeHGlobalHandle(IntPtr handle, int size, bool ownsHandle = true) : - base(IntPtr.Zero, ownsHandle) - { - if (handle != IntPtr.Zero) - SetHandle(handle); - Size = size; - } - - public SafeHGlobalHandle(int size) : this() - { - if (size < 0) - throw new ArgumentOutOfRangeException(nameof(size), "The value of this argument must be non-negative"); - SetHandle(Marshal.AllocHGlobal(size)); - Size = size; - } - - public SafeHGlobalHandle(object value) : this(Marshal.SizeOf(value)) => Marshal.StructureToPtr(value, handle, false); - - /// - /// Allocates from unmanaged memory to represent an array of pointers and marshals the unmanaged pointers (IntPtr) to the native - /// array equivalent. - /// - /// Array of unmanaged pointers - /// SafeHGlobalHandle object to an native (unmanaged) array of pointers - public SafeHGlobalHandle(IntPtr[] values) : this(IntPtr.Size * values.Length) => Marshal.Copy(values, 0, handle, values.Length); - - /// Allocates from unmanaged memory to represent a Unicode string (WSTR) and marshal this to a native PWSTR. - /// String - /// SafeHGlobalHandle object to an native (unmanaged) Unicode string - public SafeHGlobalHandle(string s) : this(s == null ? IntPtr.Zero : Marshal.StringToHGlobalUni(s), (s?.Length + 1) * 2 ?? 0) - { - } - - /* - /// Initializes a new instance of the class. - /// The secure string. - public SafeHGlobalHandle(Security.SecureString s) : - base(IntPtr.Zero, p => { Marshal.ZeroFreeGlobalAllocUnicode(p); return true; }, true) - { - if (s != null) - { - s.MakeReadOnly(); - SetHandle(Marshal.SecureStringToGlobalAllocUnicode(s)); - Size = s.Length; - } - } - */ - - public override bool IsInvalid => handle == IntPtr.Zero; - - /// Gets the size of the allocated memory block. - /// The sizeof the allocated memory block. - public int Size { get; } - - /// Allocates from unmanaged memory sufficient memory to hold an object of type T. - /// Native type - /// SafeHGlobalHandle object to an native (unmanaged) memory block the size of T. - public static SafeHGlobalHandle AllocHGlobal() => new(Marshal.SizeOf(typeof(T))); - - /// - /// Allocates from unmanaged memory to represent an array of structures and marshals the structure elements to the native array of - /// structures. ONLY structures with attribute StructLayout of LayoutKind.Sequential are supported. - /// - /// Native structure type - /// Collection of structure objects - /// SafeHGlobalHandle object to an native (unmanaged) array of structures - public static SafeHGlobalHandle AllocHGlobal(ICollection values) where T : struct - { - Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential); - - return AllocHGlobal(0, values, values.Count); - } - - /// - /// Allocates from unmanaged memory to represent a structure with a variable length array at the end and marshal these structure - /// elements. It is the callers responsibility to marshal what precedes the trailing array into the unmanaged memory. ONLY structures - /// with attribute StructLayout of LayoutKind.Sequential are supported. - /// - /// Type of the trailing array of structures - /// Number of bytes preceding the trailing array of structures - /// Collection of structure objects - /// Number of items in . - /// SafeHGlobalHandle object to an native (unmanaged) structure with a trail array of structures - public static SafeHGlobalHandle AllocHGlobal(int prefixBytes, IEnumerable values, int count) where T : struct - { - Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential); - - var result = new SafeHGlobalHandle(prefixBytes + Marshal.SizeOf(typeof(T)) * count); - var ptr = new IntPtr(result.handle.ToInt32() + prefixBytes); - foreach (var value in values) - { - Marshal.StructureToPtr(value, ptr, false); - ptr = new IntPtr(ptr.ToInt32() + Marshal.SizeOf(typeof(T))); - } - return result; - } - - /// Allocates from unmanaged memory to hold a copy of a structure. - /// Type of the structure. - /// The object. - /// SafeHGlobalHandle object to an native (unmanaged) structure - public static SafeHGlobalHandle AllocHGlobalStruct(T obj) where T : struct - { - Debug.Assert(typeof(T).StructLayoutAttribute?.Value == LayoutKind.Sequential); - - var result = new SafeHGlobalHandle(Marshal.SizeOf(typeof(T))); - Marshal.StructureToPtr(obj, result.handle, false); - return result; - } - - /// Allows to use SafeHGlobalHandle as IntPtr - public static implicit operator IntPtr(SafeHGlobalHandle h) => h.DangerousGetHandle(); - - /// Allows to assign IntPtr to SafeHGlobalHandle - public static implicit operator SafeHGlobalHandle(IntPtr ptr) => new(ptr, 0, true); - - /// - /// Adds reference to other SafeHGlobalHandle objects, the pointer to which are referred to by this object. This is to ensure that - /// such objects being referred to wouldn't be unreferenced until this object is active. - /// - /// For e.g. when this object is an array of pointers to other objects - /// - /// Collection of SafeHGlobalHandle objects referred to by this object. - public void AddSubReference(IEnumerable children) - { - if (references == null) - references = new List(); - references.AddRange(children); - } - - public T ToStructure() where T : struct - { - if (IsInvalid) - return default(T); - if (Size < Marshal.SizeOf(typeof(T))) - throw new InsufficientMemoryException("Requested structure is larger than the memory allocated."); - return (T)Marshal.PtrToStructure(handle, typeof(T)); - } - - protected override bool ReleaseHandle() - { - if (!IsInvalid) - Marshal.FreeHGlobal(handle); - return true; - } - } -} \ No newline at end of file diff --git a/Rectify11Installer/Win32/ShellLink.cs b/Rectify11Installer/Win32/ShellLink.cs index 2b3eb5aff..38c98442c 100644 --- a/Rectify11Installer/Win32/ShellLink.cs +++ b/Rectify11Installer/Win32/ShellLink.cs @@ -6,1108 +6,1103 @@ namespace Rectify11Installer.Core { - #region File icon - /// - /// Enables extraction of icons for any file type from - /// the Shell. - /// - public class FileIcon - { - #region UnmanagedCode - private const int MAX_PATH = 260; - - [StructLayout(LayoutKind.Sequential)] - private struct SHFILEINFO - { - public readonly IntPtr hIcon; - private readonly int iIcon; - private readonly int dwAttributes; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] - public readonly string szDisplayName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] - public readonly string szTypeName; - } - - [DllImport("shell32")] - private static extern int SHGetFileInfo( - string pszPath, - int dwFileAttributes, - ref SHFILEINFO psfi, - uint cbFileInfo, - uint uFlags); - - private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000; - private const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x200; - [DllImport("kernel32")] - private static extern int FormatMessage( - int dwFlags, - IntPtr lpSource, - int dwMessageId, - int dwLanguageId, - string lpBuffer, - uint nSize, - int argumentsLong); - - [DllImport("kernel32")] - private static extern int GetLastError(); - #endregion - - #region Member Variables - private string fileName; - private string displayName; - private string typeName; - private SHGetFileInfoConstants flags; - - #endregion - - #region Enumerations - [Flags] - public enum SHGetFileInfoConstants - { - SHGFI_ICON = 0x100, // get icon - SHGFI_DISPLAYNAME = 0x200, // get display name - SHGFI_TYPENAME = 0x400, // get type name - SHGFI_ATTRIBUTES = 0x800, // get attributes - SHGFI_ICONLOCATION = 0x1000, // get icon location - SHGFI_EXETYPE = 0x2000, // return exe type - SHGFI_SYSICONINDEX = 0x4000, // get system icon index - SHGFI_LINKOVERLAY = 0x8000, // put a link overlay on icon - SHGFI_SELECTED = 0x10000, // show icon in selected state - SHGFI_ATTR_SPECIFIED = 0x20000, // get only specified attributes - SHGFI_LARGEICON = 0x0, // get large icon - SHGFI_SMALLICON = 0x1, // get small icon - SHGFI_OPENICON = 0x2, // get open icon - SHGFI_SHELLICONSIZE = 0x4, // get shell size icon - //SHGFI_PIDL = 0x8, // pszPath is a pidl - SHGFI_USEFILEATTRIBUTES = 0x10, // use passed dwFileAttribute - SHGFI_ADDOVERLAYS = 0x000000020, // apply the appropriate overlays - SHGFI_OVERLAYINDEX = 0x000000040 // Get the index of the overlay - } - #endregion - - #region Implementation - - /// - /// Gets the icon for the chosen file - /// - public Icon ShellIcon { get; private set; } - - /// - /// Gets the display name for the selected file - /// if the SHGFI_DISPLAYNAME flag was set. - /// - public string DisplayName - { - get - { - return displayName; - } - } - - /// - /// Gets the type name for the selected file - /// if the SHGFI_TYPENAME flag was set. - /// - public string TypeName - { - get - { - return typeName; - } - } - - /// - /// Gets the information for the specified - /// file name and flags. - /// - public void GetInfo() - { - ShellIcon = null; - typeName = ""; - displayName = ""; - - var shfi = new SHFILEINFO(); - var shfiSize = (uint)Marshal.SizeOf(shfi.GetType()); - - var ret = SHGetFileInfo( - fileName, 0, ref shfi, shfiSize, (uint)(flags)); - if (ret != 0) - { - if (shfi.hIcon != IntPtr.Zero) - { - ShellIcon = Icon.FromHandle(shfi.hIcon); - // Now owned by the GDI+ object - //DestroyIcon(shfi.hIcon); - } - typeName = shfi.szTypeName; - displayName = shfi.szDisplayName; - } - else - { - - var err = GetLastError(); - Console.WriteLine("Error {0}", err); - var txtS = new string('\0', 256); - var len = FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - IntPtr.Zero, err, 0, txtS, 256, 0); - Console.WriteLine("Len {0} text {1}", len, txtS); - - // throw exception - - } - } - - /// - /// Constructs a new, default instance of the FileIcon - /// class. Specify the filename and call GetInfo() - /// to retrieve an icon. - /// - public FileIcon() - { - flags = SHGetFileInfoConstants.SHGFI_ICON | - SHGetFileInfoConstants.SHGFI_DISPLAYNAME | - SHGetFileInfoConstants.SHGFI_TYPENAME | - SHGetFileInfoConstants.SHGFI_ATTRIBUTES | - SHGetFileInfoConstants.SHGFI_EXETYPE; - } - /// - /// Constructs a new instance of the FileIcon class - /// and retrieves the icon, display name and type name - /// for the specified file. - /// - /// The filename to get the icon, - /// display name and type name for - public FileIcon(string fileName) : this() - { - this.fileName = fileName; - GetInfo(); - } - /// - /// Constructs a new instance of the FileIcon class - /// and retrieves the information specified in the - /// flags. - /// - /// The filename to get information - /// for - /// The flags to use when extracting the - /// icon and other shell information. - public FileIcon(string fileName, SHGetFileInfoConstants flags) - { - this.fileName = fileName; - this.flags = flags; - GetInfo(); - } - - #endregion - } - #endregion - #region ShellLink Object - /// - /// Summary description for ShellLink. - /// - public class ShellLink : IDisposable - { - #region ComInterop for IShellLink - - #region IPersist Interface - [ComImport()] - [Guid("0000010C-0000-0000-C000-000000000046")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IPersist - { - [PreserveSig] - //[helpstring("Returns the class identifier for the component object")] - void GetClassID(out Guid pClassID); - } - #endregion - - #region IPersistFile Interface - [ComImport()] - [Guid("0000010B-0000-0000-C000-000000000046")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IPersistFile - { - // can't get this to go if I extend IPersist, so put it here: - [PreserveSig] - void GetClassID(out Guid pClassID); - - //[helpstring("Checks for changes since last file write")] - void IsDirty(); - - //[helpstring("Opens the specified file and initializes the object from its contents")] - void Load( - [MarshalAs(UnmanagedType.LPWStr)] string pszFileName, - uint dwMode); - - //[helpstring("Saves the object into the specified file")] - void Save( - [MarshalAs(UnmanagedType.LPWStr)] string pszFileName, - [MarshalAs(UnmanagedType.Bool)] bool fRemember); - - //[helpstring("Notifies the object that save is completed")] - void SaveCompleted( - [MarshalAs(UnmanagedType.LPWStr)] string pszFileName); - - //[helpstring("Gets the current name of the file associated with the object")] - void GetCurFile( - [MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName); - } - #endregion - - #region IShellLink Interface - [ComImport()] - [Guid("000214EE-0000-0000-C000-000000000046")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IShellLinkA - { - //[helpstring("Retrieves the path and filename of a shell link object")] - void GetPath( - [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, - int cchMaxPath, - ref _WIN32_FIND_DATAA pfd, - uint fFlags); - - //[helpstring("Retrieves the list of shell link item identifiers")] - void GetIDList(out IntPtr ppidl); - - //[helpstring("Sets the list of shell link item identifiers")] - void SetIDList(IntPtr pidl); - - //[helpstring("Retrieves the shell link description string")] - void GetDescription( - [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, - int cchMaxName); - - //[helpstring("Sets the shell link description string")] - void SetDescription( - [MarshalAs(UnmanagedType.LPStr)] string pszName); - - //[helpstring("Retrieves the name of the shell link working directory")] - void GetWorkingDirectory( - [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszDir, - int cchMaxPath); - - //[helpstring("Sets the name of the shell link working directory")] - void SetWorkingDirectory( - [MarshalAs(UnmanagedType.LPStr)] string pszDir); - - //[helpstring("Retrieves the shell link command-line arguments")] - void GetArguments( - [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszArgs, - int cchMaxPath); - - //[helpstring("Sets the shell link command-line arguments")] - void SetArguments( - [MarshalAs(UnmanagedType.LPStr)] string pszArgs); - - //[propget, helpstring("Retrieves or sets the shell link hot key")] - void GetHotkey(out short pwHotkey); - //[propput, helpstring("Retrieves or sets the shell link hot key")] - void SetHotkey(short pwHotkey); - - //[propget, helpstring("Retrieves or sets the shell link show command")] - void GetShowCmd(out uint piShowCmd); - //[propput, helpstring("Retrieves or sets the shell link show command")] - void SetShowCmd(uint piShowCmd); - - //[helpstring("Retrieves the location (path and index) of the shell link icon")] - void GetIconLocation( - [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszIconPath, - int cchIconPath, - out int piIcon); - - //[helpstring("Sets the location (path and index) of the shell link icon")] - void SetIconLocation( - [MarshalAs(UnmanagedType.LPStr)] string pszIconPath, - int iIcon); - - //[helpstring("Sets the shell link relative path")] - void SetRelativePath( - [MarshalAs(UnmanagedType.LPStr)] string pszPathRel, - uint dwReserved); - - //[helpstring("Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary)")] - void Resolve( - IntPtr hWnd, - uint fFlags); - - //[helpstring("Sets the shell link path and filename")] - void SetPath( - [MarshalAs(UnmanagedType.LPStr)] string pszFile); - } - - - [ComImport()] - [Guid("000214F9-0000-0000-C000-000000000046")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - private interface IShellLinkW - { - //[helpstring("Retrieves the path and filename of a shell link object")] - void GetPath( - [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, - int cchMaxPath, - ref _WIN32_FIND_DATAW pfd, - uint fFlags); - - //[helpstring("Retrieves the list of shell link item identifiers")] - void GetIDList(out IntPtr ppidl); - - //[helpstring("Sets the list of shell link item identifiers")] - void SetIDList(IntPtr pidl); - - //[helpstring("Retrieves the shell link description string")] - void GetDescription( - [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, - int cchMaxName); - - //[helpstring("Sets the shell link description string")] - void SetDescription( - [MarshalAs(UnmanagedType.LPWStr)] string pszName); - - //[helpstring("Retrieves the name of the shell link working directory")] - void GetWorkingDirectory( - [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, - int cchMaxPath); - - //[helpstring("Sets the name of the shell link working directory")] - void SetWorkingDirectory( - [MarshalAs(UnmanagedType.LPWStr)] string pszDir); - - //[helpstring("Retrieves the shell link command-line arguments")] - void GetArguments( - [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, - int cchMaxPath); - - //[helpstring("Sets the shell link command-line arguments")] - void SetArguments( - [MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - - //[propget, helpstring("Retrieves or sets the shell link hot key")] - void GetHotkey(out short pwHotkey); - //[propput, helpstring("Retrieves or sets the shell link hot key")] - void SetHotkey(short pwHotkey); - - //[propget, helpstring("Retrieves or sets the shell link show command")] - void GetShowCmd(out uint piShowCmd); - //[propput, helpstring("Retrieves or sets the shell link show command")] - void SetShowCmd(uint piShowCmd); - - //[helpstring("Retrieves the location (path and index) of the shell link icon")] - void GetIconLocation( - [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, - int cchIconPath, - out int piIcon); - - //[helpstring("Sets the location (path and index) of the shell link icon")] - void SetIconLocation( - [MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, - int iIcon); - - //[helpstring("Sets the shell link relative path")] - void SetRelativePath( - [MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, - uint dwReserved); - - //[helpstring("Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary)")] - void Resolve( - IntPtr hWnd, - uint fFlags); - - //[helpstring("Sets the shell link path and filename")] - void SetPath( - [MarshalAs(UnmanagedType.LPWStr)] string pszFile); - } - #endregion - - #region ShellLinkCoClass - [Guid("00021401-0000-0000-C000-000000000046")] - [ClassInterface(ClassInterfaceType.None)] - [ComImport()] - private class CShellLink { } - - #endregion - - #region Private IShellLink enumerations - private enum EShellLinkGP : uint - { - SLGP_UNCPRIORITY = 2 - } - - [Flags] - private enum EShowWindowFlags : uint - { - SW_NORMAL = 1, - SW_MAXIMIZE = 3, - SW_SHOWMINNOACTIVE = 7, - } - #endregion - - #region IShellLink Private structs - - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0, CharSet = CharSet.Unicode)] - private struct _WIN32_FIND_DATAW - { - public readonly uint dwFileAttributes; - public readonly _FILETIME ftCreationTime; - public readonly _FILETIME ftLastAccessTime; - public readonly _FILETIME ftLastWriteTime; - public readonly uint nFileSizeHigh; - public readonly uint nFileSizeLow; - public readonly uint dwReserved0; - public readonly uint dwReserved1; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] // MAX_PATH - public readonly string cFileName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public readonly string cAlternateFileName; - } - - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0, CharSet = CharSet.Ansi)] - private struct _WIN32_FIND_DATAA - { - public readonly uint dwFileAttributes; - public readonly _FILETIME ftCreationTime; - public readonly _FILETIME ftLastAccessTime; - public readonly _FILETIME ftLastWriteTime; - public readonly uint nFileSizeHigh; - public readonly uint nFileSizeLow; - public readonly uint dwReserved0; - public readonly uint dwReserved1; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] // MAX_PATH - public readonly string cFileName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public readonly string cAlternateFileName; - } - - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0)] - private struct _FILETIME - { - public readonly uint dwLowDateTime; - public readonly uint dwHighDateTime; - } - #endregion - - #region UnManaged Methods - private class UnManagedMethods - { - [DllImport("Shell32", CharSet = CharSet.Auto)] - internal static extern int ExtractIconEx( - [MarshalAs(UnmanagedType.LPTStr)] - string lpszFile, - int nIconIndex, - IntPtr[] phIconLarge, - IntPtr[] phIconSmall, - int nIcons); - } - #endregion - - #endregion - - #region Enumerations - /// - /// Flags determining how the links with missing - /// targets are resolved. - /// - [Flags] - public enum EShellLinkResolveFlags : uint - { - /// - /// Allow any match during resolution. Has no effect - /// on ME/2000 or above, use the other flags instead. - /// - SLR_ANY_MATCH = 0x2, - /// - /// Call the Microsoft Windows Installer. - /// - SLR_INVOKE_MSI = 0x80, - /// - /// Disable distributed link tracking. By default, - /// distributed link tracking tracks removable media - /// across multiple devices based on the volume name. - /// It also uses the UNC path to track remote file - /// systems whose drive letter has changed. Setting - /// SLR_NOLINKINFO disables both types of tracking. - /// - SLR_NOLINKINFO = 0x40, - /// - /// Do not display a dialog box if the link cannot be resolved. - /// When SLR_NO_UI is set, a time-out value that specifies the - /// maximum amount of time to be spent resolving the link can - /// be specified in milliseconds. The function returns if the - /// link cannot be resolved within the time-out duration. - /// If the timeout is not set, the time-out duration will be - /// set to the default value of 3,000 milliseconds (3 seconds). - /// - SLR_NO_UI = 0x1, - /// - /// Not documented in SDK. Assume same as SLR_NO_UI but - /// intended for applications without a hWnd. - /// - SLR_NO_UI_WITH_MSG_PUMP = 0x101, - /// - /// Do not update the link information. - /// - SLR_NOUPDATE = 0x8, - /// - /// Do not execute the search heuristics. - /// - SLR_NOSEARCH = 0x10, - /// - /// Do not use distributed link tracking. - /// - SLR_NOTRACK = 0x20, - /// - /// If the link object has changed, update its path and list - /// of identifiers. If SLR_UPDATE is set, you do not need to - /// call IPersistFile::IsDirty to determine whether or not - /// the link object has changed. - /// - SLR_UPDATE = 0x4 - } - - public enum LinkDisplayMode : uint - { - edmNormal = EShowWindowFlags.SW_NORMAL, - edmMinimized = EShowWindowFlags.SW_SHOWMINNOACTIVE, - edmMaximized = EShowWindowFlags.SW_MAXIMIZE - } - #endregion - - #region Member Variables - // Use Unicode (W) under NT, otherwise use ANSI - private IShellLinkW linkW; - private IShellLinkA linkA; - private string shortcutFile = ""; - #endregion - - #region Constructor - /// - /// Creates an instance of the Shell Link object. - /// - public ShellLink() - { - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - linkW = (IShellLinkW)new CShellLink(); - } - else - { - linkA = (IShellLinkA)new CShellLink(); - } - } - - /// - /// Creates an instance of a Shell Link object - /// from the specified link file - /// - /// The Shortcut file to open - public ShellLink(string linkFile) : this() - { - Open(linkFile); - } - #endregion - - #region Destructor and Dispose - /// - /// Call dispose just in case it hasn't happened yet - /// - ~ShellLink() - { - Dispose(); - } - - /// - /// Dispose the object, releasing the COM ShellLink object - /// - public void Dispose() - { - if (linkW != null) - { - Marshal.ReleaseComObject(linkW); - linkW = null; - } - if (linkA != null) - { - Marshal.ReleaseComObject(linkA); - linkA = null; - } - } - #endregion - - #region Implementation - public string ShortCutFile - { - get - { - return this.shortcutFile; - } - set - { - this.shortcutFile = value; - } - } - - /// - /// Gets a System.Drawing.Icon containing the icon for this - /// ShellLink object. - /// - public Icon LargeIcon - { - get - { - return getIcon(true); - } - } - - public Icon SmallIcon - { - get - { - return getIcon(false); - } - } - - private Icon getIcon(bool large) - { - // Get icon index and path: - int iconIndex; - var iconPath = new StringBuilder(260, 260); - if (linkA == null) - { - linkW.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); - } - else - { - linkA.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); - } - var iconFile = iconPath.ToString(); - - // If there are no details set for the icon, then we must use - // the shell to get the icon for the target: - if (iconFile.Length == 0) - { - // Use the FileIcon object to get the icon: - var flags = FileIcon.SHGetFileInfoConstants.SHGFI_ICON | - FileIcon.SHGetFileInfoConstants.SHGFI_ATTRIBUTES; - if (large) - { - flags = flags | FileIcon.SHGetFileInfoConstants.SHGFI_LARGEICON; - } - else - { - flags = flags | FileIcon.SHGetFileInfoConstants.SHGFI_SMALLICON; - } - var fileIcon = new FileIcon(Target, flags); - return fileIcon.ShellIcon; - } - else - { - // Use ExtractIconEx to get the icon: - var hIconEx = new[] { IntPtr.Zero }; - if (large) - { - UnManagedMethods.ExtractIconEx( - iconFile, - iconIndex, - hIconEx, - null, - 1); - } - else - { - UnManagedMethods.ExtractIconEx( - iconFile, - iconIndex, - null, - hIconEx, - 1); - } - // If success then return as a GDI+ object - Icon icon = null; - if (hIconEx[0] != IntPtr.Zero) - { - icon = Icon.FromHandle(hIconEx[0]); - //UnManagedMethods.DestroyIcon(hIconEx[0]); - } - return icon; - } - } - - /// - /// Gets the path to the file containing the icon for this shortcut. - /// - public string IconPath - { - get - { - var iconPath = new StringBuilder(260, 260); - if (linkA == null) - { - linkW.GetIconLocation(iconPath, iconPath.Capacity, out _); - } - else - { - linkA.GetIconLocation(iconPath, iconPath.Capacity, out _); - } - return iconPath.ToString(); - } - set - { - var iconPath = new StringBuilder(260, 260); - int iconIndex; - if (linkA == null) - { - linkW.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); - } - else - { - linkA.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); - } - if (linkA == null) - { - linkW.SetIconLocation(value, iconIndex); - } - else - { - linkA.SetIconLocation(value, iconIndex); - } - } - } - - /// - /// Gets the index of this icon within the icon path's resources - /// - public int IconIndex - { - get - { - var iconPath = new StringBuilder(260, 260); - int iconIndex; - if (linkA == null) - { - linkW.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); - } - else - { - linkA.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); - } - return iconIndex; - } - set - { - var iconPath = new StringBuilder(260, 260); - if (linkA == null) - { - linkW.GetIconLocation(iconPath, iconPath.Capacity, out _); - } - else - { - linkA.GetIconLocation(iconPath, iconPath.Capacity, out _); - } - if (linkA == null) - { - linkW.SetIconLocation(iconPath.ToString(), value); - } - else - { - linkA.SetIconLocation(iconPath.ToString(), value); - } - } - } - - /// - /// Gets/sets the fully qualified path to the link's target - /// - public string Target - { - get - { - var target = new StringBuilder(260, 260); - if (linkA == null) - { - var fd = new _WIN32_FIND_DATAW(); - linkW.GetPath(target, target.Capacity, ref fd, (uint)EShellLinkGP.SLGP_UNCPRIORITY); - } - else - { - var fd = new _WIN32_FIND_DATAA(); - linkA.GetPath(target, target.Capacity, ref fd, (uint)EShellLinkGP.SLGP_UNCPRIORITY); - } - return target.ToString(); - } - set - { - if (linkA == null) - { - linkW.SetPath(value); - } - else - { - linkA.SetPath(value); - } - } - } - - /// - /// Gets/sets the Working Directory for the Link - /// - public string WorkingDirectory - { - get - { - var path = new StringBuilder(260, 260); - if (linkA == null) - { - linkW.GetWorkingDirectory(path, path.Capacity); - } - else - { - linkA.GetWorkingDirectory(path, path.Capacity); - } - return path.ToString(); - } - set - { - if (linkA == null) - { - linkW.SetWorkingDirectory(value); - } - else - { - linkA.SetWorkingDirectory(value); - } - } - } - - /// - /// Gets/sets the description of the link - /// - public string Description - { - get - { - var description = new StringBuilder(1024, 1024); - if (linkA == null) - { - linkW.GetDescription(description, description.Capacity); - } - else - { - linkA.GetDescription(description, description.Capacity); - } - return description.ToString(); - } - set - { - if (linkA == null) - { - linkW.SetDescription(value); - } - else - { - linkA.SetDescription(value); - } - } - } - - /// - /// Gets/sets any command line arguments associated with the link - /// - public string Arguments - { - get - { - var arguments = new StringBuilder(260, 260); - if (linkA == null) - { - linkW.GetArguments(arguments, arguments.Capacity); - } - else - { - linkA.GetArguments(arguments, arguments.Capacity); - } - return arguments.ToString(); - } - set - { - if (linkA == null) - { - linkW.SetArguments(value); - } - else - { - linkA.SetArguments(value); - } - } - } - - /// - /// Gets/sets the initial display mode when the shortcut is - /// run - /// - public LinkDisplayMode DisplayMode - { - get - { - uint cmd; - if (linkA == null) - { - linkW.GetShowCmd(out cmd); - } - else - { - linkA.GetShowCmd(out cmd); - } - return (LinkDisplayMode)cmd; - } - set - { - if (linkA == null) - { - linkW.SetShowCmd((uint)value); - } - else - { - linkA.SetShowCmd((uint)value); - } - } - } - - /// - /// Gets/sets the HotKey to start the shortcut (if any) - /// - public Keys HotKey - { - get - { - short key; - if (linkA == null) - { - linkW.GetHotkey(out key); - } - else - { - linkA.GetHotkey(out key); - } - return (Keys)key; - } - set - { - if (linkA == null) - { - linkW.SetHotkey((short)value); - } - else - { - linkA.SetHotkey((short)value); - } - } - } - - /// - /// Saves the shortcut to ShortCutFile. - /// - public void Save() - { - Save(shortcutFile); - } - - /// - /// Saves the shortcut to the specified file - /// - /// The shortcut file (.lnk) - public void Save( - string linkFile - ) - { - // Save the object to disk - if (linkA == null) - { - ((IPersistFile)linkW).Save(linkFile, true); - shortcutFile = linkFile; - } - else - { - ((IPersistFile)linkA).Save(linkFile, true); - shortcutFile = linkFile; - } - } - - /// - /// Loads a shortcut from the specified file - /// - /// The shortcut file (.lnk) to load - public void Open( - string linkFile - ) - { - Open(linkFile, - IntPtr.Zero, - (EShellLinkResolveFlags.SLR_ANY_MATCH | EShellLinkResolveFlags.SLR_NO_UI), - 1); - } - - /// - /// Loads a shortcut from the specified file, and allows flags controlling - /// the UI behaviour if the shortcut's target isn't found to be set. - /// - /// The shortcut file (.lnk) to load - /// The window handle of the application's UI, if any - /// Flags controlling resolution behaviour - public void Open( - string linkFile, - IntPtr hWnd, - EShellLinkResolveFlags resolveFlags - ) - { - Open(linkFile, - hWnd, - resolveFlags, - 1); - } - - /// - /// Loads a shortcut from the specified file, and allows flags controlling - /// the UI behaviour if the shortcut's target isn't found to be set. If - /// no SLR_NO_UI is specified, you can also specify a timeout. - /// - /// The shortcut file (.lnk) to load - /// The window handle of the application's UI, if any - /// Flags controlling resolution behaviour - /// Timeout if SLR_NO_UI is specified, in ms. - public void Open( - string linkFile, - IntPtr hWnd, - EShellLinkResolveFlags resolveFlags, - ushort timeOut - ) - { - uint flags; - - if ((resolveFlags & EShellLinkResolveFlags.SLR_NO_UI) - == EShellLinkResolveFlags.SLR_NO_UI) - { - flags = (uint)((int)resolveFlags | (timeOut << 16)); - } - else - { - flags = (uint)resolveFlags; - } - - if (linkA == null) - { - ((IPersistFile)linkW).Load(linkFile, 0); //STGM_DIRECT) - linkW.Resolve(hWnd, flags); - this.shortcutFile = linkFile; - } - else - { - ((IPersistFile)linkA).Load(linkFile, 0); //STGM_DIRECT) - linkA.Resolve(hWnd, flags); - this.shortcutFile = linkFile; - } - } - #endregion - } - #endregion + #region File icon + /// + /// Enables extraction of icons for any file type from + /// the Shell. + /// + public class FileIcon + { + #region UnmanagedCode + private const int MAX_PATH = 260; + + [StructLayout(LayoutKind.Sequential)] + private struct SHFILEINFO + { + public readonly IntPtr hIcon; + private readonly int iIcon; + private readonly int dwAttributes; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] + public readonly string szDisplayName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + public readonly string szTypeName; + } + + [DllImport("shell32")] + private static extern int SHGetFileInfo( + string pszPath, + int dwFileAttributes, + ref SHFILEINFO psfi, + uint cbFileInfo, + uint uFlags); + + private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000; + private const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x200; + [DllImport("kernel32")] + private static extern int FormatMessage( + int dwFlags, + IntPtr lpSource, + int dwMessageId, + int dwLanguageId, + string lpBuffer, + uint nSize, + int argumentsLong); + + [DllImport("kernel32")] + private static extern int GetLastError(); + #endregion + + #region Member Variables + private string fileName; + private string displayName; + private string typeName; + private SHGetFileInfoConstants flags; + + #endregion + + #region Enumerations + [Flags] + public enum SHGetFileInfoConstants + { + SHGFI_ICON = 0x100, // get icon + SHGFI_DISPLAYNAME = 0x200, // get display name + SHGFI_TYPENAME = 0x400, // get type name + SHGFI_ATTRIBUTES = 0x800, // get attributes + SHGFI_ICONLOCATION = 0x1000, // get icon location + SHGFI_EXETYPE = 0x2000, // return exe type + SHGFI_SYSICONINDEX = 0x4000, // get system icon index + SHGFI_LINKOVERLAY = 0x8000, // put a link overlay on icon + SHGFI_SELECTED = 0x10000, // show icon in selected state + SHGFI_ATTR_SPECIFIED = 0x20000, // get only specified attributes + SHGFI_LARGEICON = 0x0, // get large icon + SHGFI_SMALLICON = 0x1, // get small icon + SHGFI_OPENICON = 0x2, // get open icon + SHGFI_SHELLICONSIZE = 0x4, // get shell size icon + //SHGFI_PIDL = 0x8, // pszPath is a pidl + SHGFI_USEFILEATTRIBUTES = 0x10, // use passed dwFileAttribute + SHGFI_ADDOVERLAYS = 0x000000020, // apply the appropriate overlays + SHGFI_OVERLAYINDEX = 0x000000040 // Get the index of the overlay + } + #endregion + + #region Implementation + + /// + /// Gets the icon for the chosen file + /// + public Icon ShellIcon { get; private set; } + + /// + /// Gets the display name for the selected file + /// if the SHGFI_DISPLAYNAME flag was set. + /// + public string DisplayName + { + get + { + return displayName; + } + } + + /// + /// Gets the type name for the selected file + /// if the SHGFI_TYPENAME flag was set. + /// + public string TypeName + { + get + { + return typeName; + } + } + + /// + /// Gets the information for the specified + /// file name and flags. + /// + public void GetInfo() + { + ShellIcon = null; + typeName = ""; + displayName = ""; + + var shfi = new SHFILEINFO(); + var shfiSize = (uint)Marshal.SizeOf(shfi.GetType()); + + var ret = SHGetFileInfo( + fileName, 0, ref shfi, shfiSize, (uint)(flags)); + if (ret != 0) + { + if (shfi.hIcon != IntPtr.Zero) + { + ShellIcon = Icon.FromHandle(shfi.hIcon); + } + typeName = shfi.szTypeName; + displayName = shfi.szDisplayName; + } + else + { + + var err = GetLastError(); + Console.WriteLine("Error {0}", err); + var txtS = new string('\0', 256); + var len = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + IntPtr.Zero, err, 0, txtS, 256, 0); + Console.WriteLine("Len {0} text {1}", len, txtS); + } + } + + /// + /// Constructs a new, default instance of the FileIcon + /// class. Specify the filename and call GetInfo() + /// to retrieve an icon. + /// + public FileIcon() + { + flags = SHGetFileInfoConstants.SHGFI_ICON | + SHGetFileInfoConstants.SHGFI_DISPLAYNAME | + SHGetFileInfoConstants.SHGFI_TYPENAME | + SHGetFileInfoConstants.SHGFI_ATTRIBUTES | + SHGetFileInfoConstants.SHGFI_EXETYPE; + } + /// + /// Constructs a new instance of the FileIcon class + /// and retrieves the icon, display name and type name + /// for the specified file. + /// + /// The filename to get the icon, + /// display name and type name for + public FileIcon(string fileName) : this() + { + this.fileName = fileName; + GetInfo(); + } + /// + /// Constructs a new instance of the FileIcon class + /// and retrieves the information specified in the + /// flags. + /// + /// The filename to get information + /// for + /// The flags to use when extracting the + /// icon and other shell information. + public FileIcon(string fileName, SHGetFileInfoConstants flags) + { + this.fileName = fileName; + this.flags = flags; + GetInfo(); + } + + #endregion + } + #endregion + #region ShellLink Object + /// + /// Summary description for ShellLink. + /// + public class ShellLink : IDisposable + { + #region ComInterop for IShellLink + + #region IPersist Interface + [ComImport()] + [Guid("0000010C-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IPersist + { + [PreserveSig] + //[helpstring("Returns the class identifier for the component object")] + void GetClassID(out Guid pClassID); + } + #endregion + + #region IPersistFile Interface + [ComImport()] + [Guid("0000010B-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IPersistFile + { + // can't get this to go if I extend IPersist, so put it here: + [PreserveSig] + void GetClassID(out Guid pClassID); + + //[helpstring("Checks for changes since last file write")] + void IsDirty(); + + //[helpstring("Opens the specified file and initializes the object from its contents")] + void Load( + [MarshalAs(UnmanagedType.LPWStr)] string pszFileName, + uint dwMode); + + //[helpstring("Saves the object into the specified file")] + void Save( + [MarshalAs(UnmanagedType.LPWStr)] string pszFileName, + [MarshalAs(UnmanagedType.Bool)] bool fRemember); + + //[helpstring("Notifies the object that save is completed")] + void SaveCompleted( + [MarshalAs(UnmanagedType.LPWStr)] string pszFileName); + + //[helpstring("Gets the current name of the file associated with the object")] + void GetCurFile( + [MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName); + } + #endregion + + #region IShellLink Interface + [ComImport()] + [Guid("000214EE-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IShellLinkA + { + //[helpstring("Retrieves the path and filename of a shell link object")] + void GetPath( + [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, + int cchMaxPath, + ref _WIN32_FIND_DATAA pfd, + uint fFlags); + + //[helpstring("Retrieves the list of shell link item identifiers")] + void GetIDList(out IntPtr ppidl); + + //[helpstring("Sets the list of shell link item identifiers")] + void SetIDList(IntPtr pidl); + + //[helpstring("Retrieves the shell link description string")] + void GetDescription( + [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, + int cchMaxName); + + //[helpstring("Sets the shell link description string")] + void SetDescription( + [MarshalAs(UnmanagedType.LPStr)] string pszName); + + //[helpstring("Retrieves the name of the shell link working directory")] + void GetWorkingDirectory( + [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszDir, + int cchMaxPath); + + //[helpstring("Sets the name of the shell link working directory")] + void SetWorkingDirectory( + [MarshalAs(UnmanagedType.LPStr)] string pszDir); + + //[helpstring("Retrieves the shell link command-line arguments")] + void GetArguments( + [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszArgs, + int cchMaxPath); + + //[helpstring("Sets the shell link command-line arguments")] + void SetArguments( + [MarshalAs(UnmanagedType.LPStr)] string pszArgs); + + //[propget, helpstring("Retrieves or sets the shell link hot key")] + void GetHotkey(out short pwHotkey); + //[propput, helpstring("Retrieves or sets the shell link hot key")] + void SetHotkey(short pwHotkey); + + //[propget, helpstring("Retrieves or sets the shell link show command")] + void GetShowCmd(out uint piShowCmd); + //[propput, helpstring("Retrieves or sets the shell link show command")] + void SetShowCmd(uint piShowCmd); + + //[helpstring("Retrieves the location (path and index) of the shell link icon")] + void GetIconLocation( + [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszIconPath, + int cchIconPath, + out int piIcon); + + //[helpstring("Sets the location (path and index) of the shell link icon")] + void SetIconLocation( + [MarshalAs(UnmanagedType.LPStr)] string pszIconPath, + int iIcon); + + //[helpstring("Sets the shell link relative path")] + void SetRelativePath( + [MarshalAs(UnmanagedType.LPStr)] string pszPathRel, + uint dwReserved); + + //[helpstring("Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary)")] + void Resolve( + IntPtr hWnd, + uint fFlags); + + //[helpstring("Sets the shell link path and filename")] + void SetPath( + [MarshalAs(UnmanagedType.LPStr)] string pszFile); + } + + + [ComImport()] + [Guid("000214F9-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IShellLinkW + { + //[helpstring("Retrieves the path and filename of a shell link object")] + void GetPath( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, + int cchMaxPath, + ref _WIN32_FIND_DATAW pfd, + uint fFlags); + + //[helpstring("Retrieves the list of shell link item identifiers")] + void GetIDList(out IntPtr ppidl); + + //[helpstring("Sets the list of shell link item identifiers")] + void SetIDList(IntPtr pidl); + + //[helpstring("Retrieves the shell link description string")] + void GetDescription( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, + int cchMaxName); + + //[helpstring("Sets the shell link description string")] + void SetDescription( + [MarshalAs(UnmanagedType.LPWStr)] string pszName); + + //[helpstring("Retrieves the name of the shell link working directory")] + void GetWorkingDirectory( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, + int cchMaxPath); + + //[helpstring("Sets the name of the shell link working directory")] + void SetWorkingDirectory( + [MarshalAs(UnmanagedType.LPWStr)] string pszDir); + + //[helpstring("Retrieves the shell link command-line arguments")] + void GetArguments( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, + int cchMaxPath); + + //[helpstring("Sets the shell link command-line arguments")] + void SetArguments( + [MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + + //[propget, helpstring("Retrieves or sets the shell link hot key")] + void GetHotkey(out short pwHotkey); + //[propput, helpstring("Retrieves or sets the shell link hot key")] + void SetHotkey(short pwHotkey); + + //[propget, helpstring("Retrieves or sets the shell link show command")] + void GetShowCmd(out uint piShowCmd); + //[propput, helpstring("Retrieves or sets the shell link show command")] + void SetShowCmd(uint piShowCmd); + + //[helpstring("Retrieves the location (path and index) of the shell link icon")] + void GetIconLocation( + [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, + int cchIconPath, + out int piIcon); + + //[helpstring("Sets the location (path and index) of the shell link icon")] + void SetIconLocation( + [MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, + int iIcon); + + //[helpstring("Sets the shell link relative path")] + void SetRelativePath( + [MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, + uint dwReserved); + + //[helpstring("Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary)")] + void Resolve( + IntPtr hWnd, + uint fFlags); + + //[helpstring("Sets the shell link path and filename")] + void SetPath( + [MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } + #endregion + + #region ShellLinkCoClass + [Guid("00021401-0000-0000-C000-000000000046")] + [ClassInterface(ClassInterfaceType.None)] + [ComImport()] + private class CShellLink { } + + #endregion + + #region Private IShellLink enumerations + private enum EShellLinkGP : uint + { + SLGP_UNCPRIORITY = 2 + } + + [Flags] + private enum EShowWindowFlags : uint + { + SW_NORMAL = 1, + SW_MAXIMIZE = 3, + SW_SHOWMINNOACTIVE = 7, + } + #endregion + + #region IShellLink Private structs + + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0, CharSet = CharSet.Unicode)] + private struct _WIN32_FIND_DATAW + { + public readonly uint dwFileAttributes; + public readonly _FILETIME ftCreationTime; + public readonly _FILETIME ftLastAccessTime; + public readonly _FILETIME ftLastWriteTime; + public readonly uint nFileSizeHigh; + public readonly uint nFileSizeLow; + public readonly uint dwReserved0; + public readonly uint dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] // MAX_PATH + public readonly string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] + public readonly string cAlternateFileName; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0, CharSet = CharSet.Ansi)] + private struct _WIN32_FIND_DATAA + { + public readonly uint dwFileAttributes; + public readonly _FILETIME ftCreationTime; + public readonly _FILETIME ftLastAccessTime; + public readonly _FILETIME ftLastWriteTime; + public readonly uint nFileSizeHigh; + public readonly uint nFileSizeLow; + public readonly uint dwReserved0; + public readonly uint dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] // MAX_PATH + public readonly string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] + public readonly string cAlternateFileName; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0)] + private struct _FILETIME + { + public readonly uint dwLowDateTime; + public readonly uint dwHighDateTime; + } + #endregion + + #region UnManaged Methods + private class UnManagedMethods + { + [DllImport("Shell32", CharSet = CharSet.Auto)] + internal static extern int ExtractIconEx( + [MarshalAs(UnmanagedType.LPTStr)] + string lpszFile, + int nIconIndex, + IntPtr[] phIconLarge, + IntPtr[] phIconSmall, + int nIcons); + } + #endregion + + #endregion + + #region Enumerations + /// + /// Flags determining how the links with missing + /// targets are resolved. + /// + [Flags] + public enum EShellLinkResolveFlags : uint + { + /// + /// Allow any match during resolution. Has no effect + /// on ME/2000 or above, use the other flags instead. + /// + SLR_ANY_MATCH = 0x2, + /// + /// Call the Microsoft Windows Installer. + /// + SLR_INVOKE_MSI = 0x80, + /// + /// Disable distributed link tracking. By default, + /// distributed link tracking tracks removable media + /// across multiple devices based on the volume name. + /// It also uses the UNC path to track remote file + /// systems whose drive letter has changed. Setting + /// SLR_NOLINKINFO disables both types of tracking. + /// + SLR_NOLINKINFO = 0x40, + /// + /// Do not display a dialog box if the link cannot be resolved. + /// When SLR_NO_UI is set, a time-out value that specifies the + /// maximum amount of time to be spent resolving the link can + /// be specified in milliseconds. The function returns if the + /// link cannot be resolved within the time-out duration. + /// If the timeout is not set, the time-out duration will be + /// set to the default value of 3,000 milliseconds (3 seconds). + /// + SLR_NO_UI = 0x1, + /// + /// Not documented in SDK. Assume same as SLR_NO_UI but + /// intended for applications without a hWnd. + /// + SLR_NO_UI_WITH_MSG_PUMP = 0x101, + /// + /// Do not update the link information. + /// + SLR_NOUPDATE = 0x8, + /// + /// Do not execute the search heuristics. + /// + SLR_NOSEARCH = 0x10, + /// + /// Do not use distributed link tracking. + /// + SLR_NOTRACK = 0x20, + /// + /// If the link object has changed, update its path and list + /// of identifiers. If SLR_UPDATE is set, you do not need to + /// call IPersistFile::IsDirty to determine whether or not + /// the link object has changed. + /// + SLR_UPDATE = 0x4 + } + + public enum LinkDisplayMode : uint + { + edmNormal = EShowWindowFlags.SW_NORMAL, + edmMinimized = EShowWindowFlags.SW_SHOWMINNOACTIVE, + edmMaximized = EShowWindowFlags.SW_MAXIMIZE + } + #endregion + + #region Member Variables + // Use Unicode (W) under NT, otherwise use ANSI + private IShellLinkW linkW; + private IShellLinkA linkA; + private string shortcutFile = ""; + #endregion + + #region Constructor + /// + /// Creates an instance of the Shell Link object. + /// + public ShellLink() + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + linkW = (IShellLinkW)new CShellLink(); + } + else + { + linkA = (IShellLinkA)new CShellLink(); + } + } + + /// + /// Creates an instance of a Shell Link object + /// from the specified link file + /// + /// The Shortcut file to open + public ShellLink(string linkFile) : this() + { + Open(linkFile); + } + #endregion + + #region Destructor and Dispose + /// + /// Call dispose just in case it hasn't happened yet + /// + ~ShellLink() + { + Dispose(); + } + + /// + /// Dispose the object, releasing the COM ShellLink object + /// + public void Dispose() + { + if (linkW != null) + { + Marshal.ReleaseComObject(linkW); + linkW = null; + } + if (linkA != null) + { + Marshal.ReleaseComObject(linkA); + linkA = null; + } + } + #endregion + + #region Implementation + public string ShortCutFile + { + get + { + return this.shortcutFile; + } + set + { + this.shortcutFile = value; + } + } + + /// + /// Gets a System.Drawing.Icon containing the icon for this + /// ShellLink object. + /// + public Icon LargeIcon + { + get + { + return getIcon(true); + } + } + + public Icon SmallIcon + { + get + { + return getIcon(false); + } + } + + private Icon getIcon(bool large) + { + // Get icon index and path: + int iconIndex; + var iconPath = new StringBuilder(260, 260); + if (linkA == null) + { + linkW.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); + } + else + { + linkA.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); + } + var iconFile = iconPath.ToString(); + + // If there are no details set for the icon, then we must use + // the shell to get the icon for the target: + if (iconFile.Length == 0) + { + // Use the FileIcon object to get the icon: + var flags = FileIcon.SHGetFileInfoConstants.SHGFI_ICON | + FileIcon.SHGetFileInfoConstants.SHGFI_ATTRIBUTES; + if (large) + { + flags = flags | FileIcon.SHGetFileInfoConstants.SHGFI_LARGEICON; + } + else + { + flags = flags | FileIcon.SHGetFileInfoConstants.SHGFI_SMALLICON; + } + var fileIcon = new FileIcon(Target, flags); + return fileIcon.ShellIcon; + } + else + { + // Use ExtractIconEx to get the icon: + var hIconEx = new[] { IntPtr.Zero }; + if (large) + { + UnManagedMethods.ExtractIconEx( + iconFile, + iconIndex, + hIconEx, + null, + 1); + } + else + { + UnManagedMethods.ExtractIconEx( + iconFile, + iconIndex, + null, + hIconEx, + 1); + } + // If success then return as a GDI+ object + Icon icon = null; + if (hIconEx[0] != IntPtr.Zero) + { + icon = Icon.FromHandle(hIconEx[0]); + //UnManagedMethods.DestroyIcon(hIconEx[0]); + } + return icon; + } + } + + /// + /// Gets the path to the file containing the icon for this shortcut. + /// + public string IconPath + { + get + { + var iconPath = new StringBuilder(260, 260); + if (linkA == null) + { + linkW.GetIconLocation(iconPath, iconPath.Capacity, out _); + } + else + { + linkA.GetIconLocation(iconPath, iconPath.Capacity, out _); + } + return iconPath.ToString(); + } + set + { + var iconPath = new StringBuilder(260, 260); + int iconIndex; + if (linkA == null) + { + linkW.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); + } + else + { + linkA.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); + } + if (linkA == null) + { + linkW.SetIconLocation(value, iconIndex); + } + else + { + linkA.SetIconLocation(value, iconIndex); + } + } + } + + /// + /// Gets the index of this icon within the icon path's resources + /// + public int IconIndex + { + get + { + var iconPath = new StringBuilder(260, 260); + int iconIndex; + if (linkA == null) + { + linkW.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); + } + else + { + linkA.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex); + } + return iconIndex; + } + set + { + var iconPath = new StringBuilder(260, 260); + if (linkA == null) + { + linkW.GetIconLocation(iconPath, iconPath.Capacity, out _); + } + else + { + linkA.GetIconLocation(iconPath, iconPath.Capacity, out _); + } + if (linkA == null) + { + linkW.SetIconLocation(iconPath.ToString(), value); + } + else + { + linkA.SetIconLocation(iconPath.ToString(), value); + } + } + } + + /// + /// Gets/sets the fully qualified path to the link's target + /// + public string Target + { + get + { + var target = new StringBuilder(260, 260); + if (linkA == null) + { + var fd = new _WIN32_FIND_DATAW(); + linkW.GetPath(target, target.Capacity, ref fd, (uint)EShellLinkGP.SLGP_UNCPRIORITY); + } + else + { + var fd = new _WIN32_FIND_DATAA(); + linkA.GetPath(target, target.Capacity, ref fd, (uint)EShellLinkGP.SLGP_UNCPRIORITY); + } + return target.ToString(); + } + set + { + if (linkA == null) + { + linkW.SetPath(value); + } + else + { + linkA.SetPath(value); + } + } + } + + /// + /// Gets/sets the Working Directory for the Link + /// + public string WorkingDirectory + { + get + { + var path = new StringBuilder(260, 260); + if (linkA == null) + { + linkW.GetWorkingDirectory(path, path.Capacity); + } + else + { + linkA.GetWorkingDirectory(path, path.Capacity); + } + return path.ToString(); + } + set + { + if (linkA == null) + { + linkW.SetWorkingDirectory(value); + } + else + { + linkA.SetWorkingDirectory(value); + } + } + } + + /// + /// Gets/sets the description of the link + /// + public string Description + { + get + { + var description = new StringBuilder(1024, 1024); + if (linkA == null) + { + linkW.GetDescription(description, description.Capacity); + } + else + { + linkA.GetDescription(description, description.Capacity); + } + return description.ToString(); + } + set + { + if (linkA == null) + { + linkW.SetDescription(value); + } + else + { + linkA.SetDescription(value); + } + } + } + + /// + /// Gets/sets any command line arguments associated with the link + /// + public string Arguments + { + get + { + var arguments = new StringBuilder(260, 260); + if (linkA == null) + { + linkW.GetArguments(arguments, arguments.Capacity); + } + else + { + linkA.GetArguments(arguments, arguments.Capacity); + } + return arguments.ToString(); + } + set + { + if (linkA == null) + { + linkW.SetArguments(value); + } + else + { + linkA.SetArguments(value); + } + } + } + + /// + /// Gets/sets the initial display mode when the shortcut is + /// run + /// + public LinkDisplayMode DisplayMode + { + get + { + uint cmd; + if (linkA == null) + { + linkW.GetShowCmd(out cmd); + } + else + { + linkA.GetShowCmd(out cmd); + } + return (LinkDisplayMode)cmd; + } + set + { + if (linkA == null) + { + linkW.SetShowCmd((uint)value); + } + else + { + linkA.SetShowCmd((uint)value); + } + } + } + + /// + /// Gets/sets the HotKey to start the shortcut (if any) + /// + public Keys HotKey + { + get + { + short key; + if (linkA == null) + { + linkW.GetHotkey(out key); + } + else + { + linkA.GetHotkey(out key); + } + return (Keys)key; + } + set + { + if (linkA == null) + { + linkW.SetHotkey((short)value); + } + else + { + linkA.SetHotkey((short)value); + } + } + } + + /// + /// Saves the shortcut to ShortCutFile. + /// + public void Save() + { + Save(shortcutFile); + } + + /// + /// Saves the shortcut to the specified file + /// + /// The shortcut file (.lnk) + public void Save( + string linkFile + ) + { + // Save the object to disk + if (linkA == null) + { + ((IPersistFile)linkW).Save(linkFile, true); + shortcutFile = linkFile; + } + else + { + ((IPersistFile)linkA).Save(linkFile, true); + shortcutFile = linkFile; + } + } + + /// + /// Loads a shortcut from the specified file + /// + /// The shortcut file (.lnk) to load + public void Open( + string linkFile + ) + { + Open(linkFile, + IntPtr.Zero, + (EShellLinkResolveFlags.SLR_ANY_MATCH | EShellLinkResolveFlags.SLR_NO_UI), + 1); + } + + /// + /// Loads a shortcut from the specified file, and allows flags controlling + /// the UI behaviour if the shortcut's target isn't found to be set. + /// + /// The shortcut file (.lnk) to load + /// The window handle of the application's UI, if any + /// Flags controlling resolution behaviour + public void Open( + string linkFile, + IntPtr hWnd, + EShellLinkResolveFlags resolveFlags + ) + { + Open(linkFile, + hWnd, + resolveFlags, + 1); + } + + /// + /// Loads a shortcut from the specified file, and allows flags controlling + /// the UI behaviour if the shortcut's target isn't found to be set. If + /// no SLR_NO_UI is specified, you can also specify a timeout. + /// + /// The shortcut file (.lnk) to load + /// The window handle of the application's UI, if any + /// Flags controlling resolution behaviour + /// Timeout if SLR_NO_UI is specified, in ms. + public void Open( + string linkFile, + IntPtr hWnd, + EShellLinkResolveFlags resolveFlags, + ushort timeOut + ) + { + uint flags; + + if ((resolveFlags & EShellLinkResolveFlags.SLR_NO_UI) + == EShellLinkResolveFlags.SLR_NO_UI) + { + flags = (uint)((int)resolveFlags | (timeOut << 16)); + } + else + { + flags = (uint)resolveFlags; + } + + if (linkA == null) + { + ((IPersistFile)linkW).Load(linkFile, 0); //STGM_DIRECT) + linkW.Resolve(hWnd, flags); + this.shortcutFile = linkFile; + } + else + { + ((IPersistFile)linkA).Load(linkFile, 0); //STGM_DIRECT) + linkA.Resolve(hWnd, flags); + this.shortcutFile = linkFile; + } + } + #endregion + } + #endregion } diff --git a/Rectify11Installer/Win32/VisualStylesRendererExtension.cs b/Rectify11Installer/Win32/Vanara/VisualStylesRendererExtension.cs similarity index 100% rename from Rectify11Installer/Win32/VisualStylesRendererExtension.cs rename to Rectify11Installer/Win32/Vanara/VisualStylesRendererExtension.cs diff --git a/Rectify11Installer/packages.config b/Rectify11Installer/packages.config deleted file mode 100644 index d5d482b59..000000000 --- a/Rectify11Installer/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file