我正在尝试在XE6中使用断开连接的ADO Recordset 。我们的想法是您正常打开记录集,然后将记录集的 ActiveConnection 设置为您的语言等同于null
/ Nothing
/ {{ 1}}:
nil
空rs.Set_ActiveConnection(
Delphi 5中的以下示例工作正常:
);
问题是我无法在Delphi XE6中运行它。在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);
一切都很出色。它起作用,因为rs.Set_ActiveConnection(nil);
接口被声明为:
_Recordset
因此传递procedure Set_ActiveConnection(const pvar: IDispatch); safecall;
是有效的;它起作用了。
在XE6中,演化改为:
nil
您无法通过procedure Set_ActiveConnection(pvar: OleVariant); safecall;
。那么问题就是nil
相当于OleVariant
?
nil
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(nil); //E2010 Incompatible types: 'OleVariant' and 'Pointer'
导致异常:
参数类型错误,超出可接受范围或彼此冲突
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Null);
导致异常:
参数类型错误,超出可接受范围或彼此冲突
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(EmptyParam);
导致异常:
参数类型错误,超出可接受范围或彼此冲突
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Unassigned);
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(nil)); //E2089 Invalid typecast
导致异常:
参数类型错误,超出可接受范围或彼此冲突
我清楚Codebarcadero声明错误。它真的应该是//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(OleVariant(Null));
。这意味着我需要欺骗编译器传递位于地址IDispatch
的 OleVariant (即nil)。这样ADO会在堆栈上看到值0x00000000
,并且我知道我的意思是0x00000000
:
null
我确定Bo..Imp ...... Co..Embarcadero有打算调用它的方法;我只是想不出来。
Dephi 5做的正确;它将$ 00(即rs.Set_ActiveConnection(POleVariant(nil)^); //access violation before call
)推入堆栈:
nil
尽管德尔福XE6正在通过英勇的努力去做一些我不知道的事情:
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
答案 0 :(得分: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;
并在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适合你。
我首先尝试使用Set_ActiveConnection(IDispatch(Nil))的原因,对于需要传递OleVariant的接口,是这样的:自从接口被添加到Delphi(在D3?中),iirc in添加基于变体的OLE自动化之后的版本(D2),编译器已经知道如何生成代码以在OleVariant和IDispatch接口之间双向转换。所以"问题"是如何将IDispatch接口作为OleVariant参数传递。这一点,以我简单的方式查看它,很简单,只需编写IDispatch(),其中参数应该是OleVariant,并让编译器对要生成的代码进行排序。如果我们想传递的值,因为IDisaptch接口实际上是Nil,我们只需要编写
SomeInterfaceMemberExpectingAnOleVariant(IDispatch(Nil))