如何通过线程边界传递ADO Recordset(或任何COM对象)? [英] How to pass an ADO Recordset (or any COM object) across thread boundaries?

查看:182
本文介绍了如何通过线程边界传递ADO Recordset(或任何COM对象)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在后台线程中创建的ADO Recordset 对象:

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

//将记录集赋给UI线程
//不要忘记在将它添加到32位变量之前添加引用
rs._AddRef() ;
PostMessage(hwndUIThreadWindow,WM_HeresTheRecordsetYouAskedFor,WPARAM(rs),0);
end;

然后 Recordset main线程:

  procedure ExecuteComplete(var msg:TMessage);消息WM_HeresTheRecordsetYouAskedFor; 
var
rs:_Recordset;
begin
rs:= _Recordset(msg.wParam);
//不要忘记删除手动添加的引用
rs._Release();

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

我也可以这样做:

  var 
global_Recordset:_Recordset;

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

无论如何,没有创建COM对象的线程现在使用它。从线程:

  global_Recordset .Fields ['TheTimeIs']。 

COM禁止访问公寓中的COM对象(在这种情况下: threads

COM对象接口中的正确方法是什么

解决方案

跨公寓传递COM对象的正确方法是封送接口指针,这可以完成以两种不同的方式之一:


  1. 让工作线程调用 CoMarshalInterThreadInterfaceInStream() 函数, c $ c> IStream 指向UI线程的指针,然后调用


  2. 使用

    a href =http://msdn.microsoft.com/en-us/library/windows/desktop/ms678517.aspx =nofollow> IGlobalInterfaceTable
    接口。让工作线程创建接口并调用其 RegisterInterfaceInGlobal()方法,并将结果cookie传递给UI线程,然后创建接口并调用其 GetInterfaceFromGlobal() RevokeInterfaceFromGlobal()方法。



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?

解决方案

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.

这篇关于如何通过线程边界传递ADO Recordset(或任何COM对象)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆