通过 Outlook 和 Redemption 发送电子邮件时的 AV

发布于 2024-11-03 09:06:22 字数 1787 浏览 5 评论 0原文

这是我的代码:

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 ('[email protected]');
 rdSafeItem.Send;
 rdUtils:= CreateOleObject ('Redemption.MAPIUtils');
 rdUtils.DeliverNow;
 olNameSpace.Logoff;
 varclear (rdUtils);
 varclear (rdSafeItem);
 varclear (olItem);
 varclear (olNameSpace);
 varclear (olApp);
end;

发送电子邮件后,我在地址 A70D6D13 处收到访问冲突消息(该地址似乎是不变的)。如果我用 F8 单步执行整个过程,在“end”语句之后,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('[email protected]');
 sItem.Attachments.Add('C:\windows\win.ini');
 sItem.save;
 SItem.send;
 outlookapplication1.Disconnect;
end;

这也给出了同样的错误。 AV的地址有什么神奇之处?这一定是解决问题的线索。

蒂亚,

诺姆

Here is my code:

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 ('[email protected]');
 rdSafeItem.Send;
 rdUtils:= CreateOleObject ('Redemption.MAPIUtils');
 rdUtils.DeliverNow;
 olNameSpace.Logoff;
 varclear (rdUtils);
 varclear (rdSafeItem);
 varclear (olItem);
 varclear (olNameSpace);
 varclear (olApp);
end;

After the email is sent, I get an access violation message at address A70D6D13 (this address seems to be constant). If I step through the entire procedure with F8, after the 'end' statement, the CPU window gets displayed at address A70D6D13, showing all the memory as ????.

I'm using Delphi 7, Outlook 2003, Redemption 4.8.0.1184
What is missing from this code?

EDIT:
I've found a few other code snippets to send mail via Outlook/Redemption. Here is one such snippet which uses the OutlookApplication server.

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('[email protected]');
 sItem.Attachments.Add('C:\windows\win.ini');
 sItem.save;
 SItem.send;
 outlookapplication1.Disconnect;
end;

This too gives the same error. What is magical about the address of the AV? It must be a clue to the solution.

TIA,

No'am

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

南冥有猫 2024-11-10 09:06:22

尝试删除 varclear 语句。

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

Try dropping the varclear statements.

The symptoms you're describing suggest that you're managing to evict the COM objects from memory in the routine, and then Delphi's trying to release them again when the method variables go out of scope.

风尘浪孓 2024-11-10 09:06:22

更新

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

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


不确定这实际上是问题的原因,但我在代码中错过的是与 Outlook 应用程序的连接和断开连接。尽管它们显然不需要使用 Outlook COM 服务器(如发送的邮件所建议的那样),但它们是我所知道的“正常”COM 使用模式的一部分。我可以想象,当变量超出范围(在 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 块也不会浪费。

Update

As No'am rightly commented, Outlook's application COM interface does not support Connect and Disconnect. I was suprised at that, but I normally use the Delphi wrappers and indeed TOutlookApplication's implementation of Connect just returns the result of the CreateOleObject or GetActiveObject. The implementation of TOutlookApplication's Disconnect method, actually does something more than just releasing interfaces. If AutoQuit is true it calls Quit on the Application's COM interface.

However, as it seems to be optional, I think not calling olApp.Quit should not cause the problems No'am is having. Leaving my answer as "educational" material and so others don't have to check this.


Not sure this is actually the cause of your problem, but what I miss in your code is the connect to and disconnect from the Outlook Application. Although they apparently are not needed to use the Outlook COM server (as suggested by the mail being sent), they are part of the "normal" COM use patterns I know. I can well imagine that not connecting/disconnecting may well cause finalization code to fall over when that is triggered by the vars going out of scope (after the end statement).

The pattern I normally use is:

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

You would use Create and Free when using one of the Delphi provided TxxxApplication wrappers, CreateOleObject and Releasing the interface (setting it to nil/unassigned) if you are using "straight" COM.

In your example that would mean adding

olApp.Connect;

between the CreateOleObject and olNameSpace assignment lines, and adding

olApp.Disconnect;

after the olNameSpace.LogOff;

Adding a couple of try/finally blocks also wouldn't be wasted.

半衾梦 2024-11-10 09:06:22

我正在使用 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 ('[email protected]');
 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;

I am using Redemption 5.0.0.2174, Delphi 7, Outlook 2003

I modified your code as follows and was able to send an email without any errors

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 ('[email protected]');
 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;
奢欲 2024-11-10 09:06:22

您在结束语句中收到错误,这意味着在清理某些临时变量时可能会抛出错误。也许是清理 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 ('[email protected]');
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。

You get the error at the end statement, that means the error is probably thrown when it is cleaning up some temporary variables. Maybe its the cleaning up the temp var for rdSafeItem.Recipients or some intermediate variable that is used with CreateOleObject. What you can do is chop up your code into smaller pieces, doing ALL the com related stuff in those smaller procedures (at least the ones that use intermediate variables) and not in your main method. This can make it easier to track down the problem or maybe it even fixes the problem.

Something like this:

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 ('[email protected]');
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;

Edit: added OutputDebugStrings because the error only seems to happen when the application is run without the debugger. When you find the offending function, you can add more OutputDebugStrings there.

半﹌身腐败 2024-11-10 09:06:22

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

其次,尝试摆脱 Logoff 语句。
如果 Outlook 已经在运行,您需要小心 - 如果用户正在运行它,您不想终止它。

Firstly, there is no reason to use DeliverNow - MS broke it in Outlook 2002:
http://www.dimastr.com/redemption/faq.htm#1

Secondly, try to get rid of the Logoff statement.
You need to be careful if Outlook is already running - you don't want to kill it if a user is running it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文