1

这是我的代码:

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 逐步完成整个过程,在“结束”语句之后,CPU 窗口将显示在地址 A70D6D13 处,将所有内存显示为????。

我正在使用 Delphi 7、Outlook 2003、Redemption 4.8.0.1184 这段代码缺少什么?

编辑:我发现了一些其他代码片段可以通过 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的地址有什么神奇之处?它必须是解决方案的线索。

TIA,

诺姆

4

5 回答 5

0

尝试删除varclear语句。

您描述的症状表明您正在设法从例程中的内存中逐出 COM 对象,然后当方法变量超出范围时,Delphi 试图再次释放它们。

于 2011-04-25T14:38:16.313 回答
0

您在 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。

于 2011-04-26T07:07:25.283 回答
0

更新

正如 No'am 正确评论的那样,Outlook 的应用程序 COM 接口不支持连接和断开连接。我对此感到惊讶,但我通常使用 Delphi 包装器,而且实际上 TOutlookApplication 的 Connect 实现只返回 CreateOleObject 或 GetActiveObject 的结果。TOutlookApplication 的 Disconnect 方法的实现,实际上不仅仅是发布接口。如果 AutoQuit 为真,它会在应用程序的 COM 接口上调用 Quit。

但是,由于它似乎是可选的,我认为不调用 olApp.Quit 不应导致 No'am 遇到的问题。将我的答案保留为“教育”材料,因此其他人不必检查这一点。


不确定这实际上是您问题的原因,但我在您的代码中错过的是与 Outlook 应用程序的连接和断开连接。尽管它们显然不需要使用 Outlook COM 服务器(正如正在发送的邮件所建议的那样),但它们是我所知道的“正常”COM 使用模式的一部分。我可以很好地想象,当 vars 超出范围(在 end 语句之后)触发时,不连接/断开连接很可能会导致最终代码崩溃。

我通常使用的模式是:

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

如果您使用“直接”COM,则在使用 Delphi 提供的 TxxxApplication 包装器、CreateOleObject 和释放接口(将其设置为 nil/未分配)之一时,您将使用 Create 和 Free。

在您的示例中,这意味着添加

olApp.Connect;

在 CreateOleObject 和 olNameSpace 分配线之间,并添加

olApp.Disconnect;

在 olNameSpace.LogOff 之后;

添加几个 try/finally 块也不会浪费。

于 2011-04-25T17:15:53.843 回答
0

我正在使用 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;
于 2011-04-25T19:17:31.433 回答
0

首先,没有理由使用 DeliverNow - MS 在 OUTlook 2002 中打破了它: http ://www.dimastr.com/redemption/faq.htm#1

其次,如果您摆脱 Logoff 语句,它会起作用吗?如果 Outlook 已经在运行,您需要小心 - 如果用户正在运行它,您不想杀死它。

于 2011-04-25T22:53:26.073 回答