TOutlookApplication / TOutlookApplicationItemSend params differ from older Delphi 6 to newer Delphi XEx.

Add-in Express™ Support Service
That's what is more important than anything else

TOutlookApplication / TOutlookApplicationItemSend params differ from older Delphi 6 to newer Delphi XEx.
 
Greg Saunders




Posts: 11
Joined: 2012-07-19
We have a legacy app in Delphi 6 using Add-In Express for VCL that was written by a past developer. This is an Outlook add on.

We are porting this over to Delphi XE5 (last version we had), just upgraded to the latest Add-In Express and we are getting several compile issues.

We had assigned a procedure to the OutlookApp.OnItemSend which was simply called with:

OutlookApp.OnItemSend := DoItemSend;


The OnItemSend (TOutlookApplicationItemSend) looks like this:

  
TOutlookApplicationItemSend = procedure(Sender: TObject;  {Flags(3), (2/2) CC:4, INV:1, DBG:9}var {VT_9:0}Item: OleVariant; var {VT_11:1}Cancel: OleVariant) of object;


The DoItemSend looked like this:


procedure TAddInModule.DoItemSend(ASender: TObject; var Item: OleVariant;
  var Cancel: OleVariant);

var

  CSApp : String ;
  TempFile : String ;
  CtrlFile : String ;
  SentList : tStringList ;
  ItemDispIntf     : IDispatch ;
  imail    : _MailItem ;

begin
  if SendButtonDown and NOT(VarIsNull(Item)) then
  begin
    CSApp := GetCSVaultApp ;
    if FileExists(CSApp) then
      begin
        TempFile := CreateTempFile('.msg') ;
        CtrlFile := CreateTempFile('.ctl') ;
        Item.SaveAs(TempFile) ;
        ExecNewProcess(CSApp,'-nosave "'+CtrlFile+'" ' + '"'+TempFile+'"',true);

        ItemDispIntf := Item ;
        Imail := ItemDispIntf as _mailItem ;
        SentList := tStringList.create ;
        SentList.LoadFromFile(CtrlFile);
        If SentList.Count > 0 then
          begin
            imail.UserProperties.Add('VaultKey',olText,true,EmptyParam).Value := GetDBKey(SentList[0])  ;
          end ;
        SentList.Free ;
        DeleteFile(Pchar(CtrlFile)) ;
        DeleteFile(pchar(TempFile)) ;
      end
    else
      begin
        MessageDlg('Vault Application not found', mtError, [mbOK], 0) ;
      end ;
  end;
end;


You will notice in Delphi 6 the parameters were ASender: TObject, var Item: OleVariant and var Cancel: OleVariant

Within the code the Item was simply referenced and properties or methods were called with Items.???.

However in Delphi XE5 the parameters have changed and look like this:

TOutlookApplicationItemSend = procedure(ASender: TObject; const Item: IDispatch; 
                                                            var Cancel: WordBool) of object;


It has been a long while since I have had to do any real coding so I am a bit confused on the change of Item to IDispatch. I am obviously getting errors on the Item.SaveAs(TempFile) command, but not sure how to do this now that the type is iDispatch instead of OleVariant.

Would love some advice on how to deal with this change.

For the second half of the problem I have code that creates TItems and assigns a procedure to the OnItemAdd:


if assigned(outlookapp) then
    begin
      ItemsEvents := TItems.Create(Self);
      ItemsEvents.OnItemAdd := ItemsAdd;
      ItemsEvents.ConnectTo(Self.OutlookApp.GetNamespace('MAPI').
        GetDefaultFolder(olFolderSentMail).Items);
    end ;


The OnItemsAdd (TItemsItemAdd) is defined like this in D6:


  TItemsItemAdd = procedure(Sender: TObject;  {Flags(3), (1/1) CC:4, INV:1, DBG:9}var {VT_9:0}Item: OleVariant) of object;


The OnItemsAdd (TItemsItemAdd) is defined like this in XE5:


TItemsItemAdd = procedure(ASender: TObject; const Item: IDispatch) of object;


The ItemsAdd procedure looks like this:


procedure TAddInModule.ItemsAdd(ASender: TObject; var Item: IDispatch);
var
  UserProp1 : UserProperty ;
  iMail : _MailItem ;
  test     : IDispatch ;
  FileName : String ;

begin
  test := item ;
  imail := (Test as _MailItem)  ;
  UserProp1 := imail.UserProperties.Find('VaultKey',EmptyParam) ;
  try
    if Assigned(UserProp1) then
      begin
        FileName := GetFileName(UserProp1.Value) ;
        if FileName <> '' then
          begin
            Item.FlagIcon := 1 ;    //purple flag
            Item.FlagStatus := 2 ; //olFlagMarked
            Item.FlagRequest := 'Filed In Vault' ;
            Item.ReminderSet := False ;
            Item.Save ;
            Item.SaveAs(FileName);
            SetComplete(UserProp1.Value);
          end ;
      end
  Except
    ShowMessage('Fault') ;
  end ;


We are again getting errors on the Item.??? statements, but the compiler error we are also seeing when assigning the procedure ItemsEvents.OnItemSend := ItemsAdd is "E2009 Incompatible Types: Parameter lists differ".

This last message is confusing as I have the procedure using the same parameter list as it is defined for TItemsItemAdd.

I have never worked with iDispatch so likely my confusion.

I have searched the forums / blogs and elsewhere trying to figure out how to reference the Item now that it is iDispatch and the other issue, but no luck so far.

Thank you for your time.
Posted 25 Jan, 2017 15:16:12 Top
Greg Saunders




Posts: 11
Joined: 2012-07-19
Ok... figuring this out.

The issue with "E2009 Incompatible Types: Parameter lists differ" was simply me being dense and not noticing the var vs const in the declaration.


TItemsItemAdd = procedure(ASender: TObject; const Item: IDispatch) of object; 



procedure TAddInModule.ItemsAdd(ASender: TObject; var Item: IDispatch);


Simply needed to make const in my procedure. So confused by the iDispatch stuff that I lost vision on the simple thing.

Now in regards to the IDispatch... I am noticing in the code the original developer used he actually referenced the Item as the olevariant, but then does seem to access it a different way which seems to give me access to what I was looking for... This is what he had:


var
  ItemDispIntf     : IDispatch ; 
  imail    : _MailItem ; 

begin
  ItemDispIntf := Item ; 
  Imail := ItemDispIntf as _mailItem ;

  imail.UserProperties.Add('VaultKey',olText,true,EmptyParam).Value := GetDBKey(SentList[0])  ;
end;


And in the other procedure the same thing. Now need to test and see if things work.
Posted 25 Jan, 2017 16:27:28 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
Hello Greg,

Does the below work for you?


Andrei Smolin
Add-in Express Team Leader

procedure TAddInModule.DoItemSend(ASender: TObject; const Item: IDispatch; var Cancel: WordBool);
var
  CSApp : String ;
  TempFile : String ;
  CtrlFile : String ;
  SentList : tStringList ;
  imail    : _MailItem ;

begin
  if SendButtonDown and NOT(VarIsNull(Item)) then
  begin
    CSApp := GetCSVaultApp ;
    if FileExists(CSApp) then
      begin
        Imail := Item as _mailItem ;
        if Assigned(Imail) then begin
          TempFile := CreateTempFile('.msg') ;
          CtrlFile := CreateTempFile('.ctl') ;
          Imail.SaveAs(TempFile) ;
          ExecNewProcess(CSApp,'-nosave "'+CtrlFile+'" ' + '"'+TempFile+'"',true);

          SentList := tStringList.create ;
          SentList.LoadFromFile(CtrlFile);
          If SentList.Count > 0 then
            begin
              imail.UserProperties.Add('VaultKey',olText,true,EmptyParam).Value := GetDBKey(SentList[0])  ;
            end ;
          SentList.Free ;
          DeleteFile(Pchar(CtrlFile)) ;
          DeleteFile(pchar(TempFile)) ;
          Imail:= nil;
        end;
      end
    else
      begin
        MessageDlg('Vault Application not found', mtError, [mbOK], 0) ;
      end ;
  end;
end;

procedure TAddInModule.ItemsAdd(ASender: TObject; var Item: IDispatch);
var
  UserProp1: UserProperty;
  iMail: _MailItem;
  FileName: String;

begin
  iMail := Item as _MailItem;
  if Assigned(imail) then begin
    UserProp1 := imail.UserProperties.Find('VaultKey',EmptyParam) ;
    try
      if Assigned(UserProp1) then
        begin
          FileName := GetFileName(UserProp1.Value) ;
          if FileName <> '' then
            begin
              iMail.FlagIcon := 1 ;    //purple flag
              iMail.FlagStatus := 2 ; //olFlagMarked
              iMail.FlagRequest := 'Filed In Vault' ;
              iMail.ReminderSet := False ;
              iMail.Save ;
              iMail.SaveAs(FileName);
              SetComplete(UserProp1.Value);
            end ;
        end
    Except
      ShowMessage('Fault') ;
    end ;
  end;
end;
Posted 26 Jan, 2017 03:52:46 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
Ah!

Please use:

procedure TAddInModule.ItemsAdd(ASender: TObject; const var Item: IDispatch);

The parameters must be the same as declared by the event procedure type.


Andrei Smolin
Add-in Express Team Leader
Posted 26 Jan, 2017 03:55:57 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
(it isn't my day obviously)

procedure TAddInModule.ItemsAdd(ASender: TObject; const Item: IDispatch);


Andrei Smolin
Add-in Express Team Leader
Posted 26 Jan, 2017 03:57:26 Top
Greg Saunders




Posts: 11
Joined: 2012-07-19
Andrei,

The following line had to be changed from:

Imail.SaveAs(TempFile);


to

iMail.SaveAs(TempFile,olMSG);


Basically the SaveAs is saying requires the Type_.

I will be starting some testing shortly, but have another issue that I'll submit in another topic.
Posted 26 Jan, 2017 10:29:13 Top
Andrei Smolin


Add-in Express team


Posts: 18821
Joined: 2006-05-11
Right.


Andrei Smolin
Add-in Express Team Leader
Posted 27 Jan, 2017 04:38:03 Top