Windows Shell与多个文件集成

时间:2011-06-29 21:40:27

标签: c# shell windows-explorer

我正在制作一个使用Windows Shell Integration的程序,我做的注册表更改是: 例如,对于.txt,我看到HKEY_CLASSES_ROOT\.txt > (Default)的值为txtfile。我向HKEY_CLASSES_ROOT\txtfile\shell添加了值为myprogram > (Default)的密钥Open with MYPROGRAM。到myprogram我添加command > (Default)*path-to-my-program* %1。现在,当我右键单击.txt文件时,可以选择使用我的程序打开它。

但是,当我使用多个.txt文件执行此操作时,Windows会多次打开我的程序,每次另一个文件作为参数。但是我想用所有文件打开我的程序一次。是否可以选择在注册表中更改内容?

如果没有,我也找不到一种方法来制作一个可以多次打开的程序并将它们全部组合成一个,所以如果有人可以帮助我,我也可以这样做。顺便说一下,我用C#编写这个程序。

4 个答案:

答案 0 :(得分:0)

处理此问题的标准方法是使用互斥锁来确保只运行程序的单个实例。然后当shell尝试启动一个新实例来打开每个文件时,新实例只是将消息传递给已经运行的实例并让它打开文件。

答案 1 :(得分:0)

一种可能的选择是检查程序的另一个实例是否已在运行。如果是这样,您将文件路径传递给该实例以打开。对于程序内部通信,您可以使用任何您喜欢的内容,例如:.NET远程处理,命名管道,DDE,自定义窗口消息等。

答案 2 :(得分:0)

这是默认值。你告诉shell,当点击'打开MYPROGRAM'时,为每个被选中的文件调用 application %1。

解决此问题的最简单方法是使应用程序成为单个实例,并在选择其他文件时将消息发送到已运行的实例。这样,启动了一个应用程序实例来打开一个文件,它会收到打开其他每个文件的请求。这是通常使用C ++实现的方式

如果查看Developer Documentation,还建议使用DDE。我不知道DDE在C#中的可访问性如何,并且不推荐使用它。

答案 3 :(得分:0)

您必须使您的应用程序成为“单一实例”。 像这样的东西应该做的伎俩: (未经测试的代码,仅供参考)

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;
                        }
                    }
                }
            }
        }
    }
}

有关更好的示例,请参阅this CodeProject解决方案。