Announcement

Collapse
No announcement yet.

Von Delphi nach C# - SendMessage / FindWindow etc.

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Von Delphi nach C# - SendMessage / FindWindow etc.


    Während meiner Experimente in C# bin ich irgendwie auf Probleme gestossen. In Delphi hatte ich eine Anwendung geschrieben, um von dieser Anwendung aus, Winamp per SendMessage zu steuern. In C# fehlen mir nun irgendwie diese ganzen Befehle.

    Ich habe schon einmal einen DLL Import von der User32 versucht, bin aber gescheitert.

    Kann mir hier jemand helfen. Ich würde gerne die folgenden Befehle (welche aus einer Delphi Anwendung kommen) in C# umsetzen:

    hwndWinamp : THandle

    ...

    hwndWinamp := FindWindow('Winamp v1.x', SW_SHOWNA);

    ...

    SendMessage(hwndWinamp, WM_COMMAND, 40045, 0);

    ...

    WinExec(PChar('C:\programme\winamp\winamp.exe'), SW_SHOWNA);

    ....

    Über Hilfe wie ich diese Befehle realiseren könnte, wäre ich sehr dankbar.

    Viele Dank im voraus für die Hilfe.

    mfg Christian Müller

  • #2
    Hallo,

    um Anwendungen kontrolliert zu starten, ist im .NET-Framework die <b>Process</b>-Klasse zuständig. Das folgende Beispiel startet den Windows-Taschenrechner und wartet auf dessen Ende:
    <pre>
    using System.Diagnostics;
    ...
    private void button1_Click_1(object sender, System.EventArgs e)
    {
    Process p = new Process();
    p.StartInfo.FileName = "calc.exe";
    p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
    p.Start();
    p.WaitForExit();
    p.Close();
    MessageBox.Show ("Programm wurde geschlossen");
    }
    </pre>
    Für das Ermitteln der laufenden Anwendungen ist ebenfalls die gleiche Klasse zuständig:
    <pre>
    using System.Diagnostics;
    ...
    private void button1_Click(object sender, System.EventArgs e)
    {
    Process[] aRunningProcesses = Process.GetProcesses();
    foreach(Process aProcess in aRunningProcesses)
    {
    listBox1.Items.Add(aProcess.ProcessName);
    }
    }
    </pre>
    Für das Zuschicken von Tastatureingaben ist die Klasse <b>SendKeys</b> (aus System.Windows.Forms) zuständig, wobei ich dafür nur ein VB.NET-Beispiel am Lager habe:
    <pre>
    Dim aProc As Process() = Process.GetProcessesByName("Calc")
    If aProc.Length > 0 Then
    Microsoft.VisualBasic.AppActivate(aProc(0).Id)
    SendKeys.SendWait("1{+}")
    SendKeys.SendWait("2")
    SendKeys.SendWait("~")
    End If
    </pre>
    Wenn es darum geht, Windows-Botschaften zuzustellen, ist <b>P/Invoke</b> der richtige Ansatz. Das folgende Beispiel schickt an sich selbst über die Botschaftswarteschlange von Win32 eine private Botschaft:
    <pre>
    [DllImport("user32.dll")]
    extern static int PostMessage(int hWnd, int Message, int wParam, int lParam);

    private void button1_Click(object sender, System.EventArgs e)
    {
    PostMessage(this.Handle.ToInt32(), WM_APP, 0, 0);
    }
    </pre&gt

    Comment


    • #3
      Hallo Herr Kosch,

      Vielen Dank für die Antwort. Habe alles schon umgesetzt und das Starten funktioniert auch schon. Nur mit der PostMessage habe ich so meine kleinen Probleme.

      Wo bekomme ich den Wert für WM_APP bzw. WM_COMMAND her?

      C# kennt WM_APP und WM_COMMAND nicht, sagt jedenfalls der Compiler

      Comment


      • #4
        Hallo,

        &gt;Wo bekomme ich den Wert für WM_APP bzw. WM_COMMAND her?

        oops - da ist mir doch eine Zeile aus der Zwischenablage abhanden gekommen:
        <pre>
        const int WM_APP = 0x8000; // aus WinUser.h
        </pre>
        Die Konstanten sind alle in den Dateien (wie zum Beispiel <i>WinUser.h</i> und <i>Windows.h</i>) aus dem <i>Microsoft Platform SDK</i> zu finden und müssen in das eigene Projekt eingefügt werden. Damit der Entwickler auch wirklich zuerst in den Klassen des .NET-Frameworks sucht, stellt Microsoft in der Version 1.0 des Frameworks keine vordeklarierte Sachen für die "alten" Win32-API-Funktionen bereit :-

        Comment


        • #5
          Hallo Herr Kosch,

          vielen Dank für die Antwort. Habe das ganze implementiert und leider funktioniert es nicht mit dem Process.

          Ich habe mir dann, nach dem Beispiel von PostMessage, noch die Funktion FindWindow importiert und dann funktioniert es.

          Wenn ich "Winamp" über Process starte und diesen Handle für PostMessage verwende, gibt es keine Reaktion. Jedoch hatte ich mit der folgenden Anweisung Erfolg:

          <B>Process myProcess;

          myProcess = new Process();

          myProcess.StartInfo.FileName = @"Winamp.exe";

          myProcess.StartInfo.WorkingDirectory = @"C:\Programme\Winamp\";

          myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

          myProcess.Start();

          int Handle = FindWindow("Winamp v1.x",null);

          PostMessage(Handle,(int)Msg.WM_COMMAND,40045,0);</B>

          Die Folgenden Codezeilen starten zwar Winamp, jedoch gab es keine Reaktion auf PostMessage:

          <B>Process myProcess;

          myProcess = new Process();

          myProcess.StartInfo.FileName = @"Winamp.exe";

          myProcess.StartInfo.WorkingDirectory = @"C:\Programme\Winamp\";

          myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

          myProcess.Start();

          PostMessage(myProcess.Handle.ToInt32(),(int)Msg.WM _COMMAND,40045,0);</B>

          Können Sie mir erklären wieso es auf die eine Weise funktioniert und auf die andere nicht?

          Viele Grüße,

          Christian Mülle

          Comment


          • #6
            Hallo,

            die Erklärung dafür ist sehr einfach. Die Hilfeseite <i>Process Members</i> der .NET Framework Class Library zeigt, dass die Process-Klasse zwischen:<br>
            a) <b>Handle</b> als natives Prozess-Handle (nicht Fenster-Handle), und <br>
            b) <b>MainWindowHandle</b> als das Fenster-Handle des Hauptfensters des gestarten Prozesses<br>
            unterscheidet. Die Botschaft muss also an die von MainWindowHandle zurückgelieferte Adresse geschickt werden. Auf der Hilfeseite ist allerdings auch vermerkt, dass diese Eigenschaft nur dann zur Verfügung steht, wenn die Eigenschaft <b>ProcessStartInfo.UseShellExecute</b> auf false gesetzt wurde.

            P.S: Bevor mach versucht, den "alten" Weg über die Win32-API-Funktionen nachzubauen, sollte man zuerst die Hilfeseiten der jeweiligen .NET-Klassen durchsuchen. In fast allen Fällen ist dort bereits eine Objektorientierte Lösung für das eigene Problem zu finden

            Comment


            • #7
              Hallo Herr Kosch,

              vielen Dank. Jetzt funktioniert es einbandfrei.

              Ich hatte es vorher schon mal mit MainWindowHandle probiert, nur hatte UseShellExecute nicht auf false gesetzt und so funktioniert es dann auch nicht.

              Nochmals vielen Dank für die entscheidende Hilfestellung.

              Christian Mülle

              Comment

              Working...
              X