如何在 XE6 中断开 ADO 记录集?
How to disconnect an ADO Recordset in 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);
它适用于 Delphi 5
问题是我无法让它在 Delphi XE6 中工作。在 Delphi 5 我会成功调用:
rs.Set_ActiveConnection(nil);
一切都非常顺利。它起作用是因为 _Recordset
接口声明为:
procedure Set_ActiveConnection(const pvar: IDispatch); safecall;
所以通过nil
是有效的;它奏效了。
在 XE6 中,声明更改为:
procedure Set_ActiveConnection(pvar: OleVariant); safecall;
你不能传递给nil
。那么问题就变成了,nil
的 OleVariant
是什么?
尝试#1
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(nil); //E2010 Incompatible types: 'OleVariant' and 'Pointer'
尝试 #2
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Null);
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
尝试#3
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(EmptyParam);
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
尝试#4
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Unassigned);
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
尝试#5
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(nil)); //E2089 Invalid typecast
试试#6
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(Null));
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
试试 #7
我很清楚 Codebarcadero 的声明有误。它确实应该是 IDispatch
。这意味着我需要诱使编译器传递位于地址 0x00000000
(即 nil)的 OleVariant。这样 ADO 就会在堆栈上看到值 0x00000000
,并且知道我的意思是 null
:
rs.Set_ActiveConnection(POleVariant(nil)^); //access violation before call
我确定 Bo..Imp...Co..Embarcadero 有预期的调用方式;我就是想不通。
Delphi5集
Dephi 5 做了正确的事情;它将 $00(即 nil
)压入堆栈:
<strong>rs.Set_ActiveConnection(无);</strong>
推 $0 ;推零
mov eax,[ebp-$08] ;获取rs的地址
推 eax ;推 "this"
mov eax,[eax] ;获取IRecordset的VMT
call dword ptr [eax+$28] ;调用VMT的偏移量$28
而 Delphi XE6 正在通过英勇的努力去做一些我不知道的事情:
<strong>rs.Set_ActiveConnection(无);</strong>
lea eax,[ebp-$000000d8]
调用 Null
lea edx,[ebp-$000000d8]
lea eax,[ebp-$000000c8]
致电@OleVarFromVar
push dword ptr [ebp-$000000bc]
推 dword ptr [ebp-$000000c0]
推 dword ptr [ebp-$000000c4]
推 dword ptr [ebp-$000000c8]
mov eax,[ebp-$04]
推 eax
移动 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 的接口,我首先尝试 Set_ActiveConnection(IDispatch(Nil)) 的原因是:自从接口被添加到 Delphi (在 D3 中?),iirc 在添加了基于变量的 OLE 自动化之后的版本中 (D2),编译器已经知道如何生成代码以在 OleVariant 和 IDispatch 接口之间进行双向转换。所以 "problem" 是如何将 IDispatch 接口作为 OleVariant 参数传递的。以我头脑简单的方式来看,这很简单,只需在参数应该是 OleVariant 的地方编写 IDispatch(),然后让编译器整理要生成的代码。而如果我们要作为IDisaptch接口传递的value实际上是Nil,我们只需要写
SomeInterfaceMemberExpectingAnOleVariant(IDispatch(Nil))
我正在尝试在 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);
它适用于 Delphi 5
问题是我无法让它在 Delphi XE6 中工作。在 Delphi 5 我会成功调用:
rs.Set_ActiveConnection(nil);
一切都非常顺利。它起作用是因为 _Recordset
接口声明为:
procedure Set_ActiveConnection(const pvar: IDispatch); safecall;
所以通过nil
是有效的;它奏效了。
在 XE6 中,声明更改为:
procedure Set_ActiveConnection(pvar: OleVariant); safecall;
你不能传递给nil
。那么问题就变成了,nil
的 OleVariant
是什么?
尝试#1
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(nil); //E2010 Incompatible types: 'OleVariant' and 'Pointer'
尝试 #2
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Null);
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
尝试#3
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(EmptyParam);
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
尝试#4
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Unassigned);
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
尝试#5
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(nil)); //E2089 Invalid typecast
试试#6
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(Null));
导致异常:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another
试试 #7
我很清楚 Codebarcadero 的声明有误。它确实应该是 IDispatch
。这意味着我需要诱使编译器传递位于地址 0x00000000
(即 nil)的 OleVariant。这样 ADO 就会在堆栈上看到值 0x00000000
,并且知道我的意思是 null
:
rs.Set_ActiveConnection(POleVariant(nil)^); //access violation before call
我确定 Bo..Imp...Co..Embarcadero 有预期的调用方式;我就是想不通。
Delphi5集
Dephi 5 做了正确的事情;它将 $00(即 nil
)压入堆栈:
<strong>rs.Set_ActiveConnection(无);</strong>
推 $0 ;推零
mov eax,[ebp-$08] ;获取rs的地址
推 eax ;推 "this"
mov eax,[eax] ;获取IRecordset的VMT
call dword ptr [eax+$28] ;调用VMT的偏移量$28
而 Delphi XE6 正在通过英勇的努力去做一些我不知道的事情:
<strong>rs.Set_ActiveConnection(无);</strong>
lea eax,[ebp-$000000d8]
调用 Null
lea edx,[ebp-$000000d8]
lea eax,[ebp-$000000c8]
致电@OleVarFromVar
push dword ptr [ebp-$000000bc]
推 dword ptr [ebp-$000000c0]
推 dword ptr [ebp-$000000c4]
推 dword ptr [ebp-$000000c8]
mov eax,[ebp-$04]
推 eax
移动 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 的接口,我首先尝试 Set_ActiveConnection(IDispatch(Nil)) 的原因是:自从接口被添加到 Delphi (在 D3 中?),iirc 在添加了基于变量的 OLE 自动化之后的版本中 (D2),编译器已经知道如何生成代码以在 OleVariant 和 IDispatch 接口之间进行双向转换。所以 "problem" 是如何将 IDispatch 接口作为 OleVariant 参数传递的。以我头脑简单的方式来看,这很简单,只需在参数应该是 OleVariant 的地方编写 IDispatch(),然后让编译器整理要生成的代码。而如果我们要作为IDisaptch接口传递的value实际上是Nil,我们只需要写
SomeInterfaceMemberExpectingAnOleVariant(IDispatch(Nil))