Complex Collections with Gupta COM

In the last blog post, I described how to pass complex parameters in Gupta COM functions. Another major problem is to pass arrays of complex data structures such as orders and their positions. So far I had two solutions with neither I was happy with. One of them was to serialize data in JSON format and passing the resulting string. The other to create a SafeArray for each element of the data structure and then wrap it in a variant to pass it to COM.

Collections

Guptas COM Class Wizard offers a third option: A COM object where its interface is marked as a collection (see check box).
ComWizardCollection

ComWizardCollection

 

Sample Project

The turn: With my example I would like to
  • build a rudimentary order class consisting of orderid, customer and date
  • and an arbitrarily long list of order items consisting of articles and price defined as a complex data structure
  • provide a list of order records from a service class

OrderDetails

First a class called OrderDetailItem is defined with the COM-Wizard with the properties Article (String) and Price (Number) as described similarly in the blogpost complex parameter with Gupta COM.

OrderDetailItem

OrderDetailCollection

Then create a second class called OrderDetailCollection and check the property „Collection“.

OrderDetailCollection

Next, one has to specify the data type of the collection. For our example that is the class OrderDetailItem created above.

OrderDetailCollectionType

If you look at the resulting program code you can see that the collection consists of an array of OrderDetailItems. The array is not directly addressable in COM. Instead one can access it through the COM functions Item(..), Add(..), and Remove(..). Also one can read the property „Count“.

Unfortunately the wizard generates code with a small but crucial mistake: the internal array m_aCollection [*] is of type IOrderDetailItem. As described in the last blog post for „Instance Variables“ one has to use the CoClass  (the one without the leading I). One has to fix that manually otherwise one gets error messages at run time. By the way with the Gupta IDE (version 3.1) one cannot simply remove the „I“. Instead one has to remove the entire line and rewrite it correctly: OrderDetailItem: m_aCollection [*]

OrderDetailCollectionCode

OrderItem

The order record in the example has the properties Id (number), Customer (String), Date (Date/Time) and – tadaa – OrderDetails of type IOrderDetailCollection.

OrderItemWizard

But even here the wizard makes a mistake: the instance variable must be of type OrderDetailCollection (CoClass). Instead the wizard creates an InterfaceVar what even causes a compile error. The data types in the return value and parameters (PropSet – and PropGet- functions) however are correct (IOderDetailCollection).

OrderItemCode

OrderCollection

For this sample I want to pass a list of orders. So we generate a collection of type OrderItem. Again one has to fix the type of the variable m_aCollection [] to the CoClass (the one without the „I“).

Service

Finally a service COM class is created with the function „GetOrderCollection“ which returns the OderCollection defined above. Usually, of course, the data comes from a database. However, for the sample project I wrote functions that assign random values to all properties.

Consumer

As a consumer, I have created a WinForm application with the freely available Visual Studio 2012 Express Edition (desktop). The registered COM object is included as a reference. The application brings up a list of sample orders created by our COM object and depicts it in a TreeView control.

ComComplexCollectionConsumer

Download

All of the projects described in the blog are included in file ComComplexCollection.zip:

  • The Gupta 3.1 project „ComComplexCollection“
  • The VisualStudio project „ComComplexCollectionConsumer“
  • An executable demo application (assuming Gupta 3.1 runtime).

Happy Coding

Advertisements

Complex Collections mit Gupta COM

Im letzten Blogpost habe ich beschrieben, wie komplexe Parameter in COM-Funktionen übergeben werden können. Ein weiteres großes Problem íst die Übergabe von Arrays komplexer Datenstrukturen, wie z.B. Aufträge und deren Positionen. Bislang hatte ich dafür zwei Lösungen, mit denen ich aber nicht zufrieden war. Eine davon ist, die Daten im JSON-Format zu serialisieren und den resultierenden String zu übergeben. Die andere, jedes einzelne Element der Datenstruktur als SafeArray anzulegen, das wiederum in einen Variant verpackt werden muss, um es an COM übergeben zu können.

Collections

Der COM-Class-Wizard bietet noch eine dritte Möglichkeit an: Ein COM-Objekt, dessen Interface als Collection gekennzeichnet wird (siehe Checkbox).

ComWizardCollection

ComWizardCollection

Das Beispielprojekt

Der Reihe nach: Im Beispiel möchte ich

  • eine rudimentäre Auftrag-Klasse bestehend aus AuftragNr, Kunde und Datum,
  • sowie einer beliebig langen Liste von Auftragspositionen bestehend aus Artikel und Preis als komplexe Datenstruktur definieren.
  • Eine Service-Klasse soll eine beliebig große Liste von Auftragsdatensätzen liefern können

OrderDetails

Zuerst wird mit dem COM-Wizard die Klasse OrderDetailItem mit den Propertys Article (String) und Price (Number) definiert. Analog, wie es im Blogpost Complex Parameters mit Gupta COM beschrieben ist.

OrderDetailItem

OrderDetailCollection

Anschließend wird mit dem Wizard eine zweite Klasse OrderDetailCollection erstellt. Dieser wird die Eigenschaft „Collection“ zugewiesen.

OrderDetailCollection

Im nächsten Schritt gibt man im Wizard den Datentyp der Collection an. Für unser Beispiel ist das die oben erstellte Klasse OrderDetailItem.

OrderDetailCollectionType

Schaut man sich den resultierenden Programmcode an, dann sieht man, dass die Collection aus einem Array von OrderDetailItems besteht. Dieses ist in COM nicht direkt ansprechbar. Stattdessen kann man über die COM-Funktionen Item, Add und Remove darauf zugreifen, ebenso kann man auf das Property „Count“ lesend zugreifen.

Leider macht der Wizard bei der Code-Erzeugung einen kleinen, aber entscheidenden Fehler: Das interne Array m_aCollection[*] ist vom Typ IOrderDetailItem. Wie schon im letzten Blogpost beschrieben, muss als „Instance Variable“ die CoClass ohne das führende I verwendet werden. Das muss man also manuell korrigieren, ansonsten erhält man Fehlermeldungen zur Laufzeit. Übrigens lässt die Gupta-IDE (Version 3.1) nicht zu, dass man einfach das I löscht. Stattdessen muss die ganze Zeile gelöscht und neu geschrieben werden: OrderDetailItem: m_aCollection[*]

OrderDetailCollectionCode

OrderItem

Der Auftragsdatensatz besteht im Beispiel aus den Feldern Id (Number), Customer (String), Date (Date/Time) und – tadaaa – den Auftragspositionen vom Typ IOrderDetailCollection.

OrderItemWizard

Aber auch hier macht der Wizard einen Fehler: Die Instance Variable muss vom Typ OrderDetailCollection sein. Der Wizard erzeugt stattdessen eine InterfaceVar, was sogar zu einem Compile-Fehler führt. Die Datentypen im Returnwert und Parameter in den PropSet- und PropGet-Funktionen dagegen sind mit IOderDetailCollection korrekt.

OrderItemCode

OrderCollection

Im Beispiel soll eine Liste von Aufträgen übergeben werden, also erzeugen wir noch eine Collection, dieses Mal vom Typ OrderItem. Auch hier muss der Typ der Variablen m_aCollection[] auf die CoClass geändert werden (ohne I).

Service

Zu guter Letzt wird ein COM-Service-Klasse erstellt, deren Funktion „GetOrderCollection“ die oben definierte Collectionklasse zurückgibt. Üblicherweise kommen die Dateninhalte natürlich aus einer Datenbank. Für das Beispielprojekt habe ich Funktionen geschrieben, die den Propertys Zufallswerte zuweisen.

Consumer

Als Consumer habe ich mit der kostenlosen Visual Studio 2012 Express Edition (Desktop) eine WinForm-Applikation erstellt. Das registrierte COM-Objekt wird als Verweis eingebunden. Die Applikation holt eine Liste von Sample-Aufträge aus dem oben erstellen COM-Objekt ab und bildet sie in einem TreeView-Control ab.

ComComplexCollectionConsumer

Download

Alle im Blog beschriebenen Projekte sind in Datei ComComplexCollection.zip  enthalten:

  • Das Gupta 3.1-Projekt „ComComplexCollection“
  • Das VisualStudio-Projekt „ComComplexCollectionConsumer“
  • Eine lauffähige Demo-Applikation (Gupta 3.1-Runtime vorausgesetzt).

Happy Coding

Complex Parameter with Gupta-COM

With the Gupta Team Developer you can create COM objects so that you can use the functionality in other languages such as C# ­. How this works is described in this article https://thomasuttendorfer.wordpress.com/2010/06/17/von-apd-uber-com-nach-soap-teil-1/ .

So far I had always used the generic data types String, DateTime and Number in COM functions as a return value or parameter. Receive parameters are also possible and necessary if you want to pass e.g. a data set. However, the parameter lists of COM functions are often long and unwieldy. Maintaining, expanding and using these functions is cumbersome and error-prone. The wish to be able to pass complex parameters – as classes and their member variables – was getting bigger. Fortunately, the Gupta IDE offers a solution: you can create another COM object, define the required data elements as properties, and then use it as a function parameter in a COM function.

Properties in COM-Objects

Using the COM-Wizard (component / wizards / COM class) create a CoClass named „ComplexParameter“.

ComComplexParameters01_Wizard01

In the next step the properties are added. In my example each one for the data types of String, DateTime and Number. I chose  „Set/Get“ in the section „Declaration“. Looking at the program code generated by the wizard you can see what it’s all about.

ComComplexParameters02_Wizard02_Properties

The code generated by the wizard is remarkable: For each property, an Instance Variable m_PropertyName has been created as well as two functions named PropSetPropertyName and PropGetPropertyName.

ComComplexParameters03_WizardGeneratedCode

Referencing the COM object e.g. in a Visual Studio project, the properties appear again as thought: as ordinary member variables of the object. You can’t see the ‚ PropSet/PropGet ‚ functions. Those were automatically identified as „Setters“ and „Getters“ and will be used from the .NET Framework as such. They are called implicitly when assigning or setting the property value.

Information about the concept for Getters und Setters can be found here http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx

ComComplexParameters04_NetObjectCatalog

Sample Functions

To complete the example I create yet a COM service class with two functions which use the above generated COM data object as a parameter. In the GetSampleComplexParameter(..) function it is passed as return value and in the function SaveComplexParameter(..) the COM data object is used as a function parameter. Please note following rule which is not documented anywhere but is crucial for the functioning of the COM object: If you use a COM object as a return value or Parameter you have to use the Interface of the COM object in the declaration of the return value or parameter. Use the COM class, which is initiated with the „I“. But when you „work“ with COM dataobject – as a „local variable“ or „static variable“ – use the COM class without the leading „I“. This is evident in the program code of the function „GetSampleComplexParameter“ below: the return value is of the type IComplexParameter. The local variable that is returned is of type ComplexParameter. If you don’t consider this rule you will get errors when using COM object.

ComComplexParameters05_ServiceClass

WinForm-Application

To demonstrate the functionality, I wrote a WinForm application called „UsingComComplexParameters“ in C#  which integrates the Gupta-COM object and calls its two service functions.

ComComplexParameters06_WinFormSample

Downloads

The zip file ComComplexParameters.zip contains the full demo with source files:

The zip file ComComplexParameters.zip contains the full demo including source files:

  • The Gupta-Project „ComComplexParameter“,
  • the WinForm-Application „UsingComComplexParameter“
  • as well as a working demo „WorkingDemo“ with a batch script  „InstallAndRunComComplexParameterDemo.bat“ which registers the COM object, calls the WinForm app and cleans up afterwards.

ComComplexParameters07_Download

Happy coding.

Komplexe Parameter mit Gupta-COM

Mit dem Gupta Team Developer lassen sich COM-Objekte erzeugen, so dass man deren Funktionalität in anderen Programmiersprachen – z.B. C# –­ nutzen kann. Wie das geht, ist im Artikel https://thomasuttendorfer.wordpress.com/2010/06/17/von-apd-uber-com-nach-soap-teil-1/ beschrieben.

Bislang hatte ich in den COM-Funktionen stets die generischen Datentypen String, DateTime und Number als Rückgabewert oder Parameter verwendet. Receive-Parameter sind ebenfalls möglich und nötig, wenn man z.B. einen kompletten Datensatz übergeben möchte. Allerdings sind die Parameterlisten der COM-Funktionen dann oft lang und unübersichtlich. Die Pflege, das Erweitern und Verwenden dieser Funktionen ist lästig und fehleranfällig. Der Wunsch, komplexe Parameter – also Klassen und deren Instance-Variablen – übergeben zu können, wurde immer größer. Erfreulicherweise bietet die Gupta-IDE genau dafür eine Lösung: Man kann ein weiteres COM-Objekt erzeugen, die gewünschten Datenelemente als Propertys definieren und es dann als Funktionsparameter in einer COM-Funktion verwenden.

Propertys in COM-Objekten

Über den COM-Wizard (Component / Wizards / COM Class) erstellt man eine CoClass – im Beispiel mit dem Namen “ComplexParameter”

ComComplexParameters01_Wizard01

Im nächsten Schritt werden die Properties hinzugefügt – hier jeweils eines für die Datentypen String, DateTime und Number. Im Beispiel habe ich mich in der Sektion „Declaration“ jeweils für „Set/Get“ entschieden. Was es damit auf sich hat sieht man Programmcode den der Wizard am Ende erzeugt.

ComComplexParameters02_Wizard02_Properties

Der vom Wizard erzeugte Programmcode ist bemerkenswert: Für jedes Property hat er eine Instancevariable m_PropertyName sowie zwei Funktionen PropSetPropertyName und PropGetPropertyName erstellt.

ComComplexParameters03_WizardGeneratedCode

Bindet man das COM-Objekt z.B in ein Visual Studio-Projekt ein, tauchen die Properties wieder so auf, wie gedacht: Als ganz normale Membervariablen des Objekts. Die „PropSet/PropGet“-Funktionen sieht man nicht. Sie werden automatisch als „Setter“ bzw. „Getter“ identifiziert und vom .NET-Framework als solche verwendet. Sie werden implizit bei Wertzuweisungen bzw. beim Abrufen des Property-Werts gerufen.

Infos zum Konzept der Getter und Setter z.B. in der MSDN-Library http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx

ComComplexParameters04_NetObjectCatalog

Beispielfunktionen

Um das Beispiel zu komplettieren, erstelle ich noch eine COM-Service-Klasse mit zwei Funktionen, die das oben erzeugte COM-Datenobjekt als Parameter verwendet. In der Funktion GetSampleComplexParameter(..) wird das COM-Datenobjekt als Returnwert verwendet, in der Funktion SaveComplexParameter(..) wird er als Funktionsparameter übergeben. Zu beachten ist folgende Regel, die meines Wissens nirgends dokumentiert, aber entscheidend für das Funktionieren des COM-Objeks ist: Verwendet man ein COM-Objekt als Returnwert oder Parameter, muss in der Funktionsdeklaration das Interface verwendet werden, also die COM-Klasse, die mit dem „I“ eingeleitet wird. Arbeiten muss man aber mit der CoClass – also als „Local Variable“ oder „Static Variable“ muss die COM-Klasse ohne das führende „I“ verwendet werden. Deutlich wird das im Programmcode der Funktion „GetSampleComplexParameter“: Der Returnwert ist vom Typ IComplexParameter – die lokale Variable, die zurückgegeben wird ist vom korrespondierenden Typ ComplexParameter. Beachtet man diese Regel nicht, erhält man beim Verwenden des COM-Objekts Fehler.

ComComplexParameters05_ServiceClass

WinForm-Applikation

Um die Funktionalität demonstrieren zu können, habe ich noch eine WinForm-Applikation namens „UsingComComplexParameters“ in C# geschrieben, die das Gupta-COM-Objekt einbindet und deren beiden Service-Funktionen aufruft:

ComComplexParameters06_WinFormSample

Downloads

Die Zip-Datei ComComplexParameters.zip enhält das vollständige Demo inklusive Quelldateien:

  • Das Gupta-Projekt „ComComplexParameter“,
  • die WinForm-Applikation „UsingComComplexParameter“
  • sowie eine lauffähige Demo „WorkingDemo“ mit einer Batch „InstallAndRunComComplexParameterDemo.bat“, die das COM-Objekt registriert, die WinForm-App aufruft und anschließend wieder aufräumt.

ComComplexParameters07_Download

Happy coding.