Announcement

Collapse
No announcement yet.

Typbibliothek-Import in D7

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Typbibliothek-Import in D7

    Hallo,

    ich versuche gerade Andreas Kosch's Beispiel von der EKON7 nachzuvollziehen, in welchem gezeigt wird, wie ein D7-Client einen Enterprise-Service nutzt und von diesem ein ADO-RecordSet abfragt. Als Sprache für den "Server" habe ich C# gewählt, was allerdings keinen Unterschied machen sollte.

    Das Problem liegt darin, dass ich auf Delphiseite die Funktion zum Abrufen des DS nicht zur Verfügung gestellt bekomme. In der entstehenden ..._TLB.pas kann ich die Funktion jedenjalls nicht finden. Kann es sein, dass ich beim Import der .tlb unter D7 noch etwas beachten muss? (Unter D6 habe ich die z.B. gar nicht importieren können)

    Um Fehler meinerseits auszuschliessen, habe ich noch ein paar hoffentlich relevante Codeschnipsel:

    C#:<BR>
    ...<BR>
    public class AdoRecSetTestObject:ServicedComponent<BR>
    ...<BR>
    public ADODB.Recordset AdoRecordSetTest()<BR>
    {<BR>
    aRS = new ADODB.Recordset();<BR>
    ...<BR>
    return aRS;<BR>
    }<BR>
    <BR><BR><BR>
    Delphi7:<BR>
    ...<BR>
    // _AdoRecSetTestObject ging nicht, daher<BR>
    aSrv : AdoRecSetTestObject;<BR>
    aRS : _Recordset;<BR>
    begin<BR>
    aSrv := CoAdoRecSetTestObject.Create;<BR>
    aRS := aSrv.AdoRecordSetTest;<BR>
    ...<BR>
    <BR>
    Grüße und Dank im Voraus für jeden Hinweis,<BR>
    Daniel

  • #2
    Hallo,

    das folgende Minimal-Beispiel zeigt, wie ein .NET Enterprise Service ein gefülltes Recordset-Objekt an den Delphi 7-Client zurückliefert (die Klasse <i>OSLogError</i> schreibt nur die Fehlermeldung in die Ereignisanzeige und kann daher weggelassen werden):
    <pre>
    <b>public</b> <b>int</b> UniversalSelectRS(
    <b>string</b> sSQL,
    <b>ref</b> ADODB.Recordset aRS,
    <b>ref</b> <b>string</b> sMsg)
    {
    <b>int</b> iReturn = 0;
    <b>try</b>
    {
    ADODB.Connection aADOCon = <b>new</b> ADODB.Connection();
    aADOCon.ConnectionString = sCSADO;
    aADOCon.CursorLocation = ADODB.CursorLocationEnum.adUseClient;
    aADOCon.Open(sCSADO, <font color="#9933CC">&quot;&quot;</font>, <font color="#9933CC">&quot;&quot;</font>, 0);
    <b>try</b>
    {
    aRS = <b>new</b> ADODB.Recordset();
    aRS.CursorLocation = ADODB.CursorLocationEnum.adUseClientBatch;
    aRS.Open(sSQL, aADOCon, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockBatchOptimistic, 0);
    aRS.ActiveConnection = <b>null</b>;
    iReturn = 1;
    }
    <b>finally</b>
    {
    aADOCon.Close();
    Marshal.ReleaseComObject(aADOCon);
    }
    }
    <b>catch</b> (Exception aExc)
    {
    sMsg = aExc.Message;
    ContextUtil.SetAbort();
    OSLogError.WriteError(aExc.Message + Environment.NewLine + aExc.StackTrace);
    }
    <b>return</b> iReturn;
    }
    </pre>
    Die von Delphi 7 importierte Typbibliothek sieht an dieser Stelle dann so aus:
    <pre>
    <b>function</b> UniversalSelectRS(<b>const</b> sSQL: WideString; <b>var</b> aRS: _Recordset; <b>var</b> sMsg: WideString): Integer; <b>safecall</b>;
    </pre>
    Allerdings hat die Implementierung der C#-Klasse einen entscheidenden Einfluss darauf, welchen Interface-Aufbau Delphi 7 sieht. Der ideale Fall (den ich generell nutze) greift auf ein eigenes Interface zurück. Das hat die folgenden Vorteile: <br>
    1. Delphi 7 sieht nur die explizit im Interface veröffentlichten Methoden dieser Klasse <br>
    2. Über das Attribut <b>ClassInterface(ClassInterfaceType.None)</b> werden die "störenden" von .NET geerbten Methoden im COM-Interface dieser Klasse ausgeblendet.
    <pre>
    <b>using</b> System;
    <b>using</b> System.EnterpriseServices;
    <b>using</b> System.Runtime.InteropServices;
    <br>
    <b>namespace</b> NETTEST3
    {
    [Guid(<font color="#9933CC">&quot;14F755BD-A755-434D-9835-DB379793682C&quot;</font>)]
    <b>public</b> <b>interface</b> IAKCls3
    {
    <b>string</b> DoWork(<b>string</b> sInput);
    }
    <br>
    [TransactionAttribute(TransactionOption.NotSupporte d),
    ConstructionEnabled(<b>Default</b>=<font color="#9933CC">&quot;Test&quot;</font>),
    JustInTimeActivation(<b>true</b>),
    EventTrackingEnabled(<b>true</b>),
    DescriptionAttribute(<font color="#9933CC">&quot;NETTEST3&quot;</font>),
    Guid(<font color="#9933CC">&quot;581DEEDF-65F7-4043-A910-2B1DBDB2322A&quot;</font>),
    ClassInterface(ClassInterfaceType.None)]
    <b>public</b> <b>class</b> AKCls3: ServicedComponent,IAKCls3
    {
    <b>public</b> AKCls3()
    {
    <br>
    }
    <br>
    <b>public</b> <b>string</b> DoWork(<b>string</b> sInput)
    {
    ContextUtil.SetComplete();
    <b>return</b> sInput + <font color="#9933CC">&quot; (OK)&quot;</font>;
    }
    }
    }
    </pre>
    Wenn die eigene C#-Klasse <b>kein</b> eigenes Interface implementiert, muss die Unterstützung für ein Dual Interface über das Attribut der C#-Klasse (<b>ClassInterface(ClassInterfaceType.AutoDual)</b>) extra angefordert werden:
    <pre>
    <b>using</b> System;
    <b>using</b> System.EnterpriseServices;
    <b>using</b> System.Runtime.InteropServices;
    <br>
    <b>namespace</b> NETTEST3
    {
    [TransactionAttribute(TransactionOption.NotSupporte d),
    ConstructionEnabled(<b>Default</b>=<font color="#9933CC">&quot;Test&quot;</font>),
    JustInTimeActivation(<b>true</b>),
    EventTrackingEnabled(<b>true</b>),
    DescriptionAttribute(<font color="#9933CC">&quot;NETTEST3&quot;</font>),
    Guid(<font color="#9933CC">&quot;581DEEDF-65F7-4043-A910-2B1DBDB2322A&quot;</font>),
    ClassInterface(ClassInterfaceType.AutoDual)]
    <b>public</b> <b>class</b> AKCls3: ServicedComponent
    {
    <b>public</b> AKCls3()
    {
    <br>
    }

    <b>public</b> <b>string</b> DoWork(<b>string</b> sInput)
    {
    ContextUtil.SetComplete();
    <b>return</b> sInput + <font color="#9933CC">&quot; (OK)&quot;</font>;
    }
    }
    }
    </pre&gt

    Comment


    • #3
      <I>ClassInterface(ClassInterfaceType.AutoDual)] </I><br>
      Das war der Trick<br>
      <br>
      Danke

      Comment

      Working...
      X