Reputation: 99
I'm creating a C# WPF program with custom windows context menu items on any file.
But when any .lnk file(shortcuts) are selected and right clicked to be opened with my program through the context menu items, it opens my WPF window in the taskbar with the icon of another program.
.
As seen on this gif when right clicked on discord.lnk file and selected one of my custom context menu items it opens my WPF window page as Discord. The same happens with any other .lnk files.
It was supposed to open as it's own window in the taskbar as seen on this gif. As shown it behaves normally if the file isn't a .lnk.
.
What are the possible solutions for this problem? Is there a way to avoid .lnk files from doing this, and open my program as it's own?
private void Application_Startup(object sender, StartupEventArgs e)
{
Args = e.Args;
TryAssociate();
MainWin main = new MainWin();
main.Show();
}
// FILE ASSOCIATION
public static void TryAssociate() { if (!IsAssociated()) Associate(); }
static bool IsAssociated() { return Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.chi", false) != null; }
public static void Deassociate()
{
try
{
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Classes\.chi");
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Classes\Applications\chi.exe");
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.chi");
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Classes\*\shell\chi_Action1");
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Classes\*\shell\chi_Action2");
SHChangeNotify(0x08000000, 0x0000, IntPtr.Zero, IntPtr.Zero);
}
catch { }
}
public static void Associate()
{
Deassociate();
try
{
RegistryKey FileReg = Registry.CurrentUser.CreateSubKey(@"Software\Classes\.chi", RegistryKeyPermissionCheck.ReadWriteSubTree);
RegistryKey AppReg = Registry.CurrentUser.CreateSubKey(@"Software\Classes\Applications\chi.exe", RegistryKeyPermissionCheck.ReadWriteSubTree);
RegistryKey AppAssoc = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.chi", RegistryKeyPermissionCheck.ReadWriteSubTree);
RegistryKey Encrypt = Registry.CurrentUser.CreateSubKey(@"Software\Classes\*\shell\chi_Action1");
RegistryKey Decrypt = Registry.CurrentUser.CreateSubKey(@"Software\Classes\*\shell\chi_Action2");
Encrypt.SetValue("", "Action1 with Chi");
Encrypt.SetValue("Icon", AppData + "clf_icon.ico");
//Encrypt.SetValue("MultiSelectModel", "Player");
Encrypt.CreateSubKey("command").SetValue("", "\"" + AppPath + "\" \"%1\" " + "/Action1");
Decrypt.SetValue("", "Action2 with Chi");
Decrypt.SetValue("Icon", AppData + "clf_icon.ico");
//Decrypt.SetValue("MultiSelectModel", "Player");
Decrypt.CreateSubKey("command").SetValue("", "\"" + AppPath + "\" \"%1\" " + "/Action2");
FileReg.CreateSubKey("DefaultIcon").SetValue("", AppData + "clf_icon.ico");
FileReg.CreateSubKey("PerceivedType").SetValue("", "Document");
FileReg.CreateSubKey("OpenWithProgids").SetValue(@"Applications\chi.exe", new byte[0], RegistryValueKind.None );
AppReg.CreateSubKey("shell\\open\\command").SetValue("", "\"" + AppPath + "\" \"%1\" " + "/Open");
AppReg.CreateSubKey("DefaultIcon").SetValue("", AppData + "clf_icon.ico");
AppAssoc.CreateSubKey("UserChoice").SetValue("ProgId", @"chi.exe");
}
finally
{
SHChangeNotify(0x08000000, 0x0000, IntPtr.Zero, IntPtr.Zero);
}
}
Upvotes: 0
Views: 461
Reputation: 99
I've been studying and discovering new things in WPF and WinForms. One of them is that for somewhat reason when you create a custom shell command on regedit for any file, when you try to use them on a .lnk files (window shortcut) it can be this messy and buggy. This happens because the shortcut will interpret the action the shell command sent, and open it directly with that shortcut's root file ID and arguments.
The workaround for this should be reading the shortcut as .lnk file and not as a shortcut. (The other answer I gave can achieve almost the same result, but it doesn't fix the .lnk files)
To do this we need to override our custom shell command on the shortcut registry(If you have multiple shell commands, you should override all of them). Here is an exemple:
using System;
using Microsoft.Win32;
using System.Runtime.InteropServices;
[DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern void SHChangeNotify(uint Id, uint Flags, IntPtr Item1, IntPtr Item2);
RegistryKey programLnk = Registry.CurrentUser.CreateSubKey(@"Software\Classes\lnkfile\shell\MyProgram");
programLnk.SetValue("", "Open with MyProgram");
programLnk.SetValue("Icon", AppPath);
programLnk.CreateSubKey("command").SetValue("", "\"" + AppPath + "\" \"%1\"");
SHChangeNotify(0x08000000, 0x0000, IntPtr.Zero, IntPtr.Zero);
// This will notify window of the change made in the registry.
This should fix your program opening as another in taskbar and a give it the expected arguments.
Upvotes: 1
Reputation: 99
After a while, I have discovered a way to change what was happening.
When you start a WPF application it will create a Taskbar Icon with an ID for your app. And for some reason, if you try to to open any other application shortcut(.lnk) as your application it will start an taskbar icon as if it was that shortcut's program.
To change this behavior all you have to do is somehow modify the taskbar icon ID of your WPF window right after you create it. To do this you'll have to download Windows API Code Pack (This can be done inside VisualStudio 2019), and then you can proceed coding.
This is what your WPF will need to change the taskbar icon ID.
using System.Windows.Interop;
using Microsoft.WindowsAPICodePack.Taskbar;
Then when creating a window you should do this:
private void Application_Startup(object sender, StartupEventArgs e)
{
/* Creating a window */
MainWindow main = new MainWindow();
main.Show();
/* Changing the window taskbar id */
TaskbarManager.Instance.SetApplicationIdForSpecificWindow(new WindowInteropHelper(main).Handle, "WindowTaskbarID Here");
/* Showing window in the taskbar */
main.ShowInTaskbar = true;
}
Done! Now your program will open as a new taskbar icon, and you can even have infinite taskbar icons if you change every window ID; (This should work in WinForms too)
Upvotes: 1