Entwickler-Ecke

Sonstiges (.NET) - Program über COM steuern


richy - Mo 28.05.12 18:37
Titel: Program über COM steuern
Hallo,

ich würde gerne mit C# über das Windows COM ein Program namens EventGhost fernsteuern. Unter Python ist dies mithilfe des Plugings win32com möglich, dann müsste es doch auch mit C# gehen. Wie kann ich das COM ansprechen und das Program und die Nachricht für das Program dem COM übergeben.

Pythoncode:

Quelltext
1:
2:
3:
from win32com.client import Dispatch
eg = Dispatch("EventGhost")
eg.TriggerEvent(u"Der String mit dem Befehl.")  //Es muss eigentlich an das Program nur ein String übergeben werden.

Vielen Dank im Voraus.

Moderiert von user profile iconTh69: Code-Tags hinzugefügt


Ralf Jansen - Mo 28.05.12 23:11

Ein laufendes COM Object kannst du dir per Marshal.GetActiveObject [http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.marshal.getactiveobject(v=vs.100).aspx] ranholen. Deine gewünschte Methode am Object aufrufen kannst du in dem du dir den Typ des Objects ranholst und am Typ dann die InvokeMember [http://msdn.microsoft.com/de-de/library/bese341c] Methode benutzt. Wenn d VS2010 oder neuer einsetzt kannst du dir den Teil mit Typ ranholen und InvokeMember vereinfachen in dem du die Rückgabe von GetActiveObject als dynamic [http://msdn.microsoft.com/de-de/library/dd264741.aspx] definierst.


richy - Sa 02.06.12 21:26

Danke für die Antwort.
Ich habe nur das Problem das Program EventGhost heranzuholen. Word kann ich einfach per Word.Application holen. Wie kann ich die progid für das Program EventGhost herausfinden. Ich habe schon ausprobiert per Process.getProcesses() die EventGhost Processe zu bekommen und dann auf ihr Attribut Id zurückzugreifen. Jedoch nur eine Zahl bekommen und diese hat bei mir nicht als progid funktioniert.


Ralf Jansen - Sa 02.06.12 21:40

Was meinst du was du in deinem Python Code an die Dispatch übergibst?


richy - Fr 08.06.12 13:55

Du hast Recht "EventGhost" ist die allgemeine ProgID (mit OleComViewer überprüft). Aber das Programm muss jedesmal die Exception fangen, dass das Programm nicht greifbar ist (EventGhost ist geöffnet).



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;


namespace EventGhost
{
    class Program
    {
        static void Main(string[] args)
        {
          doAction("EventGhost"); 
          Console.ReadLine();
        }

  public static void doAction(String progID)
    {
        Type eg = null;
        Object eg2 = null;

        try
        {
            eg = Type.GetTypeFromProgID(progID);            

            eg2 = Marshal.GetActiveObject(progID);
        }
        catch (Exception e)
        {
            Console.WriteLine("Can not open.");
        }        


        if (eg2 != null)
        {
            Console.Write("super");                      
        }    
       
    }
  }
}


Ralf Jansen - Fr 08.06.12 14:02

Zitat:
Aber das Programm muss jedesmal die Exception fangen


Die Exception hat sicherlich mehr Aussagekraft als 'Can not open'. Wenn du die dir die konkrete Exception ansiehst und nicht einfach mit einer generischen Meldung wegfrühstückst wirst du sicherlich einen Hinweis auf das Problem bekommen.


richy - Fr 08.06.12 14:21

Genauer ist die System.Runtime.InteropServices.COMException in mscorlib.dll aufgetreten. Es gab noch den Hinweis, dass MK_E_UNAVAILABLE ist.


Ralf Jansen - Fr 08.06.12 15:11

Das würde darauf hindeuten das EventGhost kein COM Automation Server ist und man sich gar nicht an eine laufende Instanz hängen kann. Bist du dir sicher das in php der Dispatch Aufruf sich an eine laufende Instanz hängt? Ich vermute dort wird einfach eine neue erzeugt.


richy - Sa 09.06.12 19:52

Der Dispatch Aufruf hat wirklich eine neue Instanz erzeugt. Jetzt habe ich dies nachgebildet, funktioniert super.
Mein Problem ist nun, dass InvokeMember nicht richtig funktioniert. Ich bekomme nur diese Fehlermeldung angezeigt:

Eine nicht behandelte Ausnahme des Typs "System.ArgumentException" ist in mscorlib.dll aufgetreten.

Zusätzliche Informationen: Für ein COM-Objekt muss die Eigenschaft "Set", "Get" oder ein Methodenaufruf angegeben werden.



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;


namespace EventGhost2
{
    class Program
    {
        static void Main(string[] args)
        {
          doAction("EventGhost"); 
          Console.ReadLine();
        }

  public static void doAction(String progID)
    {
        Type eg = null;
        object eg2 = null;
     
        eg = Type.GetTypeFromProgID(progID);
        eg2 = Activator.CreateInstance(eg);
     
        if (eg2 != null)
        {
            Console.WriteLine("Bis hier funktioniert es.");

            eg.InvokeMember("TriggerEvent", BindingFlags.GetField,
            null, eg2, new String[1] {"Aktion für EventGhost"});
           
        }   
       
    }
    }
}


Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt


Ralf Jansen - Sa 09.06.12 20:02

BindingFlags.GetField? Ist TriggerEvent nicht eher eine Methode als ein Feld? Dann wären die BindingFlags eher

C#-Quelltext
1:
BindingFlags.Public | BindingFlags.InvokeMethod                    


richy - So 10.06.12 00:23

Vielen Dank Ralf Jansen. Jetzt läuft mein Programm.

Das C# Program mit dem man EventGhost fernsteuern kann. Ersetze den String "Aktion" mit dem Befehl, der getriggert werden soll.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;


namespace EventGhost
{
    class Program
    {
        static void Main(string[] args)
        {
            doAction("EventGhost");
        }

        public static void doAction(String progID)
        {
            Type typeEventGhost = null;
            object EventGhost = null;

            typeEventGhost = Type.GetTypeFromProgID(progID);
            EventGhost = Activator.CreateInstance(typeEventGhost);

            if (EventGhost != null)
            {
                typeEventGhost.InvokeMember("TriggerEvent", BindingFlags.Public | BindingFlags.InvokeMethod,
                null, EventGhost, new String[1] {"Aktion"});
            }

        }
    }
}


Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt