【问题标题】:open file with a running process使用正在运行的进程打开文件
【发布时间】:2012-10-04 04:54:55
【问题描述】:

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

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

我该怎么做?

【问题讨论】:

  • 是的,mutex 可以解决它。这里也有类似的问题:stackoverflow.com/questions/19147/…
  • 我不要单实例,应该可以多实例运行
  • 所以上面提到的例子将帮助您识别另一个实例是否正在运行,接下来要做什么由您决定。
  • 你的问题的问题是你没有表明任何先前的研究。我想你可以通过添加你迄今为止尝试过的东西并询问具体问题来改进它。否则,它将继续被 "gimme teh codez" 否决。

标签: c#


【解决方案1】:

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

该方法使用ThreadPool 对象和EventWaitHandle 对象在进程之间传递消息(对象)(.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;
        }
    }
}

【讨论】:

  • 您是否考虑添加一些解释,以便未来的读者可以知道这段代码的作用,以及它如何回答所提出的问题?
【解决方案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 消息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-28
    相关资源
    最近更新 更多