調用Application.Quit()方法時報"This operation cannot be performed in this event handler."錯誤的一種解決方法

前幾天有個同事問我一個問題,就是如何使用子線程打開PPTX文件。開始時我並沒有覺得這是個什麼大問題。因爲我覺得這個主要的難點在於注意線程上下文的切換上。不過開始做個Demo後感覺有點困惑了,主要集中在Application.Quit()方法上。

因爲需求裏希望打開PPT文件進行播放幻燈片,當幻燈片結束時需要關閉PPT文件。這個需求很合理,因爲我們的程序其實就是個打開幻燈片的外殼,如果幻燈片結束後PPT程序還掛在任務欄上,那直接使用PPT不就行了嘛,呵呵。

直入主題啦。使用的程序集就是Microsoft.Office.Interop.PowerPoint.dll,從MSDN的文檔上找到了兩個事件可以解決關閉的時機,SlideShowEnd和PresentationClose事件。

SlideShowEnd事件:一個幻燈片播放結束後發生,最後一次SlideShowNextSlide事件發生後立即發生。(Occurs after a slide show ends, immediately after the last SlideShowNextSlide event occurs.)

PresentationClose事件:任何打開的ppt關閉之前立即發生,當ppt從Presentations集合移除時發生。(Occurs immediately before any open presentation closes, as it is removed from the Presentations collection.)

從說明中選擇在SlideShowEnd事件裏關閉PPT文件。

var _application = new Microsoft.Office.Interop.PowerPoint.Application();
_application.SlideShowEnd += pres=>
{
    pres.Close();
    _application.Quit();
};
第一次打開一個文件並結束幻燈片時一切順利,但是重複幾次同樣的操作,就會報出"Application (unknown member) : Invalid request.  This operation cannot be performed in this event handler."的COMException異常。先後進行了多次修改調用的位置(不使用子線程和使用子線程調用),但是總是運行到Quit方法時報錯,從Google上也沒有找到明確的答案,只是說COM對象是出於STA模式下。

後來突然看到了Open方法的參數說明:

Name

Required/Optional

Data Type

Description

FileName

Required

String

The name of the file to open.

ReadOnly

Optional

MsoTriState

Specifies whether the file is opened with read/write or read-only status.

Untitled

Optional

MsoTriState

Specifies whether the file has a title.

WithWindow

Optional

MsoTriState

Specifies whether the file is visible.

其中WithWindow開始使用的是默認值,即MsoTriState.msoTrue。這樣在關閉幻燈片時,如果不調用Quit方法會留下PPT窗口。而當WithWindow設置爲MsoTriState.msoFalse,則關閉幻燈片不會留下窗口,這樣就不用調用Quit方法了。

var pres = _application.Presentations.Open(path.ToString(),
           MsoTriState.msoTrue,
           MsoTriState.msoFalse,
           MsoTriState.msoFalse);
if (pres.Slides.Count > 0)
{
    pres.SlideShowSettings.Run();
}
修改後的事件代碼:

var _application = new Microsoft.Office.Interop.PowerPoint.Application();
_application.SlideShowEnd += pres=>
{
    pres.Close();    
};
當我的程序關閉時再調用Application.Quit()方法,這樣能保證即關閉了PPT程序,同時也不會因爲打開幾次PPT文件而報錯了。

至於爲什麼不允許在事件中調用Quit,暫時還不清楚,也希望高人指點一下啦,呵呵。同時也希望能夠幫助到其他人。

Demo


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章