Как отключить набор записей 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))