COM Object aus Thread ansprechen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Eclipticon
Beiträge: 292
Registriert: Sa 5. Feb 2011, 20:38
OS, Lazarus, FPC: Windows XP VirtualBox (FPC 2.6.4, Laz 1.2.4)
CPU-Target: 32Bit
Wohnort: Wien

COM Object aus Thread ansprechen

Beitrag von Eclipticon »

Hi,

eine eigene Klasse B kapselt ein COM-Object eines Drittanbieters (das einem NDA unterliegt, daher muss ich mich hier ein wenig kryptisch ausdruecken, sorry). Ich erzeuge eine globale Instanz von B.

Wenn ich aus dem Main Thread ueber Methoden und Eigenschaften von B auf das COM-Object zugreife, funktioniert das wunderbar ... wenn ich aber einen anderen Thread erzeuge, und darauf auf die Instanz von B zugreife, kommen Exceptions, die offenbar aus dem COM-Object stammen und die fuer mich inhaltlich wenig Sinn machen.

Kann mir jemand dieses Verhalten erklaeren oder mir sogar verraten, was ich dagegen tun kann?

Danke :-)

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Re: COM Object aus Thread ansprechen

Beitrag von theo »

Eclipticon hat geschrieben: was ich dagegen tun kann?
Lesen. Hab's auch nicht mehr drauf, würde aber im Dunstkreis OleInitialize(nil) oder CoInitializeEx(nil,COINIT_MULTITHREADED) mal googeln.

http://www.techvanguards.com/com/concep ... eading.asp" onclick="window.open(this.href);return false;

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: COM Object aus Thread ansprechen

Beitrag von mschnell »

Ob und in wie weit ein Com-Objet threadfest ist, muss der Hersteller spezifizieren.

Da gibt es mehrere Möglichkeiten. Unter anderem:
- alle aufrufbaren Funktionen sind voll Thread fest: Du darfst jede immer aus einem beliebigen Thread aufrufen.
- überhaupt nicht threadfest. Alles darf nur im Mainthread aufgerufen werden.
- manche Funktionen sind teilweise threadfest: Hier muss das Verhalten im Einzelnen dokumentiert werden. Es kann z.B. sein, dass eine Gruppe von Funktion nur in einem gemeinsamen Thread aufgerufen werden darf oder dass eine Funktion irgendetwas instanziiert und einen Pointer oder Handel zurückgibt und der Zugriff auf Funktionen, denen dieser Pointer/Handel übergeben wird, nur in dem Thread erlaubt ist, der das Ding instanziiert wurde oder derselbe Handel nicht "concurrent" in verschiedenen Threads verwendet werden darf, aber er dann in verschiedenen Threads verwendet werden darf, wenn eine Absicherung über Critical Sections erfolgt.

Ohne vernünftige Doku des Com-Objects ist man da aufgeschmissen.

-Michael

Eclipticon
Beiträge: 292
Registriert: Sa 5. Feb 2011, 20:38
OS, Lazarus, FPC: Windows XP VirtualBox (FPC 2.6.4, Laz 1.2.4)
CPU-Target: 32Bit
Wohnort: Wien

Re: COM Object aus Thread ansprechen

Beitrag von Eclipticon »

Hallo Theo, hallo Michael,

danke fuer die Hinweise ... mit CoInitializeEx hast natuerlich recht, und ja, ich bin aufgeschmissen, weil es keine vernuenftige Dokumentation des COM-Objects gibt.

Ich habe mal mit folgendem Minimalcode

Code: Alles auswählen

unit ThreadTestMain;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, windows, SysUtils, Forms, StdCtrls, Instrument, comobj, ActiveX;
 
type
  TTestThread = class(TThread)
  protected
    procedure Execute; override;
  end;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  end;
 
var
  Form1: TForm1;
 
implementation
 
var
  ResultText: string;
 
procedure TTestThread.Execute;
var
  j: integer;
  Success: HRESULT;
begin
 
  Success := CoInitializeEx(nil, COINIT_MULTITHREADED);
  if (Success <> S_OK) or (Success <> S_FALSE)
    then Exception.Create('Not s_ok or s_false');
 
  for j := 1 to 100 do
  begin
    if AInstrument.SomeStatus then // <-- Strange exceptions from COM-Object at this line
      ResultText := ResultText + 'T'
    else
      ResultText := ResultText + 't';
  end;
 
  CoUninitialize;
 
end;
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
var
  ATestThread: TTestThread;
  i: integer;
begin
 
  ATestThread := TTestThread.Create(True);
 
  for i := 1 to 100 do
  begin
    if AInstrument.SomeStatus then
      ResultText := ResultText + 'B'
    else
      ResultText := ResultText + 'b';
    if (i = 23) then
      ATestThread.Start;
  end;
 
  ATestThread.WaitFor;
 
  if Assigned(ATestThread.FatalException) then
    raise Exception.Create(':-(');
 
  FreeAndNil(ATestThread);
 
  Label1.Caption := ResultText;
 
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  AInstrument := TInstrument.Create; // AInstrument is global
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(AInstrument);
end;
 
end.
das Problem reproduzieren koennen. Sehr ihr hier einen offensichtlichen Fehler?

Ich habe ja das COM-Object in AInstrument gekapselt ... und interessanterweise habe ich mit den Threads, die ich in der TInstrument-Klasse starte und die auch das COM-Object verwenden, noch nie Probleme gehabt. Nur wenn ich AInstrument anspreche ...

Danke fuer Euren Input!

Antworten