开发者

AV when sending email via Outlook and Redemption

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开发者_Python百科');
 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;

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('test@test.com');
 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


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.


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.


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 ('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;


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 ('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;

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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜