打开运行进程的文件

时间:2012-08-17 06:07:43

标签: c#

我正在创建一个可以打开自定义文档的应用程序。我将文档扩展名连接到应用程序(使用注册表),但是当我打开文档时,它总是打开一个新的应用程序实例。

我想要一些可以打开运行当前进程的文档的逻辑(如果存在)。我不是指一个单一的例子。它应该能够由多个实例运行。与IE或Chrome一样,它应该能够在进程运行时打开带有选项卡的HTML文件,但它也可以运行新实例。

我该怎么做?

2 个答案:

答案 0 :(得分:3)

This article包含一个很好的描述(从那里拍摄的图像)。

该方法使用带有EventWaitHandle对象的ThreadPool对象在进程(.Net Remoting)之间传递消息(对象)。
应用程序启动时,它使用CreateSingleInstance()将现有实例 OR 注册为单实例应用程序。

Flow diagram

public static bool CreateSingleInstance( string name, EventHandler<InstanceCallbackEventArgs> callback )
{
    EventWaitHandle eventWaitHandle = null;
    int curSessionId = System.Diagnostics.Process.GetCurrentProcess().SessionId;
    name += curSessionId;

    string eventName = string.Format( "{0}-{1}", Environment.MachineName, name );

    // If there is another instance
    InstanceProxy.IsFirstInstance = false;

    InstanceProxy.CommandLineArgs = Environment.GetCommandLineArgs();

    try
    {
        //try to open a handle with the eventName
        eventWaitHandle = EventWaitHandle.OpenExisting( eventName );
    }
    catch
    {
        InstanceProxy.IsFirstInstance = true;
    }

    if( InstanceProxy.IsFirstInstance )
    {
        eventWaitHandle = new EventWaitHandle( false, EventResetMode.AutoReset, eventName );

        // register wait handle for this instance (process)               
        ThreadPool.RegisterWaitForSingleObject( eventWaitHandle, WaitOrTimerCallback, callback, Timeout.Infinite, false );


        eventWaitHandle.Close();

        // register shared type (used to pass data between processes)          
        RegisterRemoteType( name );
    }
    else
    {
      // here will be the code for the second instance/
    }

    return InstanceProxy.IsFirstInstance;
}
private static void RegisterRemoteType( string uri )
{
    // register remote channel (net-pipes)
    var serverChannel = new IpcServerChannel( Environment.MachineName + uri );
    ChannelServices.RegisterChannel( serverChannel, true );

    // register shared type
    RemotingConfiguration.RegisterWellKnownServiceType(
        typeof( InstanceProxy ), uri, WellKnownObjectMode.Singleton );

    // close channel, on process exit
    Process process = Process.GetCurrentProcess();
    process.Exited += delegate
    {
        ChannelServices.UnregisterChannel( serverChannel );
    };
}
[Serializable]
[System.Security.Permissions.PermissionSet( System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust" )]
internal class InstanceProxy : MarshalByRefObject
{
    private static bool firstInstance;
    private static string[] arrCommandLineArgs;       
    public static bool IsFirstInstance
    {
        get
        {
            return firstInstance;
        }

        set
        {
            firstInstance = value;
        }
    }     
    public static string[] CommandLineArgs
    {
        get
        {
            return arrCommandLineArgs;
        }
        set
        {
            arrCommandLineArgs = value;
        }
    }

    public void SetCommandLineArgs( bool isFirstInstance, string[] commandLineArgs )
    {
        firstInstance = isFirstInstance;
        arrCommandLineArgs = commandLineArgs;
    }
}
public class InstanceCallbackEventArgs : EventArgs
{
    private  bool firstInstance;
    private  string[] arrCommandLineArgs;

    internal InstanceCallbackEventArgs( bool isFirstInstance, string[] commandLineArgs )
    {
        firstInstance = isFirstInstance;
        arrCommandLineArgs = commandLineArgs;
    }

    public bool IsFirstInstance
    {
        get
        {
            return firstInstance;
        }

        set
        {
            firstInstance = value;
        }
    }

    public string[] CommandLineArgs
    {
        get
        {
            return arrCommandLineArgs;
        }
        set
        {
            arrCommandLineArgs = value;
        }
    }
}

答案 1 :(得分:2)

这里有很多选择,其中一些是:

  1. 尝试使用历史悠久的DDE,但它仍然被MS Office等许多应用程序使用。 DDE命令在open命令中注册用于文件扩展名(例如,查看HKEY_CLASSES_ROOT\Excel.Sheet.8\shell\Open)。如果应用程序尚未启动,则由OS启动,并提交DDE命令。如果启动,则将DDE命令提交给正在运行的实例,该实例已注册为DDE服务器。

  2. 当您的流程开始时,尝试使用预定义的名称创建IpcChannel。如果使用file参数启动进程,请通过IpcChannel将文件名传递给正在运行的进程。问题是只有一个进程可以创建具有相同名称的IpcChannel。如果该流程退出,则其他流程没有开放渠道。

  3. 每个进程都使用进程ID创建一个IpcChannel。当您的进程以文件参数开头时,您枚举进程'path与您的路径相同的进程,然后使用IpcChannel连接到该进程(其中name可以通过查看进程ID获得),然后将filename传递给它。

  4. 枚举进程'路径与您的路径相同的进程,并发送包含您的文件名的WM_COPYDATA消息。