2012-04-22 9 views
2

私はかなり複雑なプログラミング上の問題がありますので、数分間お待ちください。同じプログラムの複数のインスタンスを同期させる

私はWPF(C#)でメディアプレーヤーを作成したいと思っています。

アプリケーションをシングルインスタンスにしたいので、ユーザーがサーバーファイルをダブルクリックすると、プログラムは1回だけ実行され、再生するためにすべてのファイルがキューに入れられます。

マイクロソフトの単一インスタンスの実装を含むいくつかの方法を試してみましたが、私は自分のを作成し、実装しました(これはおそらくインターネット上にあったどこかでも、それは表示されませんでした)

基本的に、私は複数のインスタンスが開かれないように、そして他のインスタンスがファイルに引数を書き込むことを強制するために、ミューテックスを作成したインスタンスはファイルを読み込みます。 言うまでもありませんが、これはパフォーマンスが向上する限り非常に効果がありますが、とにかくMain()関数の実装がここにあります。 このMain()は、VS2010によって自動的に生成されたものが本当に好きではないので、最初から書き込まれていることに注意してください。私はまた、各ダブルクリックファイル、メイン(の1つのインスタンス)のために、基本的には、スレッド今

public class handler 
{ 
    static string path = @"D:\playlist.txt"; 
    static FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); 
    string line; 

    string arg; 
    bool readerFlag = false; 
    public string ReadArgs() 
    { 
     try 
     { 
      lock (fs) // Enter synchronization block 
      { 
       if (!readerFlag) 
       {   // Wait until writer finishes 
        try 
        { 
         // Waits for the Monitor.Pulse in WriteArg 
         Monitor.Wait(fs); 
        } 
        catch (SynchronizationLockException) 
        { 

        } 
        catch (ThreadInterruptedException) 
        { 

        } 
       } 


       TextReader tr = new StreamReader(fs); 
       while ((line = tr.ReadLine()) != null) 
       { 
        arg = line; 
       } 
       tr.Close(); 
       tr.Dispose(); 

      } 

      /* fs.Close(); 
      fs.Dispose();*/ 
      readerFlag = false; 
      Monitor.Pulse(fs); 
      return arg; 
     } 
     catch (IOException e) 
     { 
      MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source); 
      exp.Show(); 
      return null; 
     } 
    } 
    public void WriteArg(object args) 
    { 
     lock (fs) 
     { 
      try 
      { 
       if (readerFlag) 
       { 
        try 
        { 
         Monitor.Wait(fs); // Wait for the Monitor.Pulse in ReadArgs 
        } 
        catch (SynchronizationLockException) 
        { 

        } 
        catch (ThreadInterruptedException) 
        { 

        } 
       } 
       arg = Convert.ToString(args); 
       // FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read);     
       TextWriter tw = new StreamWriter(fs); 
       tw.WriteLine(args); 
       tw.Close(); 
       tw.Dispose(); 


      } 
      catch (IOException e) 
      { 
       MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source); 
       exp.Show(); 
      } 
     } 
     /* fs.Close(); 
     fs.Dispose();*/ 
     readerFlag = true; 
     Monitor.Pulse(fs); 
    } 

}

間で同期しようとするために、このクラスを使用してい

static void Main(string[] args) 
    { 

      string[] arguments = new string[0]; 
      handler g = new handler(); 
      bool createdNew = false; 
      Mutex lolpaca = new Mutex(true, "lolpacamaximumtrolololololol", out createdNew); 
      if (createdNew) 
      { 

       if (args != null) 
       { 
        var MainWindow = new MainWindow(); 
        var app = new Application(); 
        app.Run(MainWindow); 
        lolpaca.ReleaseMutex(); 
        lolpaca.Dispose(); 
       } 
       else 
       { 
          Array.Resize(ref arguments, 1); 
          arguments[0] = args[0]; 
          string line; 
        //nu mai arunca exceptii nenorocitule 

          while ((line = g.ReadArgs()) != null) 
          { 
           int old_size = arguments.Length; 
           Array.Resize(ref arguments, arguments.Length + 1); 
           arguments[old_size] = line; 
          } 


        var MainWindow = new MainWindow(arguments, arguments.Length); 
        var app = new Application(); 
        app.Run(MainWindow); 
        lolpaca.ReleaseMutex(); 
        lolpaca.Dispose(); 

       } 
       if (File.Exists(path)) 
       { 
        File.Delete(path); 
       } 
      } 

      else 
      { 
       Thread writer = new Thread(new ParameterizedThreadStart(g.WriteArg)); 
       writer.Start(args); 
       writer.Join(); 

       try 
       { 
        g.WriteArg(args); 
       } 
       catch (IOException e) 
       { 
        MediaPlayerFinal_GUI_new.ExceptionCatcher exp = new MediaPlayerFinal_GUI_new.ExceptionCatcher(e.Source); 
        exp.Show(); 
       } 

      } 

    } 

関数はWindowsによって作成されます。 最初のインスタンスは、ミューテックスを制御し、何をしたいかを実行します。 他のインスタンスは引数をファイルに書き込む必要があります。

問題: 明らかにスレッド(すべてのスレッド)が正しく同期せず、IO例外が発生することがあります。 try-catchブロックがまったく何もしないように見えるので、これらの例外がどこにスローされるのかわかりません。実際、これはtry-catchが動作するよりも少し深いと思う。

だから、ユーザーがたくさんのファイルをダブルクリックしたときに発生するすべてのスレッドをどのように同期させるのですか?この実装は、最大3つのファイル(9つまでテスト済み)で最大3つのダブルクリックされたファイルで動作し、場合によっては動作する(時には動作しますが、動作しない場合もあります)。 インターネット上でこれまでに見つかったことは、同じアプリケーションのいくつかのインスタンスが独立して実行されていることです。

あなたは私の例を与えることができればそれは素晴らしいことだ:)

ありがとうございました。

+0

プロセス間通信にファイルを使用しないでください。 filespecをWM_COPYDATAメッセージ内のすでに実行中のインスタンスに送信し、パイプを使用し、TCPを使用します。ディスクファイル以外のほとんどすべてを使用します。 –

+0

そして、私はWPFの勝利メッセージとどのくらい正確に対話しますか?私が知っている限り、WPFはあなたがそれをやるのを防ぐのが最善です。 –

+0

気にしないでください:P –

答えて

0

同じアプリケーションの2つのインスタンスを話す最善の方法は、IPCを使用することです。ベロー単一のインスタンスを支援するために使用することができ、クラスの例を参照してください。

/// <summary> 
     /// Enforces single instance for an application. 
     /// </summary> 
     public class SingleInstance : IDisposable 
     { 
      #region Fields 

      /// <summary> 
      /// The synchronization context. 
      /// </summary> 
      private readonly SynchronizationContext synchronizationContext; 

      /// <summary> 
      /// The disposed. 
      /// </summary> 
      private bool disposed; 

      /// <summary> 
      /// The identifier. 
      /// </summary> 
      private Guid identifier = Guid.Empty; 

      /// <summary> 
      /// The mutex. 
      /// </summary> 
      private Mutex mutex; 

      #endregion 

      #region Constructors and Destructors 

      /// <summary> 
      /// Initializes a new instance of the <see cref="SingleInstance"/> class. 
      /// </summary> 
      /// <param name="identifier"> 
      /// An identifier unique to this application. 
      /// </param> 
      /// <param name="args"> 
      /// The command line arguments. 
      /// </param> 
      public SingleInstance(Guid identifier, IEnumerable<string> args) 
      { 
       this.identifier = identifier; 

       bool ownsMutex; 
       this.mutex = new Mutex(true, identifier.ToString(), out ownsMutex); 

       this.synchronizationContext = SynchronizationContext.Current; 

       this.FirstInstance = ownsMutex; 

       if (this.FirstInstance) 
       { 
        this.ListenAsync(); 
       } 
       else 
       { 
        this.NotifyFirstInstance(args); 
       } 
      } 

      /// <summary> 
      /// Initializes a new instance of the <see cref="SingleInstance"/> class. 
      /// </summary> 
      /// <param name="identifier"> 
      /// An identifier unique to this application. 
      /// </param> 
      public SingleInstance(Guid identifier) 
       : this(identifier, null) 
      { 
      } 

      #endregion 

      #region Public Events 

      /// <summary> 
      /// Event raised when arguments are received from successive instances. 
      /// </summary> 
      public event EventHandler<OtherInstanceCreatedEventArgs> OtherInstanceCreated; 

      #endregion 

      #region Public Properties 

      /// <summary> 
      /// Gets a value indicating whether this is the first instance of this application. 
      /// </summary> 
      public bool FirstInstance { get; private set; } 

      #endregion 

      #region Implemented Interfaces 

      #region IDisposable 

      /// <summary> 
      /// The dispose. 
      /// </summary> 
      public void Dispose() 
      { 
       this.Dispose(true); 
       GC.SuppressFinalize(this); 
      } 

      #endregion 

      #endregion 

      #region Methods 

      /// <summary> 
      /// Clean up any resources being used. 
      /// </summary> 
      /// <param name="disposing"> 
      /// True if managed resources should be disposed; otherwise, false. 
      /// </param> 
      protected virtual void Dispose(bool disposing) 
      { 
       if (this.disposed) 
       { 
        return; 
       } 

       if (disposing) 
       { 
        if (this.mutex != null && this.FirstInstance) 
        { 
         this.mutex.WaitOne(); 
         this.mutex.ReleaseMutex(); 
         this.mutex = null; 
        } 
       } 

       this.disposed = true; 
      } 

      /// <summary> 
      /// Fires the OtherInstanceCreated event. 
      /// </summary> 
      /// <param name="arguments"> 
      /// The arguments to pass with the <see cref="OtherInstanceCreatedEventArgs"/> class. 
      /// </param> 
      protected virtual void OnOtherInstanceCreated(OtherInstanceCreatedEventArgs arguments) 
      { 
       EventHandler<OtherInstanceCreatedEventArgs> handler = this.OtherInstanceCreated; 

       if (handler != null) 
       { 
        handler(this, arguments); 
       } 
      } 

      /// <summary> 
      /// Listens for arguments on a named pipe. 
      /// </summary> 
      private void Listen() 
      { 
       try 
       { 
        using (var server = new NamedPipeServerStream(this.identifier.ToString())) 
        { 
         using (var reader = new StreamReader(server)) 
         { 
          server.WaitForConnection(); 
          var arguments = new List<string>(); 

          while (server.IsConnected) 
          { 
           arguments.Add(reader.ReadLine()); 
          } 

          this.synchronizationContext.Post(o => this.OnOtherInstanceCreated(new OtherInstanceCreatedEventArgs(arguments)), null);       
         } 
        } 

        // start listening again. 
        this.Listen(); 
       } 
       catch (IOException) 
       { 
        // Pipe was broken, listen again. 
        this.Listen(); 
       }   
      } 

      /// <summary> 
      /// Listens for arguments being passed from successive instances of the applicaiton. 
      /// </summary> 
      private void ListenAsync() 
      { 
       Task.Factory.StartNew(this.Listen, TaskCreationOptions.LongRunning); 
      } 

      /// <summary> 
      /// Passes the given arguments to the first running instance of the application. 
      /// </summary> 
      /// <param name="arguments"> 
      /// The arguments to pass. 
      /// </param> 
      private void NotifyFirstInstance(IEnumerable<string> arguments) 
      { 
       try 
       { 
        using (var client = new NamedPipeClientStream(this.identifier.ToString())) 
        { 
         using (var writer = new StreamWriter(client)) 
         { 
          client.Connect(200); 

          if (arguments != null) 
          { 
           foreach (string argument in arguments) 
           { 
            writer.WriteLine(argument); 
           } 
          } 
         } 
        } 
       } 
       catch (TimeoutException) 
       { 
        // Couldn't connect to server 
       } 
       catch (IOException) 
       { 
        // Pipe was broken 
       } 
      } 



#endregion 
    } 

/// <summary> 
/// Holds a list of arguments given to an application at startup. 
/// </summary> 
public class OtherInstanceCreatedEventArgs : EventArgs 
{ 
    #region Constructors and Destructors 

    /// <summary> 
    /// Initializes a new instance of the <see cref="OtherInstanceCreatedEventArgs"/> class. 
    /// </summary> 
    /// <param name="args"> 
    /// The command line arguments. 
    /// </param> 
    public OtherInstanceCreatedEventArgs(IEnumerable<string> args) 
    { 
     this.Args = args; 
    } 

    #endregion 

    #region Public Properties 

    /// <summary> 
    /// Gets the startup arguments. 
    /// </summary> 
    public IEnumerable<string> Args { get; private set; } 

    #endregion 
} 

は、その後、あなたのメインクラスであなたがaplicationが実行されてまで滞在するクラスのインスタンスを作成することができます。 FirstInstanceプロパティで他のインスタンスが作成されているかどうかを確認し、OtherInstanceCreatedイベントによって作成された他のインスタンスを通知します。

+0

あなたの例をありがとう。これとWMを試してみます:P –

+0

(上記のSingleInstance実装を使用して)どこかでArgumentExceptionを取得し続けます。 –

関連する問題