Delphi 如何在XE6中断开ADO记录集?
我试图在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
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))
@MartynAvarNull
是一个常量,声明为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))