0

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

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

我该怎么做?

4

2 回答 2

3

这篇文章包含一个很好的描述(图片也是从那里拍摄的)。

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

流程图

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;
        }
    }
}
于 2012-10-02T13:51:30.757 回答
2

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

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

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

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

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

于 2012-09-27T09:06:00.417 回答