C'è qualche volta sorto il dubbio o il problema di poter aprire più file anche mentre il programma è avviato

tramite argomenti.

Questa cosa potrebbe risultare difficile da fare o quasi impossibile, perché di default non è possibile eseguire questa operazione.

Poniamo il caso di utilizzare Photoshop.

Cosa succede se mentre il programma è aperto andiamo a fare doppio click su file psd?

Mentre il programma resta aperto, si apre un nuovo documento ma tenendo aperti quelli già esistenti.

Questo metodo è definito Single Istance.  Ossia un programma che viene aperto una sola volta, non può essere aperto nuovamente.

il .NET ci offre la possibilità di utilizzare il Mutex per controllare ciò.

Se noi associamo una certa estensione al nostro programma esempio:  miofile.pir

Definito nel registro di sistema il comando open %1 passera come argomento al nostro programma il percorso relativo del file che si sta tentando di aprire come argomento.

Andiamo prima a verificare se il programma è già aperto.

Dichiariamo un Mutex con il GUID della nostra applicazine. Possiamo trovare il nostro GUID in Progetto->Properties->AssemblyInfo.cs

Troviamo una riga del genere

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("68257d64-da7e-46cf-98f3-fdd4a143533a")]

al file Program.cs

Prima del void Main.

Dichiariamo il Mutex con il nostro GUID

Ma prima cos'è un Mutex?

Un mutex "mutua esclusione" 

Un mutex è in grado di sincronizzarsi fra processi e thread. Con il quale impedisce più task paralleli che accedono contemporaneamente ai dati in memoria di altre risorse. Questo concetto riveste un importanza fondamentale nella programmazione parallela e soprattutto per i sistemi di transazione.

static Mutex mutex = new Mutex(true, "{68257d64-da7e-46cf-98f3-fdd4a143533a}");
       

        [STAThread]
        static void Main(string[] args)
        {
             Application.EnableVisualStyles();
                               Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());

         }

Successivamente 

 if (mutex.WaitOne(TimeSpan.Zero, true))
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
                mutex.ReleaseMutex();
            }
            else
            {
               MessageBox.Show("Un'altra istanza a questa applicazione è gia avviata");
}

noteremo che se proviamo ad aprire il programma manualmente più di una volta ci mostrerà quel messaggio.

Un modo molto semplice, chiamiamolo in un termine molto grezzo "barbatruccho" per aprire più file tramite argomenti sullo stesso programma e quello di rendere il nostro programma come un server TCP ma allo stesso tempo, un Client.

A questo punto, potremmo fare un qualcosa di molto generico.

static Mutex mutex = new Mutex(true, "{68257d64-da7e-46cf-98f3-fdd4a143533a}");
       

        [STAThread]
        static void Main(string[] args)
        {
            if (mutex.WaitOne(TimeSpan.Zero, true))
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
                mutex.ReleaseMutex();
            }
            else
            {

                try
                {

                    GC.Collect();
                    Form1 f = new Form1();
                    f.multiple_instace = true;


                    using (TcpClient client = new TcpClient())
                    {
                        client.Connect(IPAddress.Parse("127.0.0.1"), 4000);
                        ASCIIEncoding encoder = new ASCIIEncoding();

                        using (NetworkStream netStream = client.GetStream())
                        {
                            // Invio un messeggio allo stesso programma
                           //contente come stringa, args[0] ovvero il file
                           //che si sta tentando di aprire tramite argomenti

                            byte[] sendBuffer = encoder.GetBytes(args[0]);
                            netStream.Write(sendBuffer, 0, sendBuffer.Length);
                            netStream.Flush();

  
                        }
                    }

                }
                catch
                {
                    MessageBox.Show("Un'altra istanza di questo programma è già aperta");
                    Application.Exit();
                }

                          
   
            }

Recapitolando il procedimento,

Abbiamo creato un mutex che và a controllare se il programma è già aperto. Nel caso il programma è già aperto ma si e fatto doppio click su un file con estensione *.pir Istanziamo un TCPClient locale che invii un messaggio contenente args[0] che potrebbe contenere "C:miofile.pir"

Nel Form1 abbiamo bisogno di dichiarare alcune varibili di tipo volatile. Se non sapete cosa sia una variabile volatile vi invito a leggere questa guida 

Dichiariamo queste variabili

private Thread m_thread;
private volatile bool server_stop;
public volatile bool multiple_instace = false;
public volatile string file;

Naturalmente nel Form1 dobbiamo avere un server in ascolto che lo andiamo a definire nel nuovo thread questo per evitare di frizzare il nostro programma e farlo continuare nella sua esecuzione

Dalle variabili si può gia capire cosa succede.

Durante l'ascolto del server nel nuovo thread, ricevuto il testo contenente args[0] andiamo a caricare il file direttamente dal thread alla variabile file

ASCIIEncoding encoder = new ASCIIEncoding();
string text = encoder.GetString(buffer, 0, readCount);

StreamReader sr = new StreamReader(text);
file = sr.ReadToEnd();

if (InvokeRequired)
            {
                
 
                MethodInvoker method = new MethodInvoker(Carica);
                Invoke(method);

            }



public void Carica()
{

  RichTextBox rb = new RichTextBox();
 rb.Text = file;
 this.Controls.Add(rb);

}

In questo modo ci ritroviamo un nuovo componente RichTextBox aggiunto nel forum contenenete il testo del file che abbiamo aperto da esplora risorse con il doppio click.

Questo sistema è stato utilizzando in un mio progetto per caricare alcuni elementi direttamente nell'editor. Una volta invocato il methodo, esso funziona normalmente come un qualsiasi void non più rilegato al thread parallelo. Perché il contenuto del file viene instanziato in una variabile volatile che può essere Cross-Thread evitando appunto l'errore del cross-thread violation.

Attenzione!

Nel caso provassimo a passare l'argomento ricevuto in una variabile del form quando viene istanziato il Mutex Nel Main, del tipo:

Anziché fare:

Application.Run(new Form1());

Facessimo

Form1 f = new Form1();
f.valore = args[0];
Application.Run(f);

Mentre il Mutex è in esecuzione potremmo riscontrare diversi problemi con gli antivirus. Nella mia esperienza, mi è capitato di avere problemi con con Avanst. Dal momento che il processo comunica con un'altro processo tentando di passargli degli argomenti entra in azione l'antivirus crededo che il nostro exe sia un applicazione malevole.