PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C# / .NET]: Anderen Prozess benachrichtigen


Grestorn
2006-12-03, 12:56:10
Ich habe ein Problem, das mit "normalen" Boardmitteln von C++ total einfach zu lösen wäre, bei .NET steh ich aber auf dem Schlauch:

Ich habe mittels Process.GetProcessesByName() ermittelt, dass es bereits eine laufende Instanz der gerade gestarteten Applikation im System gibt.

Ich würde nun gerne dieser Instanz eine Nachricht schicken, damit sie ihr Fenster öffnet und in den Vordergrund bringt. Unter win32 hätte man dem Prozess mit SendMessage() einfach eine entsprechende Nachricht geschickt.

Wie ist das dazugehörige Pendant in .NET? Ich habe dafür in der Doku einfach nichts gefunden...

Unfug
2006-12-03, 15:21:05
müsste ein visible = true nicht reichen?

edit: ich bin grad auch etwas durcheinander, aber auch das Form. kannste bestimmt maximieren.

Grestorn
2006-12-03, 15:22:45
müsste ein visible = true nicht reichen?

Ich will das ja nicht in meinem eigenen Form setzen (denn der eigene Prozess wird ja gleich wieder beendet) sondern ich will die Form des bereits laufenden Prozesses sichtbar machen.

Ich muss also irgendwie eine Nachricht (event, oder was auch immer) im anderen Prozess auslösen.

Zur Erläuterung: Wenn nHancer bereits läuft und der Anwender started es ein zweites Mal, soll nHancer nicht hinterher 2x laufen, sondern einfach das bereits laufende nHancer sichtbar gemacht werden, und das neu gestartete beendet sich sofort.

Unfug
2006-12-03, 15:27:23
ach wenn ich jetzt nur nicht unter linux wär....
aber du könntest doch mittels

Process abc = Process.GetProcess("huhu");
und dann abc......visible=true das bestimmt hinkriegen oder nicht?


ist wie gesagt nur geraten von mir aber c# sollte das aufjedenfall hinkriegen.
edit:grad geooglet irgendwas mit abc.windowStyle ....vllt mal versuchen.

Xmas
2006-12-03, 15:38:27
SendMessage in C# mit DllImport:
http://www.codeproject.com/csharp/wmp_pinvoke.asp

Grestorn
2006-12-03, 16:05:06
SendMessage in C# mit DllImport:
http://www.codeproject.com/csharp/wmp_pinvoke.asp

Ja, eine ähnliche Idee hatte ich auch schon. Aber das ist nur die halbe Miete: Ich kann zwar Standard Windows-Messages senden, aber der empfangende Prozess ist ja ebenfalls eine .NET Applikation (das selbe Programm sogar in dem Fall), und ich habe keine Möglichkeit direkt selbst definierte Windows-Messages zu empfangen, zumindest kenne ich keine.

Ein Standard-Event a la WM_SHOWWINDOW kommt auch nicht in Frage, da es ja gar kein Fenster gibt, auf das das angewendet werden soll... nHancer hat im minimierten Zustand kein Fenster!

Der einzige Weg, der mir machbar erscheint, ist ein Remoting Interface einzubauen, und das anzusprechen. Aber das erscheint mir einfach zu aufwändig und außerdem würde es einen IP-Port belegen, und das muss ja nun nicht sein.

Kabelsalat
2006-12-03, 16:13:44
Such mal nach Subclassing. Hier u.a. ein Artikel: http://www.dotnetpro.de/articles/freearticles/subclassing.aspx

Grestorn
2006-12-03, 16:19:02
Such mal nach Subclassing. Hier u.a. ein Artikel: http://www.dotnetpro.de/articles/freearticles/subclassing.aspx

Das liest sich in der Tat sehr vielversprechend. Danke für den Link!

Gast
2006-12-03, 17:24:03
[STAThread]
public static void Main()
{
Process instance = RunningInstance();

if(instance == null)
{
Application.Run(new StartForm());
}
else
{
HandleRunningInstance(instance);
}
}

public static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);

foreach(Process process in processes)
{
if(process.Id != current.Id)
{
if(Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
{
return process;
}
}
}

return null;
}

public static void HandleRunningInstance(Process instance)
{
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);

SetForegroundWindow(instance.MainWindowHandle);
}

[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

private const int WS_SHOWNORMAL = 1;

Grestorn
2006-12-03, 17:48:17
public static void HandleRunningInstance(Process instance)
{
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);

SetForegroundWindow(instance.MainWindowHandle);
}

[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

private const int WS_SHOWNORMAL = 1;


Das sieht eigentlich sehr gut aus. Mal sehen, ich werd das mal einbauen. Danke erst mal!

Schade nur, dass es offenbar tatsächlich keine Möglichkeit unter .NET gibt, Messages zwischen Prozessen auf einer lokalen Maschine auszutauschen, ohne auf Remoting zurückzugreifen.

Grestorn
2006-12-03, 18:01:36
Wie ich schon vermutet hatte:

Das haut leider nicht hin, da nHancer im minimierter Form kein "MainWindow" hat... Das Form von nHancer ist auf "visible=false", sobald es minimiert wird und das TrayIcon ausgewählt ist.

Es geht nur, wenn das TrayIcon deaktiviert ist (minimize also "normal" funktioniert) oder die laufende Instanz von nHancer nicht minimiert wurde.

Diese Möglichkeit, so elegant sie aussieht, fällt also leider aus.

Gast
2006-12-03, 19:13:22
Na dann musst du eben noch etwas Code einbauen. Ist nicht getestet, aber sollte funktionieren.

private const int SW_RESTORE = 9;

public static void HandleRunningInstance(Process instance)
{
System.IntPtr mainWindowHandle = instance.MainWindowHandle;
if(mainWindowHandle != IntPtr.Zero)
{
ShowWindow(mainWindowHandle,SW_RESTORE);
UpdateWindow(mainWindowHandle);
}
else
{
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
SetForegroundWindow(instance.MainWindowHandle);
}
}

Grestorn
2006-12-03, 19:38:15
Na dann musst du eben noch etwas Code einbauen. Ist nicht getestet, aber sollte funktionieren.


Wie soll Dein Code funktionieren, wenn mainWindoeHandle NULL ist?

Matrix316
2006-12-03, 20:44:52
Vielleicht hilft das hier: http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=6315FF6C-1347-4C9E-913B-81F266CE8DE2

Kabelsalat
2006-12-03, 21:53:37
Das sieht eigentlich sehr gut aus. Mal sehen, ich werd das mal einbauen. Danke erst mal!

Schade nur, dass es offenbar tatsächlich keine Möglichkeit unter .NET gibt, Messages zwischen Prozessen auf einer lokalen Maschine auszutauschen, ohne auf Remoting zurückzugreifen.

Was spricht den gegen Remoting? Ich verwende es zwar nur in Kombination mit verschiedenen AppDomains und nicht über Prozessgrenzen hinweg, dass sollte aber genauso gehen (auch ohne TCP/IP).

Ansonsten stehen dir natürlich immer die Möglichkeiten der WinAPI offen und somit lässt sich alles realisieren, was du auch unter C++ zum Datenaustausch genutzt hast...

Gast
2006-12-03, 22:23:15
Wie soll Dein Code funktionieren, wenn mainWindoeHandle NULL ist?

Hast Recht, da war ich zu voreilig. Ich würde den Code trotzdem verwenden und nur noch erweitern. Das Fenster sollte ja eigentlich noch da sein, nur eben unsichtbar. Du könntest in der HandleRunningInstance Methode abfragen, ob das MainWindow vorhanden ist oder nicht. Wenn nicht, könntest du mittels der EnumWindow API dir das Fenster holen und auf Visible = true setzen. Ich kann dir allerdings zur EnumWindow API auf die Schnelle kein Code posten.

ScottManDeath
2006-12-04, 00:49:05
Ich hab ein ähnliches in meinem Raytracer. Ich will wissen, welche Instanz ich bin, damit ich meinen Ausgabe Dateinamen suffixen kann, damit sie sich die Prozesse gegenseitig nicht die Ergebnisse überschreiben.

Du solltest aber aufpassen, was passiert, wenn ein User, der gerade eingeloggt ist, aber nicht der aktive User ist, nHancer laufen hat, und der andere aktive User einen nHancer aufmacht, und sich dann wundert, dass er gleich wieder verschwindet.

edit: arghh, wurde in ähnlicher Form vom Gast oben schon gepostet. :(


static int Instance()
{

Process[] tmpProcess = Process.GetProcesses();
Process myProcess = Process.GetCurrentProcess();
Int32 cnt = 0;
foreach (Process tmpP in tmpProcess)
{
if (tmpP.ProcessName == myProcess.ProcessName)
{
cnt++;
}
}
return cnt - 1;



}

Gast
2006-12-04, 11:58:01
Dieses Beispiel funktioniert bei mir ohne Probleme:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Instance
{
static class Program
{
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync (IntPtr hWnd, int cmdShow);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow (IntPtr hWnd);
private const int WS_SHOWNORMAL = 1;

static void Main ()
{
Process instance = RunningInstance();
if (instance == null)
{
Application.Run(new Form1());
}
else
{
HandleRunningInstance(instance);
}
}

public static Process RunningInstance ()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);

foreach (Process process in processes)
{
if (process.Id != current.Id)
{
return process;
}
}
return null;
}

public static void HandleRunningInstance (Process instance)
{
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
SetForegroundWindow(instance.MainWindowHandle);
}
}
}

Grestorn
2006-12-04, 12:33:40
Dieses Beispiel funktioniert bei mir ohne Probleme:


Bei mir auch, aber nur dann, wenn die bereits laufende Applikation das Fenster lediglich minimiert hat oder es im Hintergrund liegt.

nHancer setzt aber Visible=false, was dazu führt, dass das Fenster unter Windows komplett entfernt wird und auch keinen Handle mehr hat. Damit geht der obige Code ins leere.

Gast
2006-12-04, 12:53:55
nHancer setzt aber Visible=false, was dazu führt, dass das Fenster unter Windows komplett entfernt wird und auch keinen Handle mehr hat. Damit geht der obige Code ins leere.

Das Fenster ist garantiert noch da, auch wenn der Handle weg ist. Wie gesagt, ich würde es mit der EnumWindows API probieren. Oder - was mir noch auf die Schnelle einfällt - über PInvoke speicherst du das Windows Handle im Shared Memory Bereich. Wenn dann ein neuer Prozess startet und das MainWindows Handler von der Instanz fehlt, liest du das Handle aus dem Shared Memory Bereich und stellst das Fenster via ShowWindow(handle, SW_RESTORE) dar.

Gast
2006-12-04, 14:06:52
nHancer setzt aber Visible=false, was dazu führt, dass das Fenster unter Windows komplett entfernt wird und auch keinen Handle mehr hat. Damit geht der obige Code ins leere.Ich habe ein Problem, das mit "normalen" Boardmitteln von C++ total einfach zu lösen wäre, bei .NET steh ich aber auf dem Schlauch:Und wie hast du das unter C++ gelöst, wenn das Fenster nicht sichtbar ist und auch keinen Handle hat?

MuLuNGuS
2006-12-04, 14:27:27
nur um zu schauen ob eine instanz schon läuft dürfte auch das hier genügen:


class main
{
static void Main(string[] args)
{
bool firstInstance;
Mutex mutex = new Mutex(false, "MutexName", out firstInstance);
// If firstInstance is now true, we're the first instance of the application;
// otherwise another instance is running.

if (firstInstance == true)
{
Console.WriteLine(" i'm first, i stay!");
}
else
{
Console.WriteLine("i'm second, i have 2 go");
}

Console.Read();




}
}


wenn du das andere fenster nicht aktivieren kannst mußte halt 'ne meldung ausgeben das jenes proggi schon läuft, machen andere anwendungen ja auch so...
®

Gast
2006-12-04, 16:30:40
Mit Process.GetProcessesByName kannst du auch versteckte Prozesse finden. Wie du allerdings ohne Fensterhandle einem Prozess sagen kannst, dass er sich wieder anzeigen soll, weiß ich auch nicht.

Du könntest aber auch von dem einen Prozess eine (versteckte) Datei anlegen lassen, die er regelmäßig prüft. Fehlt sie, kommt der Prozess in den Vordergrund. Der zweite Prozess löscht einfach die Datei, wenn er über GetProcessesByName feststellt, dass schon ein Prozess läuft.

Grestorn
2006-12-04, 17:25:40
Und wie hast du das unter C++ gelöst, wenn das Fenster nicht sichtbar ist und auch keinen Handle hat?

Gute Frage, ohne Windows-Handle gibt's auch kein Ziel für ne Message... :) Aber unter C++ hätte ich das Fenster wohl nicht ganz verschwinden lassen, so wie es Visible=false offensichtlich tut.

Grestorn
2006-12-04, 17:27:07
wenn du das andere fenster nicht aktivieren kannst mußte halt 'ne meldung ausgeben das jenes proggi schon läuft, machen andere anwendungen ja auch so...
®

Genau das macht nHancer im Moment auch, wenn er einen laufenden nHancer-Prozess findet, dieser aber kein Windows-Handle hat.

Irgendwann baue ich vielleicht mal eine Lösung mit Remoting ein.

@all: Danke für Eure Vorschläge und Tipps!

Grestorn
2006-12-04, 17:28:26
Du könntest aber auch von dem einen Prozess eine (versteckte) Datei anlegen lassen, die er regelmäßig prüft. Fehlt sie, kommt der Prozess in den Vordergrund. Der zweite Prozess löscht einfach die Datei, wenn er über GetProcessesByName feststellt, dass schon ein Prozess läuft.

Hm. Klingt nicht übermäßig elegant, würde aber wohl zum Ziel führen... Vielleicht besser über einen Registry-Key. Aber prinzipiell wohl die einfachste Lösung.