Comment obtenir une instance System.Windows.Form à partir de son descripteur Win32?

Le code suivant implémente un singleton simple qui garantit qu’une seule instance de mon application peut être exécutée. Toutefois, si une autre instance est démarrée, je dois pouvoir récupérer les arguments de ligne de commande de cette instance, les transmettre à l’instance initiale, puis mettre fin à la seconde instance.

Le problème se pose lorsque je tente de mettre la main sur la première instance de l’application. Une fois que j’ai trouvé le handle du formulaire principal de cette instance, je le passe à la méthode Control.FromHandle() , dans l’ Control.FromHandle() de récupérer un MainForm . Au lieu de cela, la valeur de retour est toujours null . ( Control.FromChildHandle() donne le même résultat.)

Par conséquent, ma question est simplement: qu’est-ce que je fais mal? Et est-ce même possible dans .NET?

 public class MainForm : Form { [DllImport("user32")] extern static int ShowWindowAsync(IntPtr hWnd, int nCmdShow); [DllImport("user32")] extern static bool SetForegroundWindow(IntPtr hWnd); private Mutex singletonMutex; private void MainForm_Load(object sender, EventArgs e) { bool wasCreated; singletonMutex = new Mutex(false, Application.ProductName + "Mutex", out wasCreated); // returns false for every instance except the first if (!wasCreated) { Process thisProcess = Process.GetCurrentProcess(); Process[] peerProcesses = Process.GetProcessesByName(thisProcess.ProcessName.Replace(".vshost", ssortingng.Empty)); foreach (Process currentProcess in peerProcesses) { if (currentProcess.Handle != thisProcess.Handle) { ShowWindowAsync(currentProcess.MainWindowHandle, 1); // SW_NORMAL SetForegroundWindow(currentProcess.MainWindowHandle); // always returns null !!! MainForm runningForm = (MainForm) Control.FromHandle(currentProcess.MainWindowHandle); if (runningForm != null) { runningForm.Arguments = this.Arguments; runningForm.ProcessArguments(); } break; } } Application.Exit(); return; } } 

Les applications à instance unique sont bien sockets en charge par le framework .NET. Vérifiez ce fil pour un exemple qui fait exactement ce dont vous avez besoin.

Control.FromHandle ne va pas fonctionner car le contrôle que vous recherchez se trouve dans un autre processus (et donc dans un autre domaine d’application).

Vous avez déjà le WindowHandle mais son utilisation est limitée à l’API Win32. Rien de WinForms ne va fonctionner.

Vous pouvez envoyer des messages (WM_) mais il est difficile de faire passer des données.

Les options

  1. utiliser quelque chose de bas niveau avec un fichier temporaire.

  2. utiliser la communication à distance (WCF)

Vous essayez vraiment d’implémenter une application singleton. Il y a quelques exemples sur Internet (désolé, je n’ai pas vraiment essayé moi-même), par exemple

http://www.codeproject.com/KB/cs/SingletonApplication.aspx

http://www.nathanm.com/csharp-wpf-singleton-application/

Essayez ce qui suit

 var form = (Form)(Control.FromHandle(myHandle)); 

MODIFIER

Relisez votre question et réalisez que vous regardez un descripteur dans un autre processus. Il n’y a aucun moyen de convertir un descripteur dans un autre processus en une instance de formulaire dans le processus en cours. Ma solution ne fonctionnera que pour les poignées du même processus.

Le seul moyen d’obtenir une instance de formulaire est d’utiliser la communication à distance. Mais cela nécessitera une coopération de la part des deux processus, ce qui ne semble pas être ce que vous recherchez.

Vous ne pouvez pas appeler le code directement dans un autre processus, vous devez utiliser une forme de communication inter-processus.

Si vous communiquez uniquement entre des processus lancés par le même utilisateur sur le même ordinateur, vous pouvez utiliser les messages de fenêtre (à l’aide de WinAPI PostMessage et de la substitution de WndProc), sinon je pense que la communication à distance est la plus simple à utiliser dans .net

J’utilise la bibliothèque Microsoft.VisualBasic.dll décrite dans le fil que nobugz a pointé. Oui, vous pouvez l’utiliser en C #. Vous venez de remplacer OnStartupNextInstance et de passer la ligne de commande à votre programme de la manière qui vous convient le mieux.

C’est beaucoup plus facile que de jouer avec les discussions manuellement.