在我当前运行的程序实例中打开文件?

时间:2014-11-14 21:14:13

标签: c# instance double-click file-association

一个例子:

如果您打开并运行Visual Studio(2010),然后双击PC桌面上的misc * .cs文件,该文件将在当前运行的Visual Studio实例中打开,而不是打开VS的另一个实例

如何让我自己的C#程序模仿这种行为?

换句话说,如果我的文件类型如* .myfile与我的程序相关联,并且用户在Windows资源管理器中双击* .myfile,并且.... 我的程序已在运行 .....它应该在没有Windows启动程序的另一个实例的情况下打开文件。如果程序没有运行,那么Windows可以正常启动实例。

请注意,我的程序的多个实例是允许的 - 与Visual Studio相同。

任何建议都将不胜感激!!

3 个答案:

答案 0 :(得分:3)

如果您查看注册表中注册的.cs文件的内容,您将看到它不是Visual Studio。对于Express版本,例如注册的应用程序是'VCSExpress.exe',工作室正在'WDExpress.exe'中运行。在高级版本中,我认为该工作室以'devenv.exe'运行。有趣的是,有两个应用程序:您的UI应用程序和一种启动器应用程序。我不知道VS是怎么做到的,但我可以想象这样:启动器通过任何类型的进程间通信与UI进行通信,例如:命名管道。 (See here)也许试试这个:

  • Launcher应用程序(您的文件扩展名已注册)尝试打开到UI应用程序的管道作为客户端。
  • 如果失败,则启动UI应用程序的新实例并将文件名作为参数传递。 UI应用程序启动命名管道的服务器端
  • 如果管道已成功打开,即已经运行了UI实例,则启动器会通过管道将文件名发送到现有UI进程。
  • Launcher在将作业传递给UI
  • 后退出

答案 1 :(得分:0)

自从我做这样的事情已经差不多20年了,但是IIRC,你做了这样的事情:

  1. 在其他任何事情之前,创建一个Mailslot(或任何其他方便的IPC工具)
  2. 如果要求您打开应该转到现有实例的类型的文档,如果没有其他Mailslots,则继续
  3. 如果有一个邮件槽,你会发送一个带有文件信息的开放邮件,然后你退出。
  4. 编写代码以响应Mailslot打开的消息。
  5. 如果在创建窗口之前执行这些步骤,它应该像您想要的那样。

答案 2 :(得分:0)

我使用windows-messaging制作了一些实现这些东西的项目模板。 模板很大,包含一些其他内容(如本地化,更新,formclosing,剪贴板和文档界面,这样MDI中的操作可以很容易地转发给MDI子项)。 如果您想查看模板,请尝试this link(或this link

部分代码:

Win32.cs:

public partial class Win32
{
    //public const int WM_CLOSE = 16;
    //public const int BN_CLICKED = 245;
    public const int WM_COPYDATA = 0x004A;

    public struct CopyDataStruct : IDisposable
    {
        public IntPtr dwData;
        public int cbData;
        public IntPtr lpData;

        public void Dispose()
        {
            if (this.lpData != IntPtr.Zero)
            {
                LocalFree(this.lpData);
                this.lpData = IntPtr.Zero;
            }
        }
    }

    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr LocalAlloc(int flag, int size);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr LocalFree(IntPtr p);

}

的Program.cs:

static class Program
{
    static Mutex mutex = new Mutex(true, guid());
    static string guid()
    {
        // http://stackoverflow.com/questions/502303/how-do-i-programmatically-get-the-guid-of-an-application-in-net2-0
        Assembly assembly = Assembly.GetExecutingAssembly();
        var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
        return attribute.Value;
    }

    static int MainWindowHandle
    {
        get
        {
            return Settings.Default.hwnd;
        }
        set
        {
            Settings sett = Settings.Default;
            sett.hwnd = value;
            sett.Save();
        }
    }
    public static string GetFileName()
    {
        ActivationArguments a = AppDomain.CurrentDomain.SetupInformation.ActivationArguments;
        // aangeklikt bestand achterhalen
        string[] args = a == null ? null : a.ActivationData;
        return args == null ? "" : args[0];
    }

    [STAThread]
    static void Main()
    {
        if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            #region standaard
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            #endregion
            #region Culture instellen
            string cult = CultureInfo.CurrentCulture.Name;
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(cult);
            Thread.CurrentThread.CurrentCulture = new CultureInfo(cult);
            #endregion
            MainForm frm = new MainForm();
            MainWindowHandle = (int)frm.Handle;
            Application.Run(frm);
            MainWindowHandle = 0;
            mutex.ReleaseMutex();
        }
        else
        {
            int hwnd = 0;
            while (hwnd == 0)
            {
                Thread.Sleep(600);
                hwnd = MainWindowHandle;
            }
            if (hwnd != 0)
            {
                Win32.CopyDataStruct cds = new Win32.CopyDataStruct();
                try
                {
                    string data = GetFileName();
                    cds.cbData = (data.Length + 1) * 2; // number of bytes
                    cds.lpData = Win32.LocalAlloc(0x40, cds.cbData); // known local-pointer in RAM
                    Marshal.Copy(data.ToCharArray(), 0, cds.lpData, data.Length); // Copy data to preserved local-pointer
                    cds.dwData = (IntPtr)1;
                    Win32.SendMessage((IntPtr)hwnd, Win32.WM_COPYDATA, IntPtr.Zero, ref cds);
                }
                finally
                {
                    cds.Dispose();
                }
            }
        }
    }
}

MainFrom.cs:

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case Win32.WM_COPYDATA:
            Win32.CopyDataStruct st = (Win32.CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(Win32.CopyDataStruct));
            string strData = Marshal.PtrToStringUni(st.lpData);
            OpenFile(strData);
            Activate();
            break;
        default:
            // let the base class deal with it
            base.WndProc(ref m);
            break;
    }
}

一次最多可以启动15个文件,它甚至可以使用。