AV при отправке электронной почты через Outlook и Redemption - PullRequest
1 голос
/ 25 апреля 2011

Вот мой код:

const
 olMailItem = 0;

var
 olApp, OlNameSpace, OlItem, rdSafeItem, rdUtils: variant;

begin
 olApp:= CreateOleObject ('Outlook.Application');
 olNameSpace:= olApp.GetNamespace ('MAPI');
 olNameSpace.Logon;
 olItem:= olApp.CreateItem (olMailItem);
 rdSafeItem:= CreateOleObject ('Redemption.SafeMailItem');
 rdSafeItem.Item:= olItem;

 rdSafeItem.Subject:= 'Testing';
 rdSafeItem.attachments.Add ('c:\windows\win.ini');
 rdSafeItem.Recipients.Add ('test@testing.com');
 rdSafeItem.Send;
 rdUtils:= CreateOleObject ('Redemption.MAPIUtils');
 rdUtils.DeliverNow;
 olNameSpace.Logoff;
 varclear (rdUtils);
 varclear (rdSafeItem);
 varclear (olItem);
 varclear (olNameSpace);
 varclear (olApp);
end;

После того, как электронное письмо отправлено, я получаю сообщение о нарушении прав доступа по адресу A70D6D13 (этот адрес кажется постоянным). Если я выполняю всю процедуру с помощью F8, после оператора 'end' окно ЦП отображается по адресу A70D6D13, показывая всю память как ????.

Я использую Delphi 7, Outlook 2003, Redemption 4.8.0.1184 Чего не хватает в этом коде?

EDIT: Я нашел несколько других фрагментов кода для отправки почты через Outlook / Redemption. Вот один такой фрагмент, который использует сервер OutlookApplication.

begin
 outlookapplication1.Connect;
 NmSpace:= outlookapplication1.GetNamespace('MAPI');
 NmSpace.Logon('', '', False, False);
 oItem:= outlookapplication1.CreateItem(olMailItem);
 sItem:= CreateOleObject('Redemption.SafeMailItem');
 oItem.Subject:= 'my subject';
 oItem.save;
 sItem.Item:= oItem;
 sItem.Recipients.Add('test@test.com');
 sItem.Attachments.Add('C:\windows\win.ini');
 sItem.save;
 SItem.send;
 outlookapplication1.Disconnect;
end;

Это тоже дает ту же ошибку. Что волшебного в адресе AV? Это должно быть ключом к решению.

ТИА,

No'am

Ответы [ 5 ]

0 голосов
/ 26 апреля 2011

Вы получаете ошибку в операторе end, это означает, что ошибка, вероятно, генерируется при очистке некоторых временных переменных. Может быть, это очистка временной переменной для rdSafeItem.Recipients или некоторой промежуточной переменной, которая используется с CreateOleObject. То, что вы можете сделать, это нарезать ваш код на более мелкие части, выполняя ВСЕ связанные с com вещи в этих меньших процедурах (по крайней мере, в тех, которые используют промежуточные переменные), а не в вашем основном методе. Это может облегчить отслеживание проблемы или, возможно, даже устранение проблемы.

Примерно так:

function CreateOutlookApp: OleVariant;
begin
  Result := CreateOleObject ('Outlook.Application');
end;

function GetAndLogonNamespace(const olApp: OleVariant): OleVariant;
begin
  Result := olApp.GetNamespace ('MAPI');
  Result.Logon;
end;

function GetSafeMailItem(const olApp: OleVariant): OleVariant;
const
 olMailItem = 0;
var
  olItem: OleVariant;
begin
  olItem:= olApp.CreateItem (olMailItem);
  Result := CreateOleObject ('Redemption.SafeMailItem');
  Result.Item:= olItem;

  Result.Subject:= 'Testing';
  Result.attachments.Add ('c:\windows\win.ini');
  Result.Recipients.Add ('test@testing.com');
end;

procedure SendTestMail;
var
 olApp, olNameSpace, rdSafeItem: OleVariant
begin
 OutputDebugString('CreateOutlookApp');
 olApp := CreateOutlookApp;
 OutputDebugString('GetAndLogonNamespace');
 olNameSpace := GetAndLogonNamespace(olApp);
 OutputDebugString('GetSafeMailItem');
 rdSafeItem := GetSafeMailItem(olApp);
 OutputDebugString('rdSafeItem.Send');
 rdSafeItem.Send;
 OutputDebugString('DeliverNow');
 DeliverNow; //implement this yourself
 OutputDebugString('LogoffNamespace');
 LogoffNamespace(olNamespace); //implement this yourself
 OutputDebugString('Cleaning up');
end;

Редактировать: добавлен OutputDebugStrings, поскольку кажется, что ошибка возникает только при запуске приложения без отладчика. Когда вы найдете нарушающую функцию, вы можете добавить туда еще OutputDebugStrings.

0 голосов
/ 26 апреля 2011

Во-первых, нет причин использовать DeliverNow - MS сломала его в OUtlook 2002: http://www.dimastr.com/redemption/faq.htm#1

Во-вторых, это работает, если вы избавляетесь от оператора Logoff? Вы должны быть осторожны, если Outlook уже запущен - вы не хотите убивать его, если пользователь запускает его.

0 голосов
/ 25 апреля 2011

Обновление

Как правильно заметил No'am, COM-интерфейс приложения Outlook не поддерживает подключение и отключение.Я был удивлен этим, но я обычно использую обертки Delphi, и действительно реализация Connect Connect для TOutlookApplication просто возвращает результат CreateOleObject или GetActiveObject.Реализация метода Disconnect TOutlookApplication на самом деле делает нечто большее, чем просто освобождение интерфейсов.Если AutoQuit имеет значение true, он вызывает Quit в COM-интерфейсе приложения.

Однако, поскольку это кажется необязательным, я думаю, что отказ от вызова olApp.Quit не должен вызывать проблем, с которыми сталкивается No'am.Оставляя мой ответ как «учебный» материал, и другие не должны проверять это.


Не уверен, что это на самом деле причина вашей проблемы, но я упускаю в вашем коде соединение си отключиться от приложения Outlook.Хотя они, очевидно, не нужны для использования COM-сервера Outlook (как предполагает отправляемая почта), они являются частью «обычных» шаблонов использования COM, которые я знаю.Я вполне могу себе представить, что отсутствие соединения / разъединения может привести к падению кода завершения, когда он запускается из-за выхода переменных из области видимости (после оператора end).

Шаблон, который я обычно использую:

Create / CreateOleObject
try
  Connect
  try
    ...
  finally
    Disconnect
  end
finally
  Free / Release 
end

Вы должны использовать Create и Free при использовании одного из предоставленных Delphi упаковщиков TxxxApplication, CreateOleObject и Releasing интерфейса (устанавливая его в ноль / не назначенный), если вы используете «прямой» COM.

В вашем примере это будет означать добавление

olApp.Connect;

между строками назначения CreateOleObject и olNameSpace и добавление

olApp.Disconnect;

после olNameSpace.LogOff;

Добавлениепара блоков try / finally также не будет потрачена впустую.

0 голосов
/ 25 апреля 2011

Я использую Redemption 5.0.0.2174, Delphi 7, Outlook 2003

Я изменил ваш код следующим образом и смог отправить письмо без ошибок

const
 olMailItem = 0;
var
 olApp, OlNameSpace, OlItem, rdSafeItem, rdUtils: variant;
begin
 olApp:= CreateOleObject ('Outlook.Application');
 olNameSpace:= olApp.GetNamespace ('MAPI');
 olNameSpace.Logon;
 olItem:= olApp.CreateItem (olMailItem);
 rdSafeItem:= CreateOleObject ('Redemption.SafeMailItem');
 rdSafeItem.Item:= olItem;
 rdSafeItem.Subject:= 'Testing';
 rdSafeItem.attachments.Add ('c:\windows\win.ini');
 rdSafeItem.Recipients.Add ('test@testing.com');
 rdSafeItem.Recipients.ResolveAll;                       // added
 rdSafeItem.Send;
// rdUtils:= CreateOleObject ('Redemption.MAPIUtils');
// rdUtils.DeliverNow;
 olNameSpace.Logoff;
// varclear (rdUtils);
// varclear (rdSafeItem);
// varclear (olItem);
// varclear (olNameSpace);
// varclear (olApp);
end;
0 голосов
/ 25 апреля 2011

Попробуйте сбросить операторы varclear.

Симптомы, которые вы описываете, позволяют предположить, что вам удается исключить COM-объекты из памяти в подпрограмме, а затем Delphi пытается освободить их снова, когда переменные метода выходят из области видимости.

...