Как отключить набор записей ADO в XE6?
я пытаюсь использовать отключенное ADO набор в версии XE6. Идея заключается в том, что вы открываете набор записей нормально, а затем устанавливаете 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
. Тогда возникает вопрос, Что такое OleVariant
эквивалентно nil
?
попробовать #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);
причины исключения:
аргументы имеют неправильный тип, находятся вне допустимого диапазона или находятся в конфликте друг с другом
попробовать #3
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(EmptyParam);
причины исключения:
аргументы имеют неправильный тип, находятся вне допустимого диапазона или находятся в конфликте друг с другом
попробовать #4
//Disconnect the recordset by setting the .ActiveConnection to null
rs.Set_ActiveConnection(Unassigned);
причины исключение:
аргументы имеют неправильный тип, находятся вне допустимого диапазона или находятся в конфликте друг с другом
попробовать #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));
причины исключения:
аргументы имеют неправильный тип, находятся вне допустимого диапазона или находятся в конфликте друг с другом
Попробовать #7
мне ясно, что Codebarcadero получил декларацию неправильный. Это действительно должно быть IDispatch
. Это означает, что мне нужно обмануть компилятор в передаче OleVariant расположенном по адресу 0x00000000
(т. е. ноль). Таким образом, ADO увидит значение 0x00000000
на стеке, и знаете, что я имею в виду null
:
rs.Set_ActiveConnection(POleVariant(nil)^); //access violation before call
я уверен, что Bo..Imp ... Co..Embarcadero имеет предполагаемый способ назвать это; я просто не могу понять это.
Delphi 5 assembly
Dephi 5 делает правильную вещь; он толкает $00 (т. е. nil
) в стек:
rs.Set_ActiveConnection(nil);
push ;push nil
mov eax,[ebp-] ;get address of rs
push eax ;push "this"
mov eax,[eax] ;get VMT of IRecordset
call dword ptr [eax+] ;call offset of VMT
в то время как Delphi XE6 предпринимает героические усилия, чтобы сделать что-то, я не знаю что:
rs.Set_ActiveConnection(nil);
lea eax,[ebp-0000d8]
call Null
lea edx,[ebp-0000d8]
lea eax,[ebp-0000c8]
call @OleVarFromVar
push dword ptr [ebp-0000bc]
push dword ptr [ebp-0000c0]
push dword ptr [ebp-0000c4]
push dword ptr [ebp-0000c8]
mov eax,[ebp-]
push eax
mov eax,[eax]
call dword ptr [eax+c]
Бонус Чтение
1 ответов
в 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 в версии после добавления автоматизации OLE на основе вариантов (D2) компилятор знал, как генерировать код для преобразования в обоих направлениях между OleVariant и интерфейсом IDispatch. Так что "проблема" как пройти интерфейса IDispatch в качестве аргумента OleVariant. Этот бит, на мой простодушный взгляд, прост, просто напишите IDispatch() , где аргумент должен быть OleVariant, и оставьте компилятор сортируйте код для генерации. И если стоимостью мы хотим передать, поскольку интерфейс IDisaptch фактически равен нулю, нам просто нужно написать
SomeInterfaceMemberExpectingAnOleVariant(IDispatch(Nil))