如何断开XE6中的ADO Recordset?

Ian*_*oyd 8 delphi ado delphi-xe6

我试图在XE6中使用断开连接的ADO Recordset.这个想法是你正常打开记录集,然后你将记录集的ActiveConnection设置为你的语言相当于null/ Nothing/ nil:

rs.Set_ActiveConnection(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);
Run Code Online (Sandbox Code Playgroud)

它适用于Delphi 5

问题是我无法在Delphi XE6中使用它.在Delphi 5中我会成功致电:

rs.Set_ActiveConnection(nil);
Run Code Online (Sandbox Code Playgroud)

一切都很出色.它起作用,因为_Recordset接口被声明为:

procedure Set_ActiveConnection(const pvar: IDispatch); safecall;
Run Code Online (Sandbox Code Playgroud)

所以通过是有效的nil; 它起作用了.

在XE6中,退出变为:

procedure Set_ActiveConnection(pvar: OleVariant); safecall;
Run Code Online (Sandbox Code Playgroud)

你不能通过nil.那么问题就变成了,OleVariant相当于nil什么?

试试#1

//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(nil); //E2010 Incompatible types: 'OleVariant' and 'Pointer'
Run Code Online (Sandbox Code Playgroud)

试试#2

//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Null);
Run Code Online (Sandbox Code Playgroud)

导致异常:

参数类型错误,超出可接受的范围,或彼此冲突

试试#3

//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(EmptyParam);
Run Code Online (Sandbox Code Playgroud)

导致异常:

参数类型错误,超出可接受的范围,或彼此冲突

试试#4

//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Unassigned);
Run Code Online (Sandbox Code Playgroud)

导致异常:

参数类型错误,超出可接受的范围,或彼此冲突

试试#5

//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(nil)); //E2089 Invalid typecast
Run Code Online (Sandbox Code Playgroud)

试试#6

//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(Null));
Run Code Online (Sandbox Code Playgroud)

导致异常:

参数类型错误,超出可接受的范围,或彼此冲突

试试#7

我很清楚,Codebarcadero的声明是错误的.它真的应该是一个IDispatch.这意味着我需要欺骗编译器传递位于地址(即nil)的OleVariant0x00000000.那样ADO会看到0x00000000堆栈上的值,并且我知道我的意思是null:

rs.Set_ActiveConnection(POleVariant(nil)^); //access violation before call
Run Code Online (Sandbox Code Playgroud)

我确定Bo..Imp ...... Co ..Embarcadero有打算调用它的方法; 我只是想不出来.

Delphi 5组装

Dephi 5做的正确; 它将$ 00(即nil)推入堆栈:

rs.Set_ActiveConnection(nil); push $0 ;push nil mov eax,[ebp-$08] ;get address of rs push eax ;push "this" mov eax,[eax] ;get VMT of IRecordset call dword ptr [eax+$28] ;call offset $28 of VMT

而Delphi XE6正在经历英勇的努力,做一些我不知道的事情:

rs.Set_ActiveConnection(nil); lea eax,[ebp-$000000d8] call Null lea edx,[ebp-$000000d8] lea eax,[ebp-$000000c8] call @OleVarFromVar push dword ptr [ebp-$000000bc] push dword ptr [ebp-$000000c0] push dword ptr [ebp-$000000c4] push dword ptr [ebp-$000000c8] mov eax,[ebp-$04] push eax mov eax,[eax] call dword ptr [eax+$2c]

奖金阅读

Mar*_*ynA 4

在 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;
Run Code Online (Sandbox Code Playgroud)

在德尔福 XE6 中:

Recordset15 = interface(_ADO)
   ['{0000050E-0000-0010-8000-00AA006D2EA4}']
   //...
   procedure _Set_ActiveConnection(const pvar: IDispatch); safecall;
   procedure Set_ActiveConnection(pvar: OleVariant); safecall;
Run Code Online (Sandbox Code Playgroud)

所以尝试一下XE6中的其他版本。就我个人而言,我会尝试

Set_ActiveConnection(IDispatch(Nil)) 
Run Code Online (Sandbox Code Playgroud)

首先,但您在评论中说 _Set_ActiveConnection 适合您。

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

SomeInterfaceMemberExpectingAnOleVariant(IDispatch(Nil))
Run Code Online (Sandbox Code Playgroud)