0

カスタム ドキュメントを開くことができるアプリケーションを作成しています。(レジストリを使用して) ドキュメント拡張機能をアプリケーションに接続しましたが、ドキュメントを開くと、常にアプリケーションの新しいインスタンスで開かれます。

現在のプロセスを実行しているドキュメントが存在する場合、そのドキュメントを開くことができるロジックが必要です。単一のインスタンスを意味するわけではありません。複数のインスタンスで実行できる必要があります。IE や chrome のように、プロセスの実行中にタブで HTML ファイルを開くことができるはずですが、新しいインスタンスを実行することもできます。

どうすればいいですか?

4

2 に答える 2

3

この記事には良い説明が含まれています(そこから取られた画像も)。

このアプローチでは、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;
        }
    }
}
于 2012-10-02T13:51:30.757 に答える
2

ここには多くのオプションがあり、そのうちのいくつかは次のとおりです。

  1. 古い歴史を持つ DDE を使用してみますが、MS Office などの多くのアプリケーションでまだ使用されています。DDE コマンドは、ファイル拡張子の open コマンドに登録されます (HKEY_CLASSES_ROOT\Excel.Sheet.8\shell\Open例を見てください)。アプリケーションがまだ起動していない場合は、OS によって起動され、DDE コマンドが送信されます。起動すると、DDE サーバーとして登録されている実行中のインスタンスに DDE コマンドが送信されます。

  2. プロセスが開始したら、定義済みの名前で IpcChannel を作成してみてください。プロセスがファイル引数で起動される場合、IpcChannel を介して実行中のプロセスにファイル名を渡します。問題は、1 つのプロセスだけが同じ名前で IpcChannel を作成できることです。そのプロセスが終了すると、他のプロセスはチャネルが開かれずに残されます。

  3. すべてのプロセスは、プロセス ID を使用して IpcChannel を作成します。プロセスがファイル引数で開始する場合、プロセスのパスが自分のものと同じであるプロセスを列挙し、IpcChannel (名前はプロセス ID を調べることで取得できます) を使用してそのプロセスに接続し、ファイル名をそれに渡します。

  4. プロセスのパスがあなたのものと同じであるプロセスを列挙し、ファイル名を含む WM_COPYDATA メッセージを送信します。

于 2012-09-27T09:06:00.417 に答える