Jump to content

SendMessage


Recommended Posts

Ich arbeite gerade wieder an meinem Bluetooth Remote Control System und will den DVBViewer über SendMessage steuern. Leider funktioniert das nicht. Ein Handle zum DVBViewer erhalte ich folgendermaßen (das funktioniert auch soweit):

 

HWND hWnd = user.FindWindowA("TfrmMain", null);

 

Danach rufe ich die SendMessage-Funktion folgendermaßen auf:

 

user.SendMessageA(hWnd, 0xB2C2, new WPARAM(25), new LPARAM(0));

 

Im LRESULT wird zwar kein Fehler signalisiert, das Kommando (in diesem Fall 25.. laut Actions.ini ist das Mute) wird vom DVBViewer aber nicht ausgeführt. Entweder ich hole mir den Handle von der falschen Klasse (TfrmMain) oder die Kommandos in der Actions.ini entsprechen nicht den SendMessage-Kommandos. Kann mir da jemand helfen?

 

Mit Winamp funktioniert es wunderbar:

HWND hWnd = user.FindWindowA("Winamp v1.x", null);
user.SendMessageA(hWnd, 0x111, new WPARAM(40045), new LPARAM(0)); // 0x111 = WM_COMMAND

 

(40045 entspricht dem Play-Kommando)

Link to comment

Funktioniert perfekt, danke! Da wär ich nicht drauf gekommen...

 

Da ich nun ein neues Mobiltelefon habe (mit relativ vielen Tasten), wird es bald ein neues und vereinfachtes Bluetooth Fernsteuerungssystem von mir geben. Wie gehabt sollte das dann mit den gängigen Java-fähigen Mobiltelefonen sowie PC-seitig allen Bluetooth-Dongles laufen. Es wird dann auch möglich sein, die Tasten des Mobiltelefons anzulernen bzw. DVBViewer-Aktionen zuzuweisen.

Link to comment

Es wurde ja schon öfter angesprochen, dass sich die Tasten einer Fernbedienung je nachdem, wo sich der DVBViewer befindet (in einem bestimmten OSD zum Beispiel), anders verhalten sollen, also eine andere Aktion ausführen. Da sich auf einem Mobiltelefon doch teilweise wenig Tasten befinden, implementiere ich nun mein Kontextkonzept. Es soll also möglich sein im Mobiltelefon den Kontext zu wechseln und je nach Kontext wird dem DVBViewer eine andere Aktion signalisiert.

 

Beispiel:

Kontext A:

NAVI_UP = ch+

NAVI_DOWN = ch-

NAVI_LEFT = vol+

NAVI_RIGHT = vol-

 

Kontext B:

NAVI_UP = OSD-Up

NAVI_DOWN = OSD-Down

NAVI_LEFT = OSD-Left

NAVI_RIGHT = OSD-Right

 

Ich lagere diese Logik, dass sich die Tasten einer FB unterschiedlich verhalten können, also auf die Fernbedienung aus.

 

Nun zur Frage:

Kann man über COM herausfinden, was der DVBViewer gerade anzeigt, bzw. löst der DVBViewer irgendwelche Events aus? Ich würde den Kontext im Mobiltelefon anhand solcher Infos gerne automatisch updaten.

Edited by CiNcH
Link to comment

Schau dir mal den DVBV-Spy (Membersarea/source bereich) an. Dort werden die möglichen rückmeldungen angezeigt (OSD-Windows/Control etc).

Link to comment

Gibt es irgendwo eine vollständige Zuordnungstabelle für

 

OSD Window -> Window-ID

OSD Control -> Control-ID

 

?

 

procedure onOSDWindow(WindowID: Integer);

The event gets fired whenever a OSD-window is activated.

 

Parameters

WindowID

ID of the OSD-window.

 

Passiert auch was, wenn das OSD wieder geschlossen wird? Denn sonst steh ich vor einem Problem.

Edited by CiNcH
Link to comment

wenn das OSD geschlossen wird, kriegt man windowsID=-1 gesendet.

 

Gibt es irgendwo eine vollständige Zuordnungstabelle für

windowdef.xml enthält die vom system definierten fenster. Einige davon kannst Du ignorieren, da sie niemals auftreten können in dem Kontext (alles mit script tag zum beispiel. Das Clock, Cutout, Visualisation, Subtitel (DVB und TTX) Fenster).

 

Bedenke dabei, das Plugins eigene Seitennummern einfügen können.

 

OSD Control -> Control-ID

Nein. Oder möchtest Du die bedienung abhängig vom ausgewählten Button machen? Dann muss Du gezielt die ControlID aus der entsprechenden OSD Skindatei ziehen.

Link to comment
wenn das OSD geschlossen wird, kriegt man windowsID=-1 gesendet.

 

Super, genau das wäre mein Vorschlag gewesen, wenn es nicht schon ginge :) . Ich konnte das nun auch feststellen, da ich jetzt über Java sowohl DVBViewer-Methoden aufrufen und Events empfangen kann.

 

Mehr dazu hier.

 

Nein. Oder möchtest Du die bedienung abhängig vom ausgewählten Button machen?

 

Eh nicht. Weiß jetzt alles, was ich wissen muss. Nun muss ich mir mal ein paar gedanken machen, wie ich das geschickt löse.

Link to comment

Du solltest einfach den dvbvspy mal starten und ein wenig mit dem viewer rumspielen. Dann kriegt man sehr schnell ein gefühl für den ganzen ablauf :) Ich nehm den immer wieder mal, ist zwar nicht schön aber hilfreich...

 

Ich weiss nicht, ob die Bluetooth api das erlaubt, aber damit könnte man auch rückmeldungen liefern, oder das aktuelle epg oder oder oder <_<

Link to comment

Ja, ich kann problemlos in beiden Richtungen Daten übertragen. Da könnte man einige interaktive Dinge mit dem mobilen Gerät machen. GUI und Logik mäßig ist auf mobilen Geräten sehr viel möglich. Sogar Mobiltelefone sind mittlerweile sehr rechenstark. Auch XML-Parsing ist kein Problem...

 

DVBSpy werd ich mir mal reinziehen, hab ich bis jetzt noch nicht gemacht.

Edited by CiNcH
Link to comment

Ich brauch mal etwas Delphikunde...

 

Was ist ein OleVariant? Welche Werte kann der haben? Wie wird auf ihn zugegriffen?

 

Folgende Methode:

function GetAsArray(ChannelID: Integer; StartTime: TDateTime; EndTime: TDateTime; out List: OleVariant): Integer;

 

Diese generiert COM4J folgendermaßen:

int getAsArray(int channelID, java.util.Date startTime, java.util.Date endTime, java.lang.Object list);

 

Der Typ Objekt ist in der Java-Klassenhierarchie ganz oben. Jede Klasse wird davon abgeleitet, entweder direkt oder indirekt. Viel kann die nicht. Deshalb weiß ich nicht, wie ich auf sowas zugreifen kann!? Vielleicht hilft mir ein Beispiel in Delphi hier weiter um zumindest zu verstehen was hinter der Variable steckt. Wahrscheinlich ein Array :) .

Link to comment

Olevariant ist ein COMautomations kompatibler Variant datentyp.

 

In der angesprochenen Funktion wird er als COM Safearray mit dem Datentyp Variant genutzt. Das ganze sind keine Delphi spezifischen sachen sondern reines COM.

 

Hier gibt es eine Diskussion dazu, ist zwar c# aber vielleicht hilft es etwas weiter.

Link to comment

Ja, hilft mir weiter.

 

Hab nun ein paar Ansatzpunkte. Im c# Beispiel wird das Object einfach in ein zweidimensionales Object-Array umgecastet (EPG-Daten sind also als 2-dimensionale Array organisiert). Das werd ich heute mal probieren, ob das mit COM4J gleich funktioniert.

 

Sonst versuch ich das Object mal in ein SaveArray umzucasten. Diesen Typ gibt es in der COM4J-Bibliothek.

 

Für die Zukunft:

Wie findet man selbstständig heraus, was sich hinter einer OleVariant Variable verbirgt? Ob eindimensionales Array, zweidimensionales Array oder was da außer Array noch so drin sein kann? OK, frage zurück, steht in der Doku. Das bekomm ich hin. Ich poste dann das Ergebnis in meinem COM4J-Thread, damit alle was davon haben.

Edited by CiNcH
Link to comment

Naja, ich komm da erstmal nicht weiter.

 

Wenn ich

int nrOfEntries = manager.getAsArray(0, startTime, endTime, null);

ausführe, kommt die Methode mit den nrOfEntries zurück.

 

Sobald ich etwas als vierten Parameter in die Methode gebe, crasht irgendwo irgendeine OLE DLL, sprich, ich weiß nicht, was ich da für eine Struktur als Parameter in die Methode packen muss, damit diese gefüllt wird. Es gibt zwar die Typen Variant und SafeArray in der COM4J-Bibliothek, aber wie diese auf OleVariant abgebildet werden, steht nirgends. Aus der Javadoc werd ich zu diesen Klassen nicht schlauer.

 

Hier nochmal der generierte Prototyp.

 

int getAsArray(int channelID, java.util.Date startTime, java.util.Date endTime, java.lang.Object list);

 

Vielleicht hat ja noch jemand eine Idee...

Edited by CiNcH
Link to comment

Also wenn ich auf die COM4J seite schaue, dann steht dort, dass Safearrays nicht komplett unterstützt werden bzw. dass damit noch grössere Probleme bestehen.

Link to comment

Wenn ich den Variant erzeuge ist er vom Typ 'VT_EMPTY', wenn er "aus der Methode" getAsArray zurückkehrt vom Typ 'VT_ARRAY_VARIANT'. Ist ja schon mal etwas :) .

Link to comment

Nein, da ist nichts mit casten.

 

Was ist nun ein Variant genau? Ich versteh nicht, wo da die Daten rauskommen sollen. Die COM4J-Klasse Variant erbt von Number, stellt also ein Zahl dar!?

 

Die einzig interessante Methode in Variant ist für mich:

<T extends Com4jObject>T object(Class<T> type)				 Reads this VARIANT as a COM interface pointer.

 

Die gibt ein Objekt einer Klasse zurück, welche das Com4jObject Interface implementiert, wie alle DVBViewer definitions, z.B. IEPGData!? Möglicherweise ein "IEPGData-Array Pointer"? Zäche Partie das ganze *g*.

Link to comment

Variante sind allround datentypen, da kann man ne menge datentypen reinstecken und wieder rausholen.

 

Der VT_Type sagt Dir was da drinne ist: ein Variantarray oder genauer ein ein- oder mehrdimensionales COM Safearray bestehend aus variant elementen. Das ganze kann man normalerweise mit API aufrufen an die COM-Parts von windows auseinanderklauben (das wird nur in den meisten sprachen angenehmer gestaltet). Es handelt sich auf keinen Fall um ein Interface.

 

Ich kann leider keinen passenden Vergleich für Java liefern, damit hab ich mich bisher nie beschäftigt (und ich merke grade mal wieder warum :) ).

Link to comment

Wirklich weiter bin ich nicht gekommen. Ich kann jetzt zumindest die Signaldaten auslesen. Die geben ja auch OleVariant zurück hier gibt die Methode aber direkt ein Object eines Java-Typs zurück.

 

Hier für die Signal Strength Methode der erzeugte Prototyp:

@VTID(9)
@ReturnValue(type=NativeType.VARIANT)
java.lang.Object signalStrength(int card);

 

Die Methode liefert ein Objekt vom Typ Integer zurück. Folgender Aufruf liefert daher die Signalstärke zurück:

Integer strength = m_DVBViewerServer.dvbHardware().signalStrength(2);

 

Die Signal Quality Methode liefert denselben Wert. Woher kommen die Daten? Vom IBDA_SignalStatistics Interface?

 

An dem SafeArray bleib ich dran. Da weiß ich leider noch nicht, wie ich dran komme.

Link to comment
  • 2 weeks later...

2 kleine Fragen zum COM-Server:

 

_ Programm, das den DVBViewer COM-Server verwendet, kann zu diesem nur dann verbinden, wenn der DVBViewer nicht läuft. Eine Verbindung mit dem COM-Server startet dann den DVBViewer. Ist dieses Verhalten soweit normal?

 

_ Wird der DVBViewer durch den COM-Server gestartet, wird der zuletzt aktive Kanal nicht eingestellt. Normal?

Link to comment
_ Programm, das den DVBViewer COM-Server verwendet, kann zu diesem nur dann verbinden, wenn der DVBViewer nicht läuft. Eine Verbindung mit dem COM-Server startet dann den DVBViewer. Ist dieses Verhalten soweit normal?

hmm? Wenn der Viewer läuft kann man sich mit dem verbinden (GetActiveObject) ansonsten macht man ein CreateObject um ihn zu starten.

 

Wird der DVBViewer durch den COM-Server gestartet, wird der zuletzt aktive Kanal nicht eingestellt. Normal?

Das ist normal.

Aber man kann ja den befehl "letzter sender" (LastChannel=63) an den Viewer schicken (entweder per sendmessage oder per idvbviewer.sendcommand).

Link to comment
hmm? Wenn der Viewer läuft kann man sich mit dem verbinden (GetActiveObject) ansonsten macht man ein CreateObject um ihn zu starten.

 

Alles klar, hab immer ein Create gemacht. Das schlägt dann fehl, wenn der DVBViewer schon läuft...

 

Aber man kann ja den befehl "letzter sender" (LastChannel=63) an den Viewer schicken (entweder per sendmessage oder per idvbviewer.sendcommand).

 

OK, werd ich dann auch so machen.

 

Vielen Dank für die Hilfe.

Link to comment

Hab jetzt das SafeArray mit JACOB hinbekommen. Der Code ist zwar auf Grund von Reflection hässlich (wenig objektorientiert), funktioniert aber...

 

		ActiveXComponent dvbvComServer = ActiveXComponent.connectToActiveInstance("DVBViewerServer.DVBViewer");
	ActiveXComponent epgManager = dvbvComServer.getPropertyAsComponent("EPGManager");

	// SafeArray-Variant
	Variant epgSafeArrayVariant = new Variant();
	epgSafeArrayVariant.putVariant(0);

	// weitere Funktionsparameter
	Variant startTime = new Variant();
	startTime.changeType(Variant.VariantDate);
	startTime.putDate(new Date());
	Variant stopTime = new Variant();
	startTime.changeType(Variant.VariantDate);
	stopTime.putDate(new Date(new Date().getTime() + 259200000));

	Variant[] arguments = new Variant[] { new Variant((int)0), startTime,stopTime, epgSafeArrayVariant};   
	Variant nrOfEntries = epgManager.invoke("GetAsArray", arguments);

	SafeArray epgSaveArray = (SafeArray)arguments[3].getVariant();   

	System.out.println("Entries: " + nrOfEntries.getInt());
	for (int i = 0; i < nrOfEntries.getInt(); i++)
	{
		System.out.print(epgSaveArray.getString(i, 2));
		System.out.print("  " + epgSaveArray.getString(i, 5));
		System.out.println();
	}

Link to comment
Der Code ist zwar auf Grund von Reflection hässlich

Wir sind hier auch nicht bei germanys next code model, also was soll, hauptsache es geht jetzt :)

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...