【问题标题】:Generate new message in Outlook and display as modal在 Outlook 中生成新消息并显示为模式
【发布时间】:2014-01-05 03:17:57
【问题描述】:

我需要从应用程序使用 Outlook 生成和发送消息。 邮件表单应显示为模态,主要是因为我生成附件,并且在用户发送电子邮件(或丢弃它)时应将其删除。

我的问题是当我制作 Outlook 对话框模式(“MailIt.Display(True)”)时,Outlook 消息窗口显示在背景中。命令“Outlook.ActiveWindow.Activate”将它带到前面,但是当窗口已经可见时可以调用它,所以如果窗口是模态的,我不能调用它。我试过这段代码:

MailIt.Display(False);
OleVariant(Outlook.ActiveWindow).Activate;
MailIt.Display(True);

但是 id 不起作用,如果 form 已经显示为正常模式,则无法切换到模态。有任何想法吗? 我的环境:Windows 8(禁用 UAC)、XE3、Outlook 2010。

刚刚尝试按照 Arioch 的建议将我的表单发送到后台:

SetWindowPos(AWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
MailIt.Display(AModal);
SetForegroundWindow(AWnd);

在这种情况下 Outlook 成为前台(因为我需要它),但我的 from can 变得不可见(如果有其他正在运行的应用程序打开了表单),所以它也不能解决问题。它应该是顶部处于模态状态的 Outlook,而我的应用程序位于 Outlook 旁边。

SetWindowPos(AWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE) 

优于 HWND_BOTTOM,但不能保证 Outlook 成为前台。

已编辑2。 基于事件的最终(希望)解决方案(来自 Kobik 的建议):

uses
  Vcl.OleServer, Winapi.ActiveX;

Type
  TOutlookMsgForm = class
  private
  protected
    FOutlook: OutlookApplication;
    FMessageSent: Boolean;

    procedure OnOpen(ASender: TObject; var Cancel: WordBool);
    procedure OnSend(ASender: TObject; var Cancel: WordBool);
    function  TryDisplayOutlookMail(const AMailTo, ASubject, ABody: string;
      const AAttachmentFileNames: array of string; AWnd: HWND; AModal: Boolean): boolean;

    property Outlook: OutlookApplication read FOutlook write FOutlook;
    property MessageSent: Boolean read FMessageSent write FMessageSent;
  public
    class function DisplayOutlookMail(const AMailTo, ASubject, ABody: string;
      const AAttachmentFileNames: array of string; AWnd: HWND; AModal: Boolean = True): boolean; static;
  end;

{ TOutlookMsgForm }

procedure TOutlookMsgForm.OnOpen(ASender: TObject; var Cancel: WordBool);
begin
  if (Outlook<>nil) and (Outlook.ActiveWindow<>nil) then
    OleVariant(Outlook.ActiveWindow).Activate;
end;

procedure TOutlookMsgForm.OnSend(ASender: TObject; var Cancel: WordBool);
begin
  Cancel := False;
  MessageSent := True;
end;

function TOutlookMsgForm.TryDisplayOutlookMail(const AMailTo, ASubject, ABody: string;
  const AAttachmentFileNames: array of string; AWnd: HWND; AModal: Boolean): boolean;
var
  MailIt: MailItem;
  Mail: TMailItem;
  i: Integer;
begin
  MessageSent := False;
  try
    OleInitialize(nil);
    try
      Outlook := CoOutlookApplication.Create;
      Mail := nil;
      try
        MailIt := Outlook.CreateItem(olMailItem) as MailItem;
        MailIt.To_ := AMailTo;
        MailIt.Subject := ASubject;
        MailIt.Body := ABody;
        for i := Low(AAttachmentFileNames) to High(AAttachmentFileNames) do
          MailIt.Attachments.Add(AAttachmentFileNames[i], EmptyParam, EmptyParam, EmptyParam);
        Mail := TMailItem.Create(nil);
        Mail.ConnectTo(MailIt);
        Mail.OnOpen := OnOpen;
        Mail.OnSend := OnSend;
        MailIt.Display(AModal);
        if AModal and (AWnd<>0) then
          SetForegroundWindow(AWnd);
        Result := true;
      finally
        FreeandNil(Mail);
        MailIt := nil;
        Outlook := nil;
      end;
    finally
      OleUnInitialize;
    end;
  except
    Result := False;
  end;
end;

这样就解决了(try#3)。谢谢!

【问题讨论】:

  • 可以从单独的线程调用吗?
  • 那么也许你可以 PostMessage 你的窗口去后面?
  • 类似问题:stackoverflow.com/questions/9972866/… 我无法使用 D5/XP 重现 :-P 您是否尝试过先禁用窗口? (查看应用程序模式循环如何工作)
  • 您可以创建一个TMailItem 并通过TMailItem.Connect(MailIt) 连接到MailIt,然后使用TMailItem.OnOpen := YourMailOnOpenEvent,然后在该事件上找到Outlook 窗口句柄。只是一个想法......(看这里:stackoverflow.com/questions/5507342/…
  • @kobik:我刚刚测试过,在 Display(True) 之前调用 SetWindowPos(AWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE) 就足够了,然后显示为应该。但是感谢您对活动的想法!

标签: delphi outlook


【解决方案1】:

如果您无法将 Outlook 放在前面,也许您可​​以通过从辅助线程发布消息将自己的应用程序推到后面?

【讨论】:

  • 我什至不需要另一个线程,它足以使表单NOTOPMOST :) 谢谢你的帮助!
  • 很高兴它帮助并感谢您与大家分享解决方案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-10
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多