3

i have an ADO Recordset object that is created in a background thread:

var
   conn: TADOConnection;
   rs: _Recordset;
begin
   conn := CreateDatabaseConnection();
   rs := conn.Execute(CommandText, cmdText, []);
   conn.Free;

   //Give the recordset to the UI thread
   //Don't forget to add a reference before we stuff it into a 32-bit variable
   rs._AddRef();
   PostMessage(hwndUIThreadWindow, WM_HeresTheRecordsetYouAskedFor, WPARAM(rs), 0);
end;

And then the Recordset is handed to my "main" thread:

procedure ExecuteComplete(var msg: TMessage); message WM_HeresTheRecordsetYouAskedFor;
var
   rs: _Recordset;    
begin
   rs := _Recordset(msg.wParam);
   //don't forget to remove the manually added reference
   rs._Release();

   ShowMessage(rs.Fields['TheTimeIs'].Value);
end;

i also could have done:

var 
   global_Recordset: _Recordset;

var
   conn: TADOConnection;
begin
   conn := CreateDatabaseConnection();
   global_Recordset := conn.Execute(CommandText, cmdText, []);
   conn.Free;
end;

Either way, a thread that didn't create the COM object is now using it. From the main thread:

global_Recordset .Fields['TheTimeIs'].Value;

COM forbids accessing COM objects from apartments (in this case: threads) that did not create the object.

What is the correct way to marshal in in-process COM object interfaces across apartment boundaries?

4

1 回答 1

4

跨单元传递 COM 对象的正确方法是编组接口指针,这可以通过以下两种不同方式之一完成:

  1. 让工作线程调用该CoMarshalInterThreadInterfaceInStream()函数并将结果IStream指针传递给 UI 线程,然后 UI 线程调用该CoGetInterfaceAndReleaseStream()函数。

  2. 使用IGlobalInterfaceTable界面。让工作线程创建接口并调用其RegisterInterfaceInGlobal()方法并将生成的 cookie 传递给 UI 线程,然后由 UI 线程创建接口并调用其GetInterfaceFromGlobal()RevokeInterfaceFromGlobal()方法。

于 2013-06-28T01:21:40.890 回答