Laden...

ActiveX ohne Verweis

Erstellt von LastGentleman vor 18 Jahren Letzter Beitrag vor 18 Jahren 5.976 Views
LastGentleman Themenstarter:in
1.274 Beiträge seit 2005
vor 18 Jahren
ActiveX ohne Verweis

Hallo zusammen wie kann ich ein ActiveX Objekt erzeugen ohne das ich eine Verweis setze.

Ich stell mir das etwa so vor (aus VB6)
Set objWord = CreateObject("word.Application")

gibt es sowas in C#.

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

X
2.051 Beiträge seit 2004
vor 18 Jahren

in System.Runtime.InteropServices-Namespace findest du vielleicht, was du suchst.

LastGentleman Themenstarter:in
1.274 Beiträge seit 2005
vor 18 Jahren
Was noch?

ObjectCreationDelegate-Delegat , in der Beschreibung steht Erstellt ein COM-Objekt.

Erstellt ein COM-Objekt.
🤔🤔🤔
🤔🤔
🤔

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

P
939 Beiträge seit 2003
vor 18 Jahren

Marshal.GetActiveObject ist die C#-Entsprechnung für CreateObject. Das nützt dir allerdings nicht viel, da C#, im Gegensatz zu VB6, streng typisiert ist.

Der Typ des zurückgelieferten Objekts muss bekannt sein, bevor man auf die Methoden und Eigenschaften zugreifen kann. Ohne einen Verweis ist er aber nicht nicht.

Ich glaube man kommt nicht um die Generierung und Einbindung eines COM-Wrappers (RCW) herum. Umständlich über Reflection würde es gehen, ich sehe da aber keinerlei Vorteile. Warum möchtest du denn keinen Wrapper beziehungsweise COM-Verweis einbinden?

Gruss
Pulpapex

3.728 Beiträge seit 2005
vor 18 Jahren
Reflection

@Pulpapex: GetActiveObject ist die Entsprechung für GetObject und nicht für CreateObject!

Das nützt natürlich was. Auch in C# kann man ohne direkte Verweise arbeiten. Das geht mit Reflection. Ist z.B. dann interessant, wenn Dein Programm mit verschiedenen Word-Versionen arbeiten muss.

Folgender Beispielcode schreibt "Hallo Welt" auf ein neues Word-Dokument ganz ohne Verweise:


// DER System.Reflection NAMESPACE MUSS IMPORTIERT WERDEN, DAMIT
// DIESER CODE LÄUFT!

// COM-Metadaten von Word.Application aus der Registry laden
Type wordApplication=Type.GetTypeFromProgID("Word.Application");

// Neue Instanz von Word erzeugen
object word = Activator.CreateInstance(wordApplication);

// Word sichtbar machen (Visible=true)
wordApplication.InvokeMember("Visible",BindingFlags.IgnoreCase | BindingFlags.SetProperty | BindingFlags.Public,null,word,new object[1]{true});

// Dokumentauflistung abrufen
object documents = wordApplication.InvokeMember("Documents", BindingFlags.IgnoreCase | BindingFlags.GetProperty | BindingFlags.Public, null, word, new object[0]);

// COM-Metadaten von Word.Documents ermitteln
Type wordDocuments = documents.GetType();

// Neues Dokument erstellen (Documents.Add)
wordDocuments.InvokeMember("Add", BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Public, null, documents, new object[0]);

// Selection-Objekt abrufen
object selection = wordApplication.InvokeMember("Selection", BindingFlags.IgnoreCase | BindingFlags.GetProperty | BindingFlags.Public, null, word, new object[0]);

// COM-Metadaten von Word.Selection ermitteln
Type wordSelection = selection.GetType();

// "Hallo Welt" schreiben
wordSelection.InvokeMember("TypeText", BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Public, null, selection, new object[1] { "Hallo Welt" });


Da Du ja keinen Verweis hast, musst Du Dir die Klassenbeschreibungen (Metadaten) eben zur Laufzeit besorgen. Wenn Du eine Instanz vom Typ Object hast, erhälst Du die Metadaten über die Methode GetType(). Diese Metadaten werden immer durch ein Type-Objekt dargestellt. Mit der Activator-Klasse lassen sich Objekte eines bestimmten Typs erzeugen. Um auf eine Methode oder Eigenschaft zuzugreifen, musst Du die InvokeMember-Methode des entsprechenden Type-Objekts verwenden. Das zu verwendende Objekt sowie ggf. Parameter für den Aufrufen müssen der InvokeMember-Methode übergeben werden. Außerdem noch BindingFlags. Die legen fest, um welche Art von Zugriff es sich handelt und wie er genau durchgeführt werden soll.

Der Vorteil dieser Reflection-Lösung liegt klar auf der Hand. Er funktioniert mit jeder Word-Version ab Word 97 ohne Änderungen (Vorrausgesetzt Du verwendest keine Funktionen, die es in älteren Word-Versionen noch nicht gegeben hat).

LastGentleman Themenstarter:in
1.274 Beiträge seit 2005
vor 18 Jahren

andere Frage,

wie kommt man bloß zu so einem Wissen?
Bücher, MSDN oder irgendwelchen Foren 😉.

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo LastGentleman,

mit Geduld und Beharrlichkeit. 🙂

herbivore

3.728 Beiträge seit 2005
vor 18 Jahren

Original von LastGentleman
andere Frage,

wie kommt man bloß zu so einem Wissen?
Bücher, MSDN oder irgendwelchen Foren 😉.

Bücher sind die Grundlage. Am besten alle 3. Monate ein komplettes Buch zu einem Thema durcharbeiten. Bücher wie Inside C# von Microsoft Press vermitteln die C# Grundlagen (Typsystem, Sprachkonstrukte, Namespaces, Multithreading). Wenn man das geschluckt hat, sollte man spezialisierte Bücher lesen (z.B. über Datenbanken, Web-Entwicklung, Entwurfsmuster, Enterprise Services, BizTalk Server ect.).

Zusätzlich zu Büchern braucht man schnelle Informationsquellen zum nachschlagen und das Wissen vertiefen. In der Microsoft Welt ist die MSDN Library DAS Instrument dafür. Auch zu empfehlen sind die MSDN Webcasts. Das sind deutschsprachige Schulungsvideos zu allen möglichen Themen. Damit kann man sich schnell einen Überblick über die Technologieflut verschaffen ohne 20 Bücher zu lesen.

http://www.microsoft.com/germany/events/webcasts/ondemand.mspx

Außerdem ist es wichtig, viele verschiedene Konzepte und Entwurfsmuster zu kennen. Das wiederum verstehen viele Leute falsch. Die sehen irgendwo eine Beispielimplementierung eines Patterns und versuchen diese zwanghaft in ihren Projekten umzusetzen. Entwurfsmuster sind eher als Richtlinien zu sehen.

Das Kozept Vererbung z.B. ist immer das selbe. Hier ein Beispiel:



// Vererbung in C#
public class Child : Parent
{
    //  ... CODE
}


/* Vererbung in Java */
public class Child extends Parent
{
    /* ... CODE */
}


Nur die Syntax ist unterschiedlich. Die kleinen Feinheiten der einzelnen Sprachen/Plattformen (z.B. Mehrfachvererbung in C++) sind ein reiner Erfahrungswert.

Das ist auch der letzte Punkte in Sachen viel Wissen. Berufserfahrung! Ich z.B. entwicklte seit genau 10 Jahren Geschäftsanwendungen. Davon 5 Jahre in nebenberuflicher Selbständigkeit.

F
10.010 Beiträge seit 2004
vor 18 Jahren

Noch eine Lösung ist z.B. auf codeproject.com zu finden.

http://www.codeproject.com/useritems/How2LateBinding.asp

Und zum Wissen, es ist wie bei meinen forrednern.
Bei mir ist nach fast 20 Jahren als SW-Entwickler, davon 16 Hauptberuflich,
eine gewisse Sucht nach Informationen entstanden, die sich in
einem reichlich gefüllten Buchregal, aber auch in immer
grösser werdenden Linksammlungen zu interessanten Leuten(Blogs)
oder Seiten( z.B. codeproject, only4gurus ) ausdrückt.

Und je mehr Aufgaben ( andere sagen Probleme ) man löst, umsomehr
Aufgaben werden es 😉

LastGentleman Themenstarter:in
1.274 Beiträge seit 2005
vor 18 Jahren

Wenn ich eine nicht Typensichere Sprache wie VB.net nehmen, ohne mit Reflection zu arbeiten.

Es sollte nähmlich mit Word 2000, XP oder 2003 funktionieren.

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

P
939 Beiträge seit 2003
vor 18 Jahren

Hi LastGentleman,

ohne Reflection geht so (am Beispiel vom "Text To Speech" ActiveX-Control):

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

// Abgespecktes .Net-Interface für das "Text To Speech" ActiveX-Control.
[ComImport, Guid("2398E32E-5C6E-11D1-8C65-0060081841DE")]
public interface ITextToSpeech {
	int initialized { get; set; }
	void Speak(string text);
}

public class ComMarshalTest {

	[STAThread]
	static void Main() {
		
		// Den COM-Type mit ProgId="Vtext.Vtext" über die CLSID laden.
		// (Mit Type.GetTypeFromProgId hat es nicht funktioniert)
		Type vtextType = Type.GetTypeFromCLSID(
			new Guid("{2398E32F-5C6E-11D1-8C65-0060081841DE}"));

		// Instanz des COM-Types erstellen und ins .Net-Interface casten.
		ITextToSpeech vtext =
			(ITextToSpeech)Activator.CreateInstance(vtextType);

		// Sag irgendwas dämliches.
		vtext.Speak("All your base are belong to us!");

		// VText, als ActiveX-Control, benötigt zur 
		// Ausführung eine Fenster-Anwendung.
		Application.Run(new PrintPreviewDialog());
	}
}

Bitte beachten, dass die zwei im Code vorkommenden GUIDs unterschiedlich sind. Das eine ist die CLSID des COM-Interfaces ITextToSpeech, das andere die der für Automation registrierten CoClass TextToSpeechClass.

Um Folgeversionen eines COM-Interfaces zu unterstützen, sollte es möglich sein, das .Net-Interface abzuleiten und die neuere GUID anzugeben. Ich konnte es leider nicht testen, da "Text To Speech" nur eine Version hat. Ansonsten ist es glaube ich so, dass veraltete Interface-Versionen, um die Kompatibilität zu waren, nie entfernt und immer mitgeschleppt werden. Wenn du Glück hast, solltest du also ein Interface für Word 2000 auch mit Word 2003 nutzen können.

Der gleiche Code wird übrigens auch generiert, wenn man einen Verweis aus COM zu seinem Projekt hinzufügt (oder wenn man Tlbimp.exe verwendet). Um ehrlich zu sein, hab ich mir einfach den von Tlbimp.exe generierten Wrapper-Code genommen und alles, was für das Beispiel nicht benötigt wird, rausgeschmissen.

Gruss
Pulpapex