Delphi 如何在XE6中断开ADO记录集?

Delphi 如何在XE6中断开ADO记录集?,delphi,ado,delphi-xe6,Delphi,Ado,Delphi Xe6,我试图在XE6中使用断开连接的ADO记录集。其思想是,您可以正常打开记录集,然后将记录集的活动连接设置为与您的语言等价的null/Nothing/nil: rs.Set\u活动连接(null) Delphi 5中的以下示例效果良好: var rs: _Recordset; rs := CoRecordset.Create; rs.CursorLocation := adUseClient; //the default for a Recordset is adUseServer (Connec

我试图在XE6中使用断开连接的ADO记录集。其思想是,您可以正常打开记录集,然后将记录集的活动连接设置为与您的语言等价的
null
/
Nothing
/
nil

rs.Set\u活动连接(
null

Delphi 5中的以下示例效果良好:

var rs: _Recordset;

rs := CoRecordset.Create;
rs.CursorLocation := adUseClient; //the default for a Recordset is adUseServer (Connection.Execute's default is adUseClient)
rs.CursorType := adOpenForwardOnly; //the default
rs.Open(CommandText, Conn,
      adOpenForwardOnly, //CursorType
      adLockReadOnly, //LockType
      adCmdText);

//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(nil);
它在Delphi5中工作 问题是我无法使它在DelphiXe6中工作。在Delphi 5中,我将成功调用:

rs.Set_ActiveConnection(nil);
一切都很顺利。它之所以有效,是因为
\u记录集
接口被声明为:

procedure Set_ActiveConnection(const pvar: IDispatch); safecall;
因此,通过
nil
是有效的;它成功了

在XE6中,delcaration更改为:

procedure Set_ActiveConnection(pvar: OleVariant); safecall;
无法传递到的
nil
。然后问题就变成了,
OleVariant
nil
的等价物是什么

试试看 试试看 导致异常的原因:

参数类型错误、超出可接受范围或相互冲突

试试看 导致异常的原因:

参数类型错误、超出可接受范围或相互冲突

试试看 导致异常的原因:

参数类型错误、超出可接受范围或相互冲突

试试看 试试看 导致异常的原因:

参数类型错误、超出可接受范围或相互冲突

试试看 我很清楚,Codebarcadero的声明是错的。它实际上应该是一个
IDispatch
。这意味着我需要欺骗编译器传递一个位于地址
0x00000000
(即nil)的OleVariant。这样ADO将在堆栈上看到值
0x00000000
,并且知道我的意思是
null

rs.Set_ActiveConnection(POleVariant(nil)^); //access violation before call
我相信Bo..Imp..Co..Embarcadero有一个专门的称呼这个的方式;我就是想不出来

Delphi 5汇编 德菲5做正确的事情;它将$00(即
nil
)推送到堆栈上:

rs.Set\u活动连接(nil)
推0美元;推零
mov eax,[ebp-$08];获取rs的地址
推动eax;推“这个”
mov-eax[eax];获取IRecordset的VMT
呼叫dword ptr[eax+$28];VMT的呼叫偏移$28

而Delphi XE6正在通过英勇的努力来做一些事情,我不知道是什么:

rs.Set\u活动连接(nil)
lea eax,[ebp-$000000d8]
调用空值
lea edx,[ebp-$000000 D8]
lea eax,[ebp-$000000c8]
调用@OleVarFromVar
推送dword ptr[ebp-$000000bc]
推送dword ptr[ebp-$000000 C0]
推送dword ptr[ebp-$000000 C4]
推送dword ptr[ebp-$000000 C8]
mov eax,[ebp-$04]
推送eax
mov-eax[eax]
呼叫dword ptr[eax+$2c]

额外阅读
在D7(手头没有D5)中,AdoInt.Pas包含两种风格的Set_ActiveConnection,例如

  Recordset15 = interface(_ADO)
    ['{0000050E-0000-0010-8000-00AA006D2EA4}']
    procedure Set_ActiveConnection(const pvar: IDispatch); safecall;
    procedure _Set_ActiveConnection(pvar: OleVariant); safecall;
在Delphi XE6中:

Recordset15 = interface(_ADO)
   ['{0000050E-0000-0010-8000-00AA006D2EA4}']
   //...
   procedure _Set_ActiveConnection(const pvar: IDispatch); safecall;
   procedure Set_ActiveConnection(pvar: OleVariant); safecall;
因此,请尝试XE6中的另一个版本。就我个人而言,我已经试过了

Set_ActiveConnection(IDispatch(Nil)) 
首先,但你在评论中说_Set_ActiveConnection适合你

对于需要传递OleVariant的接口,我会首先尝试设置_ActiveConnection(IDispatch(Nil))的原因是:自从接口被添加到Delphi中(在D3中?),iirc在基于变量的OLE自动化被添加后的版本中(D2),编译器已经知道如何生成代码,以便在OleVariant和IDispatch接口之间进行双向转换。因此,“问题”是如何将IDispatch接口作为OleVariant参数传递。这一点,以我简单的方式来看,很简单,只需编写IDispatch(),其中参数应该是一个OleVariant,然后让编译器对要生成的代码进行排序。如果我们想作为IDisaptch接口传递的值实际上是Nil,我们只需要写

SomeInterfaceMemberExpectingAnOleVariant(IDispatch(Nil))

@MartynA
varNull
是一个常量,声明为
1
。变量记录中使用它来指示变量记录包含的内容。因此,将
ActiveConnection
设置为
1
是没有意义的。但我尝试它只是为了好玩:它失败了,但也出现了同样的异常。我没能正确地回忆起“RecordSet.Set_ActiveConnection(IDispatch(Nil));(至少这在XE8中编译,fwiw)@MartynA:至少在XE8上是这样。(我的意思是说,工作不会引起例外。)@KenWhite:的确如此。D7时代曾经有一个公文包模式的ADO演示。Fwiw,D7 AdoInt.Pas在RecordSet15接口中有“过程集\活动连接(const pvar:IDispatch);安全调用;和过程集\活动连接(pvar:OleVariant);安全调用;”。@MartynA:XE8 AdoInt单元有两个相同的声明,ADO类型库的新导入也会在MSADO_TLB.pas中生成相同的两个声明。使用
IDispatch(nil)
调用两者似乎是等效的-两者都不会引发异常。
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(Null));
rs.Set_ActiveConnection(POleVariant(nil)^); //access violation before call
  Recordset15 = interface(_ADO)
    ['{0000050E-0000-0010-8000-00AA006D2EA4}']
    procedure Set_ActiveConnection(const pvar: IDispatch); safecall;
    procedure _Set_ActiveConnection(pvar: OleVariant); safecall;
Recordset15 = interface(_ADO)
   ['{0000050E-0000-0010-8000-00AA006D2EA4}']
   //...
   procedure _Set_ActiveConnection(const pvar: IDispatch); safecall;
   procedure Set_ActiveConnection(pvar: OleVariant); safecall;
Set_ActiveConnection(IDispatch(Nil)) 
SomeInterfaceMemberExpectingAnOleVariant(IDispatch(Nil))