Search code examples
c#shellwindows-explorer

Windows Shell Integration with multiple files


I'm making a program that is using Windows Shell Integration, and the registry changes I do are these: For example, for .txt, I see that the value for HKEY_CLASSES_ROOT\.txt > (Default) is txtfile. I add to HKEY_CLASSES_ROOT\txtfile\shell the key myprogram > (Default) with the value Open with MYPROGRAM. to myprogram I add command > (Default) with the value *path-to-my-program* %1. Now when I right click a .txt file there is an option to open it with my program.

But when I do that with multiple .txt files Windows opens my program many times with each time another file as argument. But I want to open my program one time with all the files as many arguments. Is there an option to do that with changing stuff in registry?

If not, I also could not find a way to make a program that can be opened multiple times and combine all of them to one, so I can also do it that way if someone can help me with it. I'm making this program with C#, by the way.


Solution

  • You have to make your application "Single Instance". Something like this should do the trick: (untested code, just for reference)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Threading;
    
    namespace YourApp
    {
        class Program
        {
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool SetForegroundWindow(IntPtr hWnd);
    
            [STAThread]
            static void Main()
            {
                bool createdNew = true;
                using (Mutex mutex = new Mutex(true, "MyApplicationName", out createdNew))
                {
                    if (createdNew)
                    {
                        Application.EnableVisualStyles();
                        Application.SetCompatibleTextRenderingDefault(false);
                        Form1 frm = new Form1();
                        frm.SetNewData("send command line here");
                        Application.Run(frm);
                    }
                    else
                    {
                        Process current = Process.GetCurrentProcess();
                        foreach (Process process in Process.GetProcessesByName(current.ProcessName))
                        {
                            if (process.Id != current.Id)
                            {
                                SetForegroundWindow(process.MainWindowHandle);
                                // send message to that form or use .Net remoting
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    

    For a better example see this CodeProject solution.