Приведение к нарушению прав доступа IDispatch в XE2

Мы используем старый код (ComLib.pas, созданный Бинь Ли), поэтому мы можем использовать интерфейс перечисления для объекта (OleVariant):

type
  TDispNewEnum = dispinterface
    ['{97079E31-6957-11D2-9154-0000B4552A26}'] // dummy
    property _NewEnum: IUnknown readonly dispid -4; // DISPID_NEWENUM
    function _NewEnumFunc: IUnknown; dispid -4; // DISPID_NEWENUM
  end;

procedure TEnumVariant.AttachUnknown (const Unk: IUnknown);
var
  pDisp: IDispatch;
  _NewEnumPropFailed: boolean;
  Unknown: IUnknown;
begin
  Detach;
  Unknown := Unk;
  { extract IEnumVariant }
  if (Unknown <> nil) then
  begin
    { try IEnumVariant }
    if not (Succeeded (Unknown.QueryInterface (IEnumVariant, FEnumVariant))) then
    begin
      FEnumVariant := nil;  // safety!

      { test _NewEnum prop and _NewEnum func }
      if (Succeeded (Unknown.QueryInterface (IDispatch, pDisp))) then
      begin
        _NewEnumPropFailed := False;
        try
          //property _NewEnum
          Unknown:=TDispNewEnum(pDisp)._NewEnum; // <---- RAISES EXCEPTION -----
          if not (Succeeded(Unknown.QueryInterface(IEnumVariant, FEnumVariant))) then
            FEnumVariant := nil;  // safety!
        except
          _NewEnumPropFailed := True;
        end;  { except }

Этот код работает с Delphi 2010 и 2007, но не с XE2. В строке, отмеченной выше (с комментарием «RAISES EXCEPTION»), мы получаем исключение:

Проект x.exe вызвал исключение класса $ C0000005 с сообщением «нарушение прав доступа на 0xbaadf00d: чтение адреса 0xbaadf00d».

Переданный объект действительно имеет интерфейс TDispNewEnum, поэтому исключение не должно возникать (как в случае с Delphi 2010 и 2007).

Предложения? Спасибо.


person Mick    schedule 24.10.2011    source источник
comment
См. stackoverflow.com/questions/7886116 о возможной основной причине проблемы. Похоже на регресс.   -  person Arnaud Bouchez    schedule 25.10.2011


Ответы (1)


Адрес памяти 0xbaadf00d - это адрес псевдопамяти, означающий «ПЛОХАЯ ЕДА» (посмотрите на шестнадцатеричные символы). Обычно это используется кодом, когда вы запрашиваете недопустимые интерфейсы или вызовы.

Что, если вы измените строку на:

pDisp: TDispNewEnum;
...
if (Succeeded (Unknown.QueryInterface (IDispatch, pDisp))) then
begin
   _NewEnumPropFailed := False;
   try
     //property _NewEnum
     Unknown:= pDisp._NewEnum; 
...

что для меня имеет больший смысл.

Я заметил некоторые недокументированные изменения в привязке интерфейса XE2. Возможно, предыдущий код с принудительным приведением типов (TDispNewEnum(pDisp)) больше не работает из-за этого.

person Arnaud Bouchez    schedule 24.10.2011
comment
Я использовал FEnumVariant: = IUnknown (UnkV._NewEnum) как IEnumVariant, заключенный в try / except, и, похоже, он работает. - person Mick; 24.10.2011
comment
@Arnaud У меня сейчас проблема с XE2 и моей надстройкой Excel на основе надстройки Express. Вызовы к COM-интерфейсам Excel, которые работали в 2010 году, теперь не работают при компиляции в XE2. Я подозреваю, что уровень XE2 COM изменился, и ваши комментарии в этом ответе заставляют меня подозревать, что ваши наблюдения связаны с моей проблемой. Вы писали где-нибудь о том, что узнали о XE2 и COM? - person David Heffernan; 24.10.2011
comment
Это звучит в точности так, как указано в stackoverflow.com/questions/7886116 - person Arnaud Bouchez; 25.10.2011