diff --git a/src/Installer/Installer.vdproj b/src/Installer/Installer.vdproj index a82130d..e6160c7 100644 --- a/src/Installer/Installer.vdproj +++ b/src/Installer/Installer.vdproj @@ -33,6 +33,12 @@ } "Entry" { + "MsmKey" = "8:_E544DEE7648C4E86937A8A746067D64C" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_FD08D480081E2A6C3D1A5EA9C82FC43F" "OwnerKey" = "8:_FD2FE03164614192A11D674CB6FD870E" "MsmSig" = "8:_UNDEFINED" @@ -52,6 +58,12 @@ "Entry" { "MsmKey" = "8:_UNDEFINED" + "OwnerKey" = "8:_E544DEE7648C4E86937A8A746067D64C" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_UNDEFINED" "OwnerKey" = "8:_FD08D480081E2A6C3D1A5EA9C82FC43F" "MsmSig" = "8:_UNDEFINED" } @@ -127,6 +139,20 @@ { "CustomAction" { + "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_70B50EF584624E8CA01EA1C853DE2D27" + { + "Name" = "8:Primary output from PostInstaller (Active)" + "Condition" = "8:" + "Object" = "8:_E544DEE7648C4E86937A8A746067D64C" + "FileType" = "3:2" + "InstallAction" = "3:1" + "Arguments" = "8:\"[ProgramMenuFolder]OnTopReplica\\OnTopReplica.lnk\" \"LorenzCunoKlopfenstein.OnTopReplica.MainForm\"" + "EntryPoint" = "8:" + "Sequence" = "3:1" + "Identifier" = "8:_FD81C6C3_6535_47C7_AD92_C0871E83103C" + "InstallerClass" = "11:FALSE" + "CustomActionData" = "8:" + } } "DefaultFeature" { @@ -247,17 +273,6 @@ } "Folder" { - "{1525181F-901A-416C-8A58-119130FE478E}:_39F91DA891324B10BB3097F6C6192D17" - { - "Name" = "8:#1916" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:DesktopFolder" - "Folders" - { - } - } "{3C67513D-01DD-4637-8A68-80971EB9504F}:_92458F5B5377456CB04EFACB28735CC9" { "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" @@ -309,11 +324,11 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:OnTopReplica" "ProductCode" = "8:{524E0F6C-A2D8-434C-A32D-3BCBF17FC5C6}" - "PackageCode" = "8:{CA4567E0-2134-40DD-AB06-06E910C7A253}" + "PackageCode" = "8:{4380D7A0-0222-4D27-964F-43FBFB59ACE6}" "UpgradeCode" = "8:{6EBB4E0A-1F0C-4302-AC60-45E05F641909}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" - "RemovePreviousVersions" = "11:FALSE" + "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" "ProductVersion" = "8:3.6.0" @@ -443,20 +458,6 @@ "Icon" = "8:_BB607179F88446409C91AC786E95410C" "Feature" = "8:" } - "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_91FD25A1D4E9441B9BADF46738B5D411" - { - "Name" = "8:OnTopReplica" - "Arguments" = "8:" - "Description" = "8:" - "ShowCmd" = "3:1" - "IconIndex" = "3:0" - "Transitive" = "11:FALSE" - "Target" = "8:_FD2FE03164614192A11D674CB6FD870E" - "Folder" = "8:_39F91DA891324B10BB3097F6C6192D17" - "WorkingFolder" = "8:_92458F5B5377456CB04EFACB28735CC9" - "Icon" = "8:_BB607179F88446409C91AC786E95410C" - "Feature" = "8:" - } } "UserInterface" { @@ -1026,7 +1027,7 @@ "Folder" = "8:_92458F5B5377456CB04EFACB28735CC9" "Condition" = "8:" "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" + "Vital" = "11:FALSE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" @@ -1046,9 +1047,37 @@ { } } + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_E544DEE7648C4E86937A8A746067D64C" + { + "SourcePath" = "8:..\\PostInstaller\\obj\\Debug\\PostInstaller.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_92458F5B5377456CB04EFACB28735CC9" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:" + "OutputGroupCanonicalName" = "8:Built" + "OutputProjectGuid" = "8:{05F8E270-8B47-449B-8755-4599B3B3A565}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_FD2FE03164614192A11D674CB6FD870E" { - "SourcePath" = "8:..\\OnTopReplica\\obj\\Release\\OnTopReplica.exe" + "SourcePath" = "8:..\\OnTopReplica\\obj\\Debug\\OnTopReplica.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_92458F5B5377456CB04EFACB28735CC9" diff --git a/src/OnTopReplica.sln b/src/OnTopReplica.sln index fb99208..4603e4e 100644 --- a/src/OnTopReplica.sln +++ b/src/OnTopReplica.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OnTopReplica", "OnTopReplic EndProject Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Installer", "Installer\Installer.vdproj", "{EA7C9C89-0CCF-41E3-A379-D593AAF7A941}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostInstaller", "PostInstaller\PostInstaller.csproj", "{05F8E270-8B47-449B-8755-4599B3B3A565}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -41,6 +43,18 @@ Global {EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|x64.Build.0 = Release {EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|x86.ActiveCfg = Release {EA7C9C89-0CCF-41E3-A379-D593AAF7A941}.Release|x86.Build.0 = Release + {05F8E270-8B47-449B-8755-4599B3B3A565}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Debug|x64.ActiveCfg = Debug|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Debug|x64.Build.0 = Debug|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Debug|x86.ActiveCfg = Debug|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Debug|x86.Build.0 = Debug|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Release|Any CPU.Build.0 = Release|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Release|x64.ActiveCfg = Release|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Release|x64.Build.0 = Release|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Release|x86.ActiveCfg = Release|Any CPU + {05F8E270-8B47-449B-8755-4599B3B3A565}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/PostInstaller/App.config b/src/PostInstaller/App.config new file mode 100644 index 0000000..b9acc38 --- /dev/null +++ b/src/PostInstaller/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/PostInstaller/IPersistFile.cs b/src/PostInstaller/IPersistFile.cs new file mode 100644 index 0000000..e869ce8 --- /dev/null +++ b/src/PostInstaller/IPersistFile.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace PostInstaller { + + [ComImportAttribute] + [GuidAttribute("0000010B-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + public interface IPersistFile { + + // can't get this to go if I extend IPersist, + // so put it here: + [PreserveSig] + int GetClassID(out Guid pClassID); + + //[helpstring("Checks for changes since + // last file write")] + [PreserveSig] + int IsDirty(); + + //[helpstring("Opens the specified file and + // initializes the object from its contents")] + int Load( + [MarshalAs(UnmanagedType.LPWStr)] string pszFileName, + ulong 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); + + } +} diff --git a/src/PostInstaller/IPropertyStore.cs b/src/PostInstaller/IPropertyStore.cs new file mode 100644 index 0000000..f6e705d --- /dev/null +++ b/src/PostInstaller/IPropertyStore.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace PostInstaller { + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")] + public interface IPropertyStore { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetCount([Out] out uint cProps); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetAt([In] uint iProp, out PropertyKey pkey); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void GetValue([In] ref PropertyKey key, out object pv); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void SetValue([In] ref PropertyKey key, [In] ref object pv); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void Commit(); + } +} diff --git a/src/PostInstaller/IShellItem.cs b/src/PostInstaller/IShellItem.cs new file mode 100644 index 0000000..0ba3a6d --- /dev/null +++ b/src/PostInstaller/IShellItem.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace PostInstaller { + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] + public interface IShellItem { + + } +} diff --git a/src/PostInstaller/IShellLink.cs b/src/PostInstaller/IShellLink.cs new file mode 100644 index 0000000..c0efade --- /dev/null +++ b/src/PostInstaller/IShellLink.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace PostInstaller { + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("000214F9-0000-0000-C000-000000000046")] + public interface IShellLink { + + /// Retrieves the path and file name of a Shell link object + void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, int fFlags); + + /// Retrieves the list of item identifiers for a Shell link object + void GetIDList(out IntPtr ppidl); + /// Sets the pointer to an item identifier list (PIDL) for a Shell link object. + void SetIDList(IntPtr pidl); + /// Retrieves the description string for a Shell link object + void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); + /// Sets the description for a Shell link object. The description can be any application-defined string + void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + /// Retrieves the name of the working directory for a Shell link object + void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + /// Sets the name of the working directory for a Shell link object + void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + /// Retrieves the command-line arguments associated with a Shell link object + void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + /// Sets the command-line arguments for a Shell link object + void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + /// Retrieves the hot key for a Shell link object + void GetHotkey(out short pwHotkey); + /// Sets a hot key for a Shell link object + void SetHotkey(short wHotkey); + /// Retrieves the show command for a Shell link object + void GetShowCmd(out int piShowCmd); + /// Sets the show command for a Shell link object. The show command sets the initial show state of the window. + void SetShowCmd(int iShowCmd); + /// Retrieves the location (path and index) of the icon for a Shell link object + void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, + int cchIconPath, out int piIcon); + /// Sets the location (path and index) of the icon for a Shell link object + void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + /// Sets the relative path to the Shell link object + void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); + + /// Attempts to find the target of a Shell link, even if it has been moved or renamed + void Resolve(IntPtr hwnd, int fFlags); + + /// Sets the path and file name of a Shell link object + void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + + } + + [GuidAttribute("00021401-0000-0000-C000-000000000046")] + [ClassInterfaceAttribute(ClassInterfaceType.None)] + [ComImportAttribute()] + public class CShellLink { + + } + +} diff --git a/src/PostInstaller/IUnknown.cs b/src/PostInstaller/IUnknown.cs new file mode 100644 index 0000000..cb2b03c --- /dev/null +++ b/src/PostInstaller/IUnknown.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace PostInstaller { + [ComImport] + //[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("00000000-0000-0000-C000-000000000046")] + public interface IUnknown { + + IntPtr QueryInterface(ref Guid riid); + + [PreserveSig] + ulong AddRef(); + + [PreserveSig] + ulong Release(); + + } +} diff --git a/src/PostInstaller/PostInstaller.csproj b/src/PostInstaller/PostInstaller.csproj new file mode 100644 index 0000000..6edc8af --- /dev/null +++ b/src/PostInstaller/PostInstaller.csproj @@ -0,0 +1,72 @@ + + + + + Debug + AnyCPU + {05F8E270-8B47-449B-8755-4599B3B3A565} + Exe + Properties + PostInstaller + PostInstaller + v4.7 + 512 + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + PostInstaller.Program + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/PostInstaller/Program.cs b/src/PostInstaller/Program.cs new file mode 100644 index 0000000..294e2cc --- /dev/null +++ b/src/PostInstaller/Program.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace PostInstaller { + class Program { + static int Main(string[] args) { +#if DEBUG + foreach(var a in args) { + Console.Write(a); + Console.Write(" "); + } + Console.WriteLine(); +#endif + + var success = Run(args); + +#if DEBUG + Console.Read(); +#endif + + return success ? 0 : 1; + } + + private static bool Run(string[] args) { +#if DEBUG + Console.WriteLine("Attempting to create IShellItem for file {0}...", args[0]); +#endif + IShellLink link = (IShellLink)new CShellLink(); + + //Win32Shell.SHCreateItemFromParsingName(args[0], IntPtr.Zero, Win32Shell.IShellLinkId, out link); + IPersistFile persistFileLink = (IPersistFile)link; + if (persistFileLink.Load(args[0], 0x00000002L) != 0) { + Console.WriteLine("Failed to load via IPersistFile."); + return false; + } + + link.Resolve(IntPtr.Zero, 0); + +#if DEBUG + Console.WriteLine("Querying for IPropertyStore interface..."); +#endif + IPropertyStore propStore = (IPropertyStore)link; + + try { +#if DEBUG + Console.WriteLine("Attempting to set property 'System.AppUserModel.ID' to {0}...", args[1]); +#endif + + PropertyKey appUserModelKey = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5); + propStore.SetValue(ref appUserModelKey, new BStrWrapper(args[1])); + propStore.Commit(); + + //Store + ((IPersistFile)link).Save(args[0], false); + } + catch (Exception ex) { + Console.WriteLine("Unable to set value of AppUserModel.ID property."); + Console.WriteLine(ex); + + return false; + } + + return true; + } + } +} diff --git a/src/PostInstaller/Properties/AssemblyInfo.cs b/src/PostInstaller/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2f734b9 --- /dev/null +++ b/src/PostInstaller/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PostInstaller")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PostInstaller")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ef62555b-7bd2-40aa-8704-874f8ce12268")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/PostInstaller/PropertyKey.cs b/src/PostInstaller/PropertyKey.cs new file mode 100644 index 0000000..d9b75b9 --- /dev/null +++ b/src/PostInstaller/PropertyKey.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace PostInstaller { + [StructLayout(LayoutKind.Sequential)] + public struct PropertyKey { + + public PropertyKey(Guid formatId, uint propertyId) { + fmtid = formatId; + pid = propertyId; + } + + public Guid fmtid; + public uint pid; + + } +} diff --git a/src/PostInstaller/Win32Shell.cs b/src/PostInstaller/Win32Shell.cs new file mode 100644 index 0000000..824d1b9 --- /dev/null +++ b/src/PostInstaller/Win32Shell.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace PostInstaller { + public static class Win32Shell { + + public readonly static Guid IShellItemId = new Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"); + + public readonly static Guid IShellLinkId = new Guid("000214F9-0000-0000-C000-000000000046"); + + public readonly static Guid IUnknownId = new Guid("00000000-0000-0000-C000-000000000046"); + + public readonly static Guid IPropertyStoreId = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"); + + [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + public static extern void SHCreateItemFromParsingName( + [In][MarshalAs(UnmanagedType.LPWStr)] string pszPath, + [In] IntPtr pbc, + [In][MarshalAs(UnmanagedType.LPStruct)] Guid iIdIShellItem, + [Out][MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellLink iShellItem + ); + + } +}