Announcement

Collapse
No announcement yet.

ConnectionStrings in COM Objekten

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

  • ConnectionStrings in COM Objekten

    Hallo,

    ich brauche mal einen Tipp aus der Praxis.

    Eine Applikation benutzt diverse Prozeduren, Funktionen oder Dialoge aus DLL’s bzw COM (COM+) Objekten. Jede dieser „externen“ Prozeduren benötigt
    einen ConnectionString. In allen Beispielen die ich so gefunden habe,
    wird der ConnectionString jeweils als Konstante deklariert, was natürlich in der Praxis keinen Sinn macht. Jedesmal eine UDL Datei zu lesen scheidet aus Performacegründen aus. Bei jedem Aufruf einen Conectionstring als Parameter zu übergeben ist auch nicht so der Hit.

    Hat jemand eine praxisnahe Lösung für diese Aufgabe?

    Knut

  • #2
    hi

    schon probiert, die Connection zu übergeben?
    <PRE>
    with myAdoDataSet do begin
    active := false;
    Connection := MyConnection;
    ....
    </PRE>
    gruß
    Bernhar

    Comment


    • #3
      Hallo,

      &gt;Hat jemand eine praxisnahe Lösung für diese Aufgabe?

      Im Fall eines COM+ Objekts würde ich zum <b>Constructor String</b> greifen: Im Eigenschaftsdialog des COM+ Objekt wird auf der Registerseite <i>Aktivierung</i> die Checkbox <b>Objektkonstruktion aktivieren</b> angekreuzt - darauf hin kann im Eingabefeld rechts daneben die eigene Verbindungszeichenfolge eingetragen werden. Immer dann, wenn eine Instanz des COM+ Objekt erzeugt wird, ruft das Betriebssystem unmittelbar darauf das COM+ Objekt über das Interface <b>IObjectConstruct</b> auf, um die Zeichenkette zu übergeben. Wenn viele Objekte diese Daten benötigten, würde ich ein spezielles COM+ Objekt vorsehen (ggf. aktiver Objektpool mit minimal/maximal 1 Instanz), dass von allen anderen nach der aktuellen Verbindungszeichenfolge "befragt" wird. Somit muss der Verbindungsdialog im Eigenschaftsdialog nur ein einziges Mal geändert werden.

      Das sieht am praktischen Beispiel so aus:
      <pre>
      unit DE2001SrvThin_Impl;
      {$WARN SYMBOL_PLATFORM OFF}
      interface
      uses
      ActiveX, Mtsobj, Mtx, ComObj, DE2001SrvThin_TLB, StdVcl,
      ADODB_TLB, COMSVCSLib_TLB;
      type
      TDE2001SrvThinObj = class(TMtsAutoObject, IDE2001SrvThinObj, IObjectConstruct)
      private
      FConnStr : WideString;
      protected
      { IObjectConstruct }
      function Construct(const pCtorObj: IDispatch): HResult; stdcall;
      { IDE2001SrvThinObj }
      function CustAddr(iCustID, iAddrType: Integer; out sAddrRow1, sAddrRow2,
      sAddrStr, sAddrHnr, sAddrPLZ, sAddrOrt: WideString): Integer;
      safecall;
      function CustomerRS: _Recordset; safecall;
      { Protected-Deklarationen }
      end;
      implementation
      uses Classes, SysUtils, ComServ, Variants;
      type
      TTNAAutoObjectFactory = class(TAutoObjectFactory)
      procedure UpdateRegistry(Register: Boolean); override;
      end;

      procedure TTNAAutoObjectFactory.UpdateRegistry(Register: Boolean);
      var
      sClassID, sServerKeyName: String;
      begin
      inherited UpdateRegistry(Register);
      if Register then
      begin
      if Instancing = ciInternal then Exit;
      sClassID := GUIDToString(ClassID);
      sServerKeyName := 'CLSID\' + sClassID + '\' + ComServer.ServerKey;
      if (ThreadingModel <> tmSingle) and IsLibrary then
      CreateRegKey(sServerKeyName, 'ThreadingModel', 'Neutral');
      end;
      end;

      { ----------------------------------------------------------- }
      { IObjectConstruct }
      { ----------------------------------------------------------- }

      function TDE2001SrvThinObj.Construct(const pCtorObj: IDispatch): HResult;
      resourcestring
      cCS = 'Provider=SQLOLEDB.1;Password=%s;Persist Security Info=True;' +
      'User ID=%s;Initial Catalog=%s;Data Source=%s';
      var
      aOC : IObjectConstructString;
      sTxt : WideString;
      aSL : TStringList;
      begin
      try
      aOC := pCtorObj as IObjectConstructString;
      sTxt := aOC.ConstructString;
      aSL := TStringList.Create;
      try
      with aSL do
      begin
      CommaText := sTxt;
      FConnStr := Format(cCS, [Strings[3], Strings[2],
      Strings[1], Strings[0]]);
      end;
      finally
      aSL.Free;
      end;
      Result := S_OK;
      except
      Result := E_UNEXPECTED;
      end;
      end;

      { ----------------------------------------------------------- }
      { IDE2001SrvExObj }
      { ----------------------------------------------------------- }

      function TDE2001SrvThinObj.CustAddr(iCustID, iAddrType: Integer;
      out sAddrRow1, sAddrRow2, sAddrStr, sAddrHnr, sAddrPLZ,
      sAddrOrt: WideString): Integer;
      var
      aConnection : _Connection;
      aCommand : _Command;
      aParam : _Parameter;
      vRowsAffected : OleVariant;

      procedure AddParamObj(const sName: String; iType,iParam,iSize: Integer);
      var
      aParam : _Parameter;
      begin
      with aCommand do
      begin
      aParam := CreateParameter(sName, iType, iParam,iSize, EmptyParam);
      Parameters.Append(aParam);
      end;
      end;

      begin
      try
      aConnection := CoConnection.Create as _Connection;
      aConnection.Open(FConnStr, '', '', adOpenForwardOnly);
      try
      aCommand := CoCommand.Create;
      try
      try
      with aCommand do
      begin
      Set_ActiveConnection(aConnection);
      CommandType := adCmdStoredProc;
      Set_CommandText('spCustAddr');
      end;
      // Rückgabewert
      AddParamObj('RETURN_VALUE', adInteger, adParamReturnValue, 4);
      // Input-Parameter
      AddParamObj('@CustID', adInteger, adParamInput, 4);
      AddParamObj('@AddrType', adInteger, adParamInput, 4);
      // Output-Parameter
      AddParamObj('@AddrRow1', adVarChar, adParamOutput, 35);
      AddParamObj('@AddrRow2', adVarChar, adParamOutput, 35);
      AddParamObj('@AddrStr', adVarChar, adParamOutput, 35);
      AddParamObj('@AddrHnr', adVarChar, adParamOutput, 10);
      AddParamObj('@AddrPLZ', adVarChar, adParamOutput, 5);
      AddParamObj('@AddrOrt', adVarChar, adParamOutput, 35);
      with aCommand do
      begin
      // Parameter-Werte zuweisen
      Parameters.Item[1].Value := iCustID;
      Parameters.Item[2].Value := iAddrType;
      // Stored Procedure ausführen
      Execute(vRowsAffected, EmptyParam, adExecuteNoRecords);
      // Rückgabewert auslesen
      Result := Parameters.Item[0].Value;
      // OUTPUT-Parameter auslesen
      with Parameters do
      begin
      sAddrRow1 := VarToStr(Item[3].Value);
      sAddrRow2 := VarToStr(Item[4].Value);
      sAddrStr := VarToStr(Item[5].Value);
      sAddrHnr := VarToStr(Item[6].Value);
      sAddrPLZ := VarToStr(Item[7].Value);
      sAddrOrt := VarToStr(Item[8].Value);
      end;
      end;
      except
      {
      on E: Exception do
      LogCommandException(E, aCommand);
      }
      raise
      end;
      finally
      aCommand := nil;
      end;
      finally
      aConnection.Close;
      end;
      SetComplete;
      except
      SetAbort;
      raise
      end;
      end;

      function TDE2001SrvThinObj.CustomerRS: _Recordset;
      var
      aConnection : _Connection;
      aRecordSet : _RecordSet;
      begin
      try
      aConnection := CoConnection.Create as _Connection;
      aConnection.CursorLocation := adUseClient;
      aConnection.Open(FConnStr, '', '', adOpenForwardOnly);
      try
      aRecordSet := CoRecordSet.Create as _RecordSet;
      try
      aRecordSet.CursorLocation := adUseClient;
      aRecordSet.Open('select CustID, CustName from Customer',
      aConnection, adOpenStatic,
      adLockBatchOptimistic, 0);
      Result := aRecordSet;
      aRecordSet._Set_ActiveConnection(nil);
      finally
      aRecordSet := nil;
      end;
      finally
      aConnection.Close;
      end;
      SetComplete;
      except
      SetAbort;
      raise
      end;
      end;

      initialization
      {
      TAutoObjectFactory.Create(ComServer, TDE2001SrvThinObj, Class_DE2001SrvThinObj,
      ciMultiInstance, tmApartment);
      }
      TTNAAutoObjectFactory.Create(ComServer, TDE2001SrvThinObj, Class_DE2001SrvThinObj,
      ciMultiInstance, tmApartment);
      end.
      </pre>
      P.S: In meinem Buch <i>COM/DCOM/COM+ mit Delphi</i> und in meinem Buch <i>ADO und Delphi</i> wird das Ganze ausführlicher beschrieben - dort sind auch die vollständigen Beispielprojekte zu finden

      Comment


      • #4
        Hallo Herr Kosch,

        erst einmal vielen Dank für Ihren unermüdlichen Einsatz im Forum. Hat mir schon einige male geholfen.

        Hab Ihr Vorgehen in Ihren Büchern nachgeschlagen und konnte Ihren Vorschlag mit dem zusätzlichen Objekt auch erfolgreich umsetzen.

        Das daraus resultierende Problem ist hier etwas "off-topic". Ich kann speziell dieses Objekt nicht auf dem Server (W2K) installieren.
        Unter Windows XP funktioniert das einwandfrei. Ich erhalte die Meldung:

        Mindestens eine Datei enthält keine Komponente oder Typenbibliothek. Diese Dateien können nicht installiert werden.

        Im Ereignisprotokoll erhalte ich die Event-ID: 11928. In der MS-KB kann ich dazu nichts Gescheites zu finden.

        Zusätzliche Frage:
        Wieso kann ein unter XP erzeugtes COM+ Install (MSI) nur in W2K installiert werden, wenn ich COM+ Version 1.0 aktiviere?

        Knut Lamber

        Comment


        • #5
          Hallo,

          &gt;Ich kann speziell dieses Objekt nicht auf dem Server (W2K) installieren.

          Tritt dieser Effekt auch dann auf, wenn das COM+ Objekt auf dem W2K-Rechner von Hand in eine COM+ Anwendung installiert wird? Diese Fehlermeldung habe ich noch nicht zu Gesicht bekommen (alle meine COM+ Objekte werden unter XP erzeugt und auf einem Windows 2000 Server installiert).

          &gt; .. unter XP erzeugtes COM+ Install (MSI) nur in W2K installiert werden..

          Ich gehe immer so vor, dass ich die Komponenten auf meinem Windows 2000 Testserver von Hand einrichte und das MSI-Setup danach von dort aus anlege. Somit muss ich niemals ein COM+1.5-Setup (XP) auf COM+ 1.0 (Windows 2000) einspielen

          Comment

          Working...
          X