Не работает COM-объект:разное объявление TSafeArray в модулях ActiveX разных версий Delphi

nicholaos
Дата: 19.08.2019 12:55:02
Здравствуйте!

Есть сторонняя COM-библиотека (на C#), в которой часть функций возвращает PSafeArray.

Когда я компилирую проект в Delphi 2007, из массива достаются правильные данные. Когда компилирую в Delphi XE8 - в момент выполнения происходит ошибка Integer overflow.

+ Пример кода считывания из PSafeArray

var
    confarray: PSafeArray;
    i: integer;
    idx: array[0..0] of integer;
    pi: PUnknown;
begin
    ...
    confarray := comp.GetConfigurations;
    for i := 0 to confarray.rgsabound[0].cElements - 1 do begin
      idx[0] := i;
      SafeArrayGetElement(confarray, idx, pi);
    ....



Integer overflow возникает на строчке
 for i := 0 to confarray.rgsabound[0].cElements - 1 do begin 
. Т.е. не получается считать cElements.

Пытаясь понять, в чем может быть дело, обнаружил, что TSafeArray имеет разное объявление в ActiveX.pas из Delphi 2007 и Winapi.ActiveX из Delphi XE8 (см. рисунок).

+ ActiveX.pas из Delphi 2007 и Winapi.ActiveX из Delphi XE8

Картинка с другого сайта.


Я добавил в XE-шный проект копию ActiveX.pas из Delphi 2007 и заменил Winapi.ActiveX в uses в модуле вызывающего кода и в _TLB.pas.
XE-шный проект заработал.

При нормальном выполнении в cElements значение меняется от 0 до, в моем случае, максимум 100. Изменение с unsigned-типа на signed-тип той же длины (4 байта) не должно ломать совместимость. Что ее ломает, я понять не могу.

P.S. Так же обратил внимание (просматривая изменения WinDiff'ом), что изменились структуры tagVARIANT, tagPROPVARIANT, tagSTATSTG, но они вроде не используются.
_Vasilisk_
Дата: 19.08.2019 15:13:53
nicholaos
Integer overflow возникает на строчке
 for i := 0 to confarray.rgsabound[0].cElements - 1 do begin 
Так и должно быть.

cElements = 0
Если cElements беззнаковое, то cElements - 1 = 4294967295. Это число не влазит в i: Integer

Варианты решения
1)
var
    i: integer;
begin
    ...
    for i := 0 to Integer(confarray.rgsabound[0].cElements) - 1 do begin

1)
var
    i: Cardinal;
begin
    ...
    for i := 1 to confarray.rgsabound[0].cElements do begin
      idx[0] := i - 1;

А вообще нужно смотреть на ворнинги компилятора. Он предупреждает
Combining signed and unsigned types - widened both operands
nicholaos
Дата: 19.08.2019 15:39:39
_Vasilisk_,

Спасибо, помогло!