2013-12-17 61 views
2

我需要從應用程序生成並使用Outlook發送郵件。 郵件表單應該顯示爲模式,主要是因爲我生成的附件,當用戶發送電子郵件(或放棄它)時應該刪除。在Outlook中生成新郵件並顯示爲模式

我的問題是當我使Outlook對話框模式(「MailIt.Display(True)」),在後臺顯示的Outlook消息窗口。命令「Outlook.ActiveWindow.Activate」將它放在前面,但是可以在窗口已經可見時調用它,所以如果窗口是模態的,我不能調用它。我想這樣的代碼:

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

但ID不能正常工作,如果形式已經顯示其正常模式下無法切換到模態。有任何想法嗎? 我的環境:Windows 8(UAC被禁用),XE3,Outlook 2010中

只是想我的形式發送到後臺的建議由亞略:

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

在這種情況下,展望前景成爲了(因爲我需要它),但我的from可以變得不可見(如果有其他正在運行的應用程序打開表單),所以它也不能解決問題。它應該是頂部的模態狀態的Outlook,我的應用程序位於Outlook旁邊。

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

更好的是HWND_BOTTOM,但不保證Outlook成爲前景。

EDITED2。 決賽(希望)解決方案基於事件(建議從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; 

所以它是解決(試行#3)。謝謝!

+0

它可以從一個單獨的線程調用嗎? –

+0

@Arioch:是的,在單獨的線程中調用它或在主線程中調用它並不是一個問題,而是從另一個線程移動到前臺。但我不確定從另一個線程調用Outlook.ActiveWindow.Activate是否安全。 –

+0

@Arioch:來自MSDN:「當後臺線程調用Office應用程序時,該調用將自動跨STA邊界封送...... Excel可能處於無法立即處理來電的狀態。例如,Office應用程序可能會顯示一個模式對話框。「所以看起來,如果窗體顯示模態,然後調用對象可能無法從另一個線程工作。 –

回答

1

如果您無法將Outlook放在前面,也許您可​​以通過發佈來自輔助線程的消息將自己的應用推送到後面?

+0

我甚至不需要另一個線程,它足以使表單NOTOPMOST :)謝謝你的幫助! –

+0

很高興幫助並感謝您與所有人分享解決方案 –

相關問題