How to pass an ADO Recordset (or any COM object) a

2019-07-03 18:43发布

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?

标签: delphi com ado
1条回答
【Aperson】
2楼-- · 2019-07-03 19:38

The correct way to pass a COM object across apartments is to marshal the interface pointer, which can be done in one of two different ways:

  1. Have the worker thread call the CoMarshalInterThreadInterfaceInStream() function and pass the resulting IStream pointer to the UI thread, which then calls the CoGetInterfaceAndReleaseStream() function.

  2. Use the IGlobalInterfaceTable interface. Have the worker thread create the interface and call its RegisterInterfaceInGlobal() method and pass the resulting cookie to the UI thread, which then creates the interface and calls its GetInterfaceFromGlobal() and RevokeInterfaceFromGlobal() methods.

查看更多
登录 后发表回答