EmptyParam была теперь переменной функцией - Как разрешить устаревший код? - PullRequest
11 голосов
/ 21 февраля 2012

Я просто обновляю старый код, написанный на Delphi 6, до Delphi XE2. К сожалению, код ссылается на объект Word97 COM для создания некоторых документов .doc. В коде есть пункт прямого использования Word97.

Я должен сохранить документ, сгенерированный в том же формате Word, который используется старым Crystal Report и другим сторонним приложением, запрашивающим этот формат документа.

Итак, к вопросу. Поскольку я использую Word97 в предложении использования, компилятор жалуется на то, что типы фактических и формальных параметров var должны быть идентичны всякий раз, когда используется переменная EmptyParam. Это идет прямо из исходного файла Word97.pas. Это потому, что EmptyParam теперь объявлен как функция, а не как переменная.

как лучше всего с этим справиться? Должен ли я скопировать исходные файлы Delphi 6 (Word97.pas et al), скажем, в мой локальный каталог, напрямую добавить их в мой проект вместе с System.Variants.pas и изменить директиву компилятора моего приложения, включив в нее EMPTYPARAM_VAR? Я не пробовал этого, но надеюсь, что тогда будет объявлен EmptyParam как переменная. Или, возможно, есть более простое решение.

Спасибо

EDIT

Вот немного дополнительной информации, хотя я принял ответ, для дальнейшего использования. Вот пример кода (AddClaimsLetter - это COM-объект «Application» - то есть TWordApplication):

AddClaimsLetter.Documents.Open(Wordfile, EmptyParam, EmptyParam,
                        EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
                        EmptyParam, EmptyParam, EmptyParam, EmptyParam);

Ничего не меняя, аргументы EmptyParam здесь потерпели неудачу во время компиляции, заявив, что "E2033 Типы фактических и формальных параметров var должны быть идентичны".

Однако, поскольку я хотел сохранить Word97 (который находится в OCX / Server в папке установки Delphi 6 Ent.), Мне нужно было скопировать файлы .pas в мой локальный файл проекта и объявить переменную, которая использовалась вместо EmptyParam (потому что эти файлы тоже пытались скомпилировать и я получил ту же ошибку компилятора, что и выше).

Итак, все работает сейчас, но я мог бы обсудить с руководством обновление до более поздней версии Office для этого приложения!

Спасибо

Ответы [ 3 ]

16 голосов
/ 21 февраля 2012

Я могу быстро обойти эту проблему, объявив локальную переменную типа OleVariant и присвоив ей результат функции EmptyParam.

7 голосов
/ 21 февраля 2012

Для каждого параметра var необходимо добавить локальную переменную, которую вы заполняете вызовом EmptyParam.

Причина в том, что все параметры var передаются по ссылке. Если вы передаете одну и ту же переменную в нескольких ссылках, вы можете столкнуться со следующей проблемой (упрощенной с помощью целых чисел).

Before: VarParameter=-1
Before: A=-1
Before: B=-1
After: A=2
After: B=2
After: VarParameter=2
EAssertionFailed: Assertion failure

Это код, который показывает риск:

program TheVarParameterRisk;

procedure AssignParameters(var A: Integer; var B: Integer);
begin
  Writeln('Before: A=', A);
  Writeln('Before: B=', B);
  A := 1;
  B := 2;
  Writeln('After: A=', A);
  Writeln('After: B=', B);
  Assert(A = 1);
end;

var
  VarParameter: Integer;

begin
  try
    VarParameter := -1;
    try
      Writeln('Before: VarParameter=', VarParameter);
      AssignParameters(VarParameter, VarParameter);
    finally
      Writeln('After: VarParameter=', VarParameter);
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Вы видите, что в AssignParameters Assert происходит сбой, потому что вызывающая сторона передала одну и ту же ссылку в два var параметра.

Именно поэтому EmptyParam стал функцией: он никогда не должен передаваться как var параметр.

Люди жаловались на ошибки в Delphi (например, здесь ), которые приводили к перезаписи значения EmptyParam.

Эта проблема решена теперь, когда EmptyParam является функцией. Когда вам нужно передать его как параметр var, используйте локальное промежуточное звено.

Примечания:

  • Если вы (поскольку ваш импортированный API указывает, что вы должны) передать EmptyParam параметру var, то, по сути, у вас возникла проблема: параметр var означает, что что-то будет изменено, что означает, что передача EmptyParam (или локальная переменная с таким же содержимым) предотвращает изменение.
  • Если вы считаете, что Импортер библиотек типов генерирует неправильный код (который имеет var параметров вместо const параметров), то либо импортированная библиотека типов имеет неправильные флаги параметров, либо (если флаги параметров в порядке ) он глючит (и вы должны подать отчет об ошибке на https://quality.embarcadero.com (раньше это была поисковая система с индексом http://qc.embarcadero.com, но она была закрыта; https://quality.embarcadero.com требует бесплатной аккаунт для поиска).

Edit:

Тот факт, что вы должны передать EmptyParam в параметр var, является очень сильным намеком на то, что вызываемая функция может фактически использовать эти параметры и потерпит неудачу. Так же, как мой пример, функция не работает. (Да, документация по функции может заманить вас к использованию нескольких EmptyParam параметров, которые на самом деле вовсе не должны быть такими пустыми; я часто видел документацию, в которой говорится, что A и реальные функции выполняют B).

1 голос
/ 21 февраля 2012

Должен ли я скопировать исходные файлы Delphi 6 (Word97.pas et al), скажем, в мой локальный каталог, напрямую добавить их в мой проект вместе с System.Variants.pas и изменить директиву компилятора моего приложения, включив в нее EMPTYPARAM_VAR? Я не пробовал этого, но надеюсь, что тогда будет объявлен EmptyParam как переменная.

Возможно, вам по закону разрешено копировать Word97.pas из гораздо более старого Delphi в новый, но тогда вам нужно будет "обновить" его для работы с новым компилятором. Скорее всего, вы столкнетесь с гораздо большими проблемами, в основном потому, что Delphi XE2 поддерживает Unicode, а Delphi 6 нет. Если этот модуль является тем, чем я считаю (как уже упоминалось, у меня его нет в 3 версиях Delphi, который я получил под рукой и проверил), то это оболочка для OLE Automating Word - то есть он полон трудной для понимания системы код и множество объявлений методов без реализации. Этот последний бит, объявления методов без реализации, делает его очень трудным для изменения: если вы что-то меняете и компилируете, это не значит, что это правильно - вы найдете только во время выполнения, работает он или нет .

Что вы, вероятно, должны делать:

  • Повторно импортируйте библиотеку типов для Word 97 (я полагаю, это то, чем является Word97.pas) и заново напишите свой код экспорта, чтобы сгенерировать документ Word с использованием этой новой библиотеки. Редактировать : По-видимому, повторный импорт TypeLibrary приводит к невозможности использования кода.
  • Напишите DLL в Delphi6, которая использует старый Word97.pas, и используйте его из Delphi XE2. Не очень элегантно, но будет работать.
  • Переосмыслите свою стратегию вокруг того, каким является текущее предложение для автоматизации Word.
...