Eventhandling mit Windows.Forms.UserControls im IE

Harass

Mitglied
Hallo,

ich habe im HTML-Code mit Hilfe des <object>-Tags ein Windows.Forms.UserControl eingebunden, was auch soweit alles prima funktioniert.

Um nun mit dem Control interagieren zu können (speziell eventhandling) hab ich, wie in diversen Artikeln/Anleitungen beschrieben, ein ComSourceInterface (IDispatch) und ein weiteres als Schnittstelle:
Code:
[ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(ControlEvents))]
public class MyWindowControl : System.Windows.Forms.UserControl
    ,ComInteropControlInterface

Leider kann ich weder über das <param>-Tag innerhalb des <object>-Tags auf die öffentlichen Membervariablen zugreifen (was IMHO ja auch ohne das "Überschreiben" des Interfaces gehen müsste), noch kann ich events abfangen. Hab da jedwede (meist nicht html-konforme) Möglichkeit ausprobiert., z.B.:
Code:
<script for="objectID" event="eventName(args)">
// code
</script>

Es will mir einfach nicht gelingen an irgendwelche Methoden/Variablen/Events zu gelangen, weder mit dem ie6 noch ie7.

Falls sich jemand hier damit auskennt, poste ich auch gerne weiteren Quellcode, falls es hilft.
[OT]Das muss bis nächste Woche Freitag hinhauen, also hopphopp ;) [/OT]

TIA, Martin
 

Norbert Eder

Erfahrenes Mitglied
Also für's Verständnis:
Du hast ein UserControl gebastelt, das ganze in einen ActiveX-Container gestopft und auf einer Webseite eingebunden?

Nun möchtest du auf dessen Methoden zugreifen bzw. gefeuerte Events handhaben. Korrekt? Wie möchtest du darauf reagieren? JScript oder anders? Im Falle von JScript kannst du das anders machen. Das Event in deinem UserControl abfangen und dann einfach an eine JScript-Funktion übergeben, die dann irgendetwas macht.
 

Harass

Mitglied
Cool, ging das schnell. Danke schonmal!

Du hast das richtig erkannt. Ziel ist es im Prinzip, normalerweise serverseitige Objekte lokal auszuführen.

Welche clientseitige Scriptsprache ich dafür benutzen muss, ist mir eigentlich ziemlich egal, da die Applikation eh nur auf vorher konfigurierten Systemen laufen wird. Würde auch VBScript nehmen, wenn es denn damit funktionieren sollte. ;)

Ziel ist, Events abzufangen, die innerhalb des Controls getriggert werden, clientseitig zu kontrollieren.
 

Norbert Eder

Erfahrenes Mitglied
Blöde Frage: Warum nicht AJAX verwenden?

Unabhängig dessen: Du kannst dir in deinem "ActiveX" per Zugriff auf auf das HtmlDocument die eingebundenen Scripts zurückliefern lassen, wodurch du ein bestimmtes aufrufen kannst. Dabei kannst du auch entsprechende Parameter übergeben etc.

Ich kann dir hier ein C++ Beispiel geben wie es funktioniert. Müsstest du in deinem ActiveX-Container entsprechend nachbilden:

Code:
CString WebHelper::CallJSFunction(CString& func, CString& param)
	{
	if (this->m_pDoc == NULL) 
		return CString();

	if (param.GetLength() == 0)
		return CString();

	CComPtr<IDispatch> spScript;

	if(!GetJScript(spScript))
		return CString();
	
	CComBSTR bstrMember(func);
	DISPID dispid = NULL;
	
	HRESULT hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);
	if(FAILED(hr)) 
		return CString();

	const int arraySize = 1;
	DISPPARAMS dispparams;
	CComBSTR bstrParams = param;
	memset(&dispparams, 0, sizeof dispparams);
	dispparams.cArgs      = arraySize;
	dispparams.rgvarg     = new VARIANT[dispparams.cArgs];
	dispparams.cNamedArgs = 0;

	bstrParams.CopyTo(&dispparams.rgvarg[0].bstrVal);
	dispparams.rgvarg[0].vt = VT_BSTR;

	EXCEPINFO excepInfo;
	memset(&excepInfo, 0, sizeof excepInfo);
	CComVariant vaResult;
	UINT nArgErr = (UINT)-1; 
	hr = spScript->Invoke(dispid,IID_NULL,0,DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);
	delete [] dispparams.rgvarg;
	if (hr == S_OK) 
		{
		if (vaResult.vt == VT_BOOL)
			{
			CString strRet = L"0";
			if (vaResult.boolVal == VARIANT_TRUE)
				strRet = L"1";
			return strRet;
			}
		else if (vaResult.vt == VT_BSTR)
			{
			CString strRet = vaResult.bstrVal;
			return strRet;
			}
		else if (vaResult.vt == VT_I2)
			{
			long lRet = vaResult.iVal;
			wchar_t cRet[65];
			_ltot(lRet, cRet, 10);
			CString strRet(cRet);
			return strRet;
			}
		else if (vaResult.vt == VT_I4)
			{
			long lRet = vaResult.lVal;
			wchar_t cRet[65];
			_ltot(lRet, cRet, 10);
			CString strRet(cRet);
			return strRet;
			}
		else if (vaResult.vt == VT_I8)
			{
			long lRet = vaResult.llVal;
			wchar_t cRet[65];
			_ltot(lRet, cRet, 10);
			CString strRet(cRet);
			return strRet;
			}
		else if (vaResult.vt == VT_INT)
			{
			long lRet = vaResult.intVal;
			wchar_t cRet[65];
			_ltot(lRet, cRet, 10);
			CString strRet(cRet);
			return strRet;
			}
		}

	return CString();
	}

bool WebHelper::GetJScript(CComPtr<IDispatch>& spDisp)
	{
	HRESULT hr = m_pDoc->get_Script(&spDisp);
	if (hr == S_OK)
		return true;
	else
		return false;
	}

Dadurch ist es innerhalb der Komponente möglich, eine Javascript-Methode aufzurufen. Diese kann dann aufgrund der übergebenen Parameter auch bestimmte Dinge tun.
 

Harass

Mitglied
Das sieht zwar ganz nett aus und wäre auch ne Möglichkeit, aber es muss doch gehen, dass ich die Events direkt aus dem HTML-Code heraus abfangen kann.
Zumal ich eh schon soweit bin, dass ich Zugriff auf Variablen und Methoden der Klasse habe. Und zwar habe ich einfach den ganzen Interface-Schnickschnack weggelassen und durch
Code:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)
ersetzt.

Was nur noch nicht klappen will, ist der Zugriff auf die Events. Kurz der grobe C# - Quellcode:
Code:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)
public class XYZ
{
   public delegate void MyEventHandler(int args);
   public MyEventHandler OnMyEvent;

   public XYZ()
   {
      // CODE
      myControl.Click += new Eventhandler(myControl_Click);
   }

   private void myControl_Click(object sender, EventArgs e)
   {
      if (OnMyEvent != null)
         OnMyEvent(0);
   }
}

Leider ist es mir noch nicht gelungen, den EventHandler auf Script-Ebene zu triggern. Wenn das nicht klappen sollte, werde ich wohl deinen Weg einschlagen müssen, aber es erscheint mir doch als so nicht vorgesehen und auch recht fehleranfällig.

Kurz zu AJAX:
Würde ich auch lieber benutzen, geht allerdings nicht und ist auch in dem Fall nicht erwünscht. :suspekt:
 

Norbert Eder

Erfahrenes Mitglied
Nur so ganz nebenbei:
Wieso verwendest du eigentlich nicht WebControls? Da könntest du auf die Events direkt reagieren. Mit einem ActiveX wird das wohl eher nicht funktionieren, aber ich lasse mich gerne belehren :)
 

Harass

Mitglied
Es geht darum, eine BluetoothLib, die auf dem Server liegt, auf dem Client auszuführen. Und da bei den Com-UserControls alle benötigten Bibliotheken auf den Clienten geladen werden ist das der einfachste Weg.

Da ich mich eh in einem geschlossenen Netzwerk finde und ActiveX und sonstiger möglicherweise bösartiger Code nicht in das Netzwerk gelangt.

Nun zur Notlösung, denn das EventHandling ist mir immer noch nicht gelungen:

Ich mache aus der Webseite heraus mit Javascript ein ständiges Polling, ob die Events geschaltet sind. Falls vielleicht doch jemand eine anständige Lösung für mein Problem findet, der kann sich bitte bei mir melden!

Grüße, Martin