Element (hWnd) in externer Anwendung finden und erweitern

  • VB6

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von vblind.

    Element (hWnd) in externer Anwendung finden und erweitern

    Hallo Community!

    Ich hoffe ihr könnt mir weiterhelfen, ich bin leider zu eingerostet um das nachfolgende Problem zu lösen:
    Ich habe eine externe Anwendung in der sich nach Klick auf einen speziellen Button ein Popup/down Menü öffnet. Ich möchte diesem Menü gerne weitere Unterpunkte (bzw. Grafiken) hinzufügen. Konkret zeigt das Popup eine Auswahl an Smilies die ich erweitern möchte.
    Da das Programm keine Möglichkeiten vorsieht (API oder ähnliches) in die GUI einzugreifen, wollte ich es über die hWnd-Eigenschaft versuchen (ich hatte es damit schonmal irgendwann geschafft), nur leider scheitere ich diesmal schon im Ansatz.

    Ich finde weder den richtigen handle, noch weiss ich wie ich damals das Menü erweitert hatte (ich meine ich hatte das Control vergrößert).
    Jemand Ansätze zur Hilfe?

    Vielen Dank!

    P.S.: Eingerostet heisst, wirklich! eingerostet.. seit der letzten Codezeile sind Jahre ins Land gegangen. Seht mir also nach, dass ich vielleicht mit einer Zeile Plaincode mehr anfangen kann, als mit einer Funktionsbeschreibung.
    Und: Ich muss mich nicht auf VB6 festlegen, VB 2010 Express dürfte auch ok sein, sollte es das Vorhaben erleichtern.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „vblind“ ()

    Hi. Um welche Anwendung handelt es sich? Wenn es um irgendeine Form des (Windows-)Explorers geht und das Menü ein Kontextmenü ist, solltest du in deiner Suche die Begriffe IShellExtInit und IContextMenu einbeziehen - die Schnittstellen sind für die beschriebene Funktionalität verantwortlich.

    Hier findest du auch Codebeispiele:
    msdn.microsoft.com/en-us/library/bb776881%28VS.85%29.aspx
    informit.com/articles/article.aspx?p=169474

    Es ist von Bedeutung, welches Menü in welcher Anwendung erweitert werden soll. Bitte beschreibe diesen Zusammenhang noch einmal genauer, da es sonst zu viele Lösungsmöglichkeiten gibt, die teilweise mehr schlecht als recht zum Ziel führen.
    Gruß
    hal2000
    Hallo hal2000 und dank dir für die Antwort.

    Bei der Anwendung handelt es sich um Skype. Dort möchte ich das Control für die Smileys erweitern.
    Sprich: Man hat x-Benutzer in der Buddyliste, klickt auf einen, öffnet damit das Chatfenster. Dort befindet sich ein Button um die Smileyliste anzuzeigen. Wenn auf diesen geklickt wird, öffnet sich die Liste:



    .. die ich gerne so erweitern möchte:

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „vblind“ ()

    Alles klar - das nenne ich mal eine ausführliche Problembeschreibung.

    Das Smileyfenster ist ein eigenständiges Overlay-Fenster, welches bei jedem Klick auf den Smiley-Button neu erstellt wird. Dadurch ist es schwierig, an dessen Handle zu kommen, da es sich ständig ändert. Die Musterlösung wäre ein Hook, der das Erstellen des Fensters mitbekommt und dessen Größe entsprechend ändert. Dabei hilft eventuell dieser Tipp. Die genauere Analyse hat gezeigt, dass das Smileyfenster dem Skype-Hauptfenster nicht untergeordnet ist, aber zum gleichen Prozess gehört. Wenn du den Hook installiert hast und das Smileyfenster geöffnet wird, musst du nur noch die passende Meldung abfangen und MoveWindow zum Ändern der Größe aufrufen, wenn der Klassenname passt, den du per GetClassName(hWnd) bekommst. Er lautet TSmileySelector für das Smileyfenster.

    Edit: Mir ist noch eingefallen, dass der angegebene Tipp von CodeProject (gemeint sind eigentlich Hooks im allgemeinen) nur im Prozess des Aufrufers funktioniert, also in deiner Anwendung. Wenn du versuchst, SetWindowsHookEx() mit einer anderen ThreadID (der von Skype) als der eigenen aufzurufen, schlägt der Aufruf fehl. Warum? Die CLR kann nicht in andere Prozesse injiziert werden. Die lange Erklärung gibts im MSDN.

    Es ist also erforderlich eine kleine DLL zu schreiben, welche dir die Hookfunktion zur Verfügung stellt. Den Callback kannst du dann an deine Anwendung weiterreichen, die dann die Größe des Fenster ändert. Allerdings kannst du die Größenänderung (kaum mehr als ein paar Zeilen) letztlich auch noch in unverwaltetem Code implementieren - dazu ein Interface für .NET zu schaffen wäre zwar nicht aufwändig, aber unnötig. Das Hook-Interface kannst du so aber immerhin wiederverwenden - ein schwacher Trost dafür, dass dein Vorhaben in .NET leider nicht realisierbar ist.
    Gruß
    hal2000

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „hal2000“ ()

    Merci für die ausführliche Antwort und Links zum Lösungsansatz.
    Wenn ich deine Aussage richtig zusammenfasse, ist es nicht unter VB 2010 (Express), bzw. VB im allgemeinen realisierbar? Oder ist es machbar, jedoch nur nicht 100% valide? War jetzt recht viel Info die ich noch sortieren muss, entschuldige.
    Nach deiner Anleitung zu Beginn deines Postings sollte es doch machbar sein, ich meine mich auch dunkel daran zu erinnern, dass es so mal unter VB6 funktioniert hat.

    Die Frage ist nun: Altere ich um Jahre, verliere den Großteil der noch verbliebenen Haare, male Funktionsdiagramme und versuche es einfach, oder ist es eher ein aussichtloses Vorhaben?

    P.S. Ich habs jetzt nochmal unter VB versucht. hWnd und Klassenname des Fensters finde ich (hWnd ID + TConversationForm.UnicodeClass). Wie komme ich von da weiter zum TSmileySelector, war für mich nicht auffindbar:

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „vblind“ ()

    Hi.

    Mir ist noch eine andere Möglichkeit eingefallen, an das Handle zu kommen. Doch dazu später mehr - erstmal beantworte ich deine Fragen :) .

    [...] ist es nicht unter VB 2010 (Express), bzw. VB im allgemeinen realisierbar?

    Doch, ist es.

    Wie komme ich von da weiter zum TSmileySelector, war für mich nicht auffindbar

    Vom Skype-Hauptfenster kommt du nicht weiter zum TSmileySelector, da dieser kein untergeordnetes Fenster ist. Style und ExStyle des TSmileySelecors sind WS_POPUP, WS_VISIBLE, WS_CLIBSIBLINGS und WS_EX_LAYERED. Die Referenz dazu gibts hier und hier. Für ein Kindfenster müsste noch WS_CHILD mit dabei sein, was es aber nicht ist. Damit ist der SmileySelector ein TopLevel-Fenster, genau wie z.B. Firefox oder das Skype-Hauptfenster (sie sind gleichberechtigt).

    Nun zum Handle des Fensters:
    Es ist eine äußerst schlechte Lösung (die Nooblösung schlechthin, die leider von vielen hier praktiziert wird), einen Timer zu verwenden und alle X Millisekunden zu prüfen, ob das Smileyfenster vorhanden ist. Darunter leidet zum einen die Performance und zum anderen sieht es nicht schön aus, wenn das Fenster erst mit Verzögerung (aufgrund des Prüfintervalls) vergrößert wird. Der richtige Weg ist wieder ein Hook. Davon gibts eine ganze Menge, aber nur zwei davon lassen sich in Verbindung mit .NET verwenden: WH_KEYBOARD_LL und WH_MOUSE_LL. Auch wenn der WH_CALLWNDPROC-Hook viel komfortabler wäre, müssen wir uns mit den Mausereignissen begnügen.

    Wir müssen auf einen Mausklick reagieren (was allein schon recht umfangreich ist) und in dessen Handler prüfen, ob das Fenster TSmileySelector existiert. Das ist allerdings ein zeitkritisches Unterfangen, denn das Fenster wird als Folge des Klicks erstellt, sodass unser Handler eventuell ins Leere läuft, wenn er vor dem Erstellen des Fensters ausgeführt wird. Das Verhalten kann je nach aktueller Systemlast variieren. Daher müssen wir auf dieses Fenster warten, ohne den Handler zu blockieren. Es wäre zu umfangreich, alles hier zu beschreiben - ich schicke dir den Code nachher mal per P/N.

    Dir ist sicher schon aufgefallen, dass meine Lösungen durchweg auf VB.NET abzielen, was auch einen Grund hat: VB6 ist veraltet. Die Objektorientierung, die mit VB7 (=VB.NET 2003) eingeführt wurde, hat viele Vorteile gegenüber der prozeduralen Programmierung in VB6, z.B. die Wiederverwendbarkeit und Erweiterbarkeit von Code, ohne den vorhandenen ändern zu müssen.
    Gruß
    hal2000