Announcement

Collapse
No announcement yet.

EOLEException: Eine Schnittstelle, die fuer einen anderen Thread marshalled war...

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

  • EOLEException: Eine Schnittstelle, die fuer einen anderen Thread marshalled war...

    Ich bekomme folgende Fehlermeldung:<br>
    'Eine Schnittstelle, die fuer einen anderen Thread marshalled war, wurde von der Anwendung aufgerufen.'<br>
    Ich werde mal versuchen, den Programmaufbau zu erklaeren:<br>
    Meine Anwendung hat einen TCP/IP-Socket, der von einer Javaanwendung eines Kollegen angesprochen wird. Fuer jede Verbindung wird in meiner Applikation eine Instanz der selbstgebauten Klasse TSession erzeugt. Jede Session wiederum baut eine DCOM-Verbingung zu einer weiteren Applikation auf, die letztendlich die eigentliche Arbeit verrichten soll. Jede Session erzeugt also eine private Instanz dieses COM-Servers. Es sollen aber mehrere Anfragen der Java-Applikation gleichzeitig verarbeitet werden koennen. Dazu habe ich die Methode TSession.Process gebaut. Diese Methode erzeugt einen eigenen Thread und fuehrt ihn aus. Hier der Code:<pre>
    procedure TSession.Process(...)
    begin
    {...}

    Thread := TSessionThread.Create(true);
    Thread.OnTerminate := OnThreadTerminated;
    Thread.OnExecute := OnExecuteThread;
    Thread.Resume;
    end;
    </pre>
    Die Methode TThread.Execute wiederum ruft eine Ereignisroutine auf, die TSession ueberschrieben hat. Die Methode CoInitialize wird dabei ebenfalls aufgerufen. Der Code von TThread.Execute sieht so aus:<pre>
    procedure TSessionThread.Execute;
    OleCheck(CoInitialize(nil));
    FThreadId := GetCurrentThreadId;
    try
    if Assigned(FOnExecute) then FOnExecute(Self);
    finally
    CoUnInitialize;
    end;
    end;
    </pre>
    Es wird also zu einer Methode von TSession gesprungen. Dort wird dann eine COM-Eigenschaft der privaten DCOM-Anwendung gelesen. Dabei tritt dann die oben erwaehnte Fehlermeldung auf. Wenn ich diese Eigenschaft direkt vom einer Methode von TSession aufrufe (also nicht den Umweg ueber den Thread gehe), gibt es keine Probleme.<br>
    Ich hoffe, dass ich den Programmaufbau einigermassen verstaendlich erlautern konnte.<br>
    Gibt es jemanden, der dieses Problem nachvollziehen konnte und auch noch eine Loesung kennt?

  • #2
    Ich habe das Problem zwar nicht behoben, sondern wie folgt umgangen:<br>
    Die Klasse TSession wird nun selbst von TThread abgeleitet. In der Methode Execute wird dann zuerst CoInitialize aufgerufen und dann die Verbindung zum COM-Server aufgebaut. Die Methode selbst wird nicht mehr verlassen, sondern 'wartet' auf Arbeit. Das sieht dann ungefaehr so aus:<pre>
    procedure TSessionThread.Execute;
    begin
    OleCheck(CoInitialize(nil));

    coFOK:= TcoFOK.Create(nil);
    coFOK.ConnectKind:= ckRunningOrNew;
    coFOK.Connect;

    try
    repeat
    if DoProcess then
    Process;

    sleep(10);
    until self.Terminated;

    finally
    if Assigned(coFOK) then begin
    coFOK.Disconnect;
    coFOK:= nil;
    end;

    CoUnInitialize;
    end;
    end;
    </pre>
    Wie zu sehen ist, befindet sich die Routine in einer Schleife, die erst verlassen wird, wenn TSession.Terminate aufgerufen wurde. Danach wird dann die Verbindung zum COM-Server getrennt und der Thread wird freigegeben. Die Verwendung von Sleep() ist sehr praktisch, da das Programm in dieser Zeit keine Rechenzeit benoetigt.<br>
    Das ist hier sicherlich nicht die eleganteste Loesung. Bleibt zu klaeren, was die oben erwaehnte Fehlermeldung aussagt und wie der Fehler umgangen werden kann

    Comment


    • #3
      Hallo,

      &gt;Jede Session wiederum baut eine DCOM-Verbingung zu einer weiteren Applikation auf...

      für den Zugriff auf COM-Objekte, die in einem anderen Prozess/Thread leben (was bei DCOM immer der Fall ist), benötigt das Betriebssystem Proxy- und Stub-Objekte, um die Verbindung herzustellen. Diese Hilfsobjekte baut das Betriebssystem automatisch zur Laufzeit zusammen. Der Interface-Zeiger darauf hat jedoch nur in dem Thread (Apartment) eine Gültigkeit, in dem dieser Zeiger angefordert wurde. Wenn die Anwendung einen Interface-Zeiger im Thread 1 anfordern und diesen in anderen Threads ebenfalls nutzen will, muss die Anwendung entweder auf die COM-Funktionen <b>CoMarshalInterThreadInterfaceInStream</b> und <b>CoGetInterfaceAndReleaseStream</b> oder auf die <b>Global Interface Table</b> (GIT) zurückgreifen, damit der <i>Marshaler</i> die Proxy-/Stub-Objekt entprechend anpassen kann. Die ganzen Details dazu können in meinem Buch <i>COM/DCOM/COM+ mit Delphi</i> nachgelesen werden

      Comment

      Working...
      X