CreateOldObject 關閉的問題 |
答題得分者是:Kingron
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
請問各位:
這是一個老問題, 我查過站上相關討論並沒有確實的答案, 想再重提一次 CreateOleObject(Excel.Application) 可以打開一份Excel系統, 但使用 myExcel.Quit 及 myExcel.Unassigned方式都只能令 Excel系統關閉, 可是仔細去查看工作管理員(Process Management), 有一份 Excel.exe仍掛在Process中無法被釋放, 除非程式結束才會被釋出, 請問, 如何取得 Excel.exe的process進而把它關閉, 否則每次一執行 CreateOleOjbect()就會多一份Excel.exe在Process中, 不用幾次系統資源就完玩了, 我再在的做法是去取得目前所有Process工作序的內容, 然後檢查是否有Excel.exe存在, 如果有則不再建立CreateOleObject, 這樣治標方式至少只會有一份Excel.exe存在, 但我仍然希望可以不用關閉程式而能令Excel.exe離開Process內存服務, 謝謝! |
liorex_60056
一般會員 發表:0 回覆:2 積分:0 註冊:2006-07-20 發送簡訊給我 |
|
00156
高階會員 發表:45 回覆:195 積分:112 註冊:2002-06-01 發送簡訊給我 |
您好:
我測試下面的程式碼,並沒有您說的問題耶... unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComObj, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var ex:Variant; begin ex:=CreateOleObject('Excel.Application'); try ShowMessage('test'); finally ex.Quit; end; end; end. 當ShowMessage時,檢查系統程序有一個Excel,按下確定鍵後,該程序便自動消失了… |
00156
高階會員 發表:45 回覆:195 積分:112 註冊:2002-06-01 發送簡訊給我 |
您好:
我測試下面的程式碼,並沒有您說的問題耶... unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComObj, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var ex:Variant; begin ex:=CreateOleObject('Excel.Application'); try ShowMessage('test'); finally ex.Quit; end; end; end. 當ShowMessage時,檢查系統程序有一個Excel,按下確定鍵後,該程序便自動消失了… |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
|
Kingron
中階會員 發表:1 回覆:51 積分:60 註冊:2005-09-14 發送簡訊給我 |
没有退出原因是因为你有其他的OLE变量引用了Excel Book,Sheet之类的对象。你应该把所有的ExcelSheet,Chart,WorkBook等对象全部VarClear掉,然后调用ExcelApp.Quit 就可以了。
另外如果Excel退出的时候,如果有对话框隐藏没有关闭,也可能不能正常退出,例如你修改了文档,但Quit没有强制保存或不保存,那么就会弹出一个对话框,也必须处理了这个对话框才能退出。 第三个方法是:首先调用GetActiveOleObject()来获取当前已经有的Excel Application,在失败的时候才调用CreateOleObject,这样可以使用已有的Excel进程: function GetObject(const ObjectName: string): OleVariant; stdcall; { 连接/返回指定的对象,失败返回NULL 例如: WordApp := GetObject('Word.Application'); } begin Result := 0; try Result := GetActiveOleObject(ObjectName); except Result := CreateOleObject(ObjectName); end; end;
------
超级猛料:http://kingron.delphibbs.com |
Coffee
版主 發表:31 回覆:878 積分:561 註冊:2006-11-15 發送簡訊給我 |
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
的確, 我是把OLE變數宣告在PRIVATE, 或 PUBLIC的地方, 而我發現一旦OLE在被CREATE之後, 系統已經在記憶體上切出使用, 而我找不到FREENIL功能, 所以就算把EXCEL關閉, 該變數仍存在, 才導致 EXCEL.EXE無法從PROCESS中被釋放, 而如果我把 OLE宣告在 PROCEDURE 中, 當該PROCEDURE 完成THEAD之後, PROCEDURE被自然釋放, 跟著EXCEL也會被釋放掉, 所以EXCEL.EXE就不存在(我不知道這個理論是否正確, 但實測確實如此), 所以我現在也是用這樣的方法來判斷EXCEL.EXE是否存在, 如果存在就不要CREATEOLE, 直接調用即可! 以上, 謝謝!
===================引 用 文 章=================== 没有退出原因是因为你有其他的OLE变量引用了Excel Book,Sheet之类的对象。你应该把所有的ExcelSheet,Chart,WorkBook等对象全部VarClear掉,然后调用ExcelApp.Quit 就可以了。 另外如果Excel退出的时候,如果有对话框隐藏没有关闭,也可能不能正常退出,例如你修改了文档,但Quit没有强制保存或不保存,那么就会弹出一个对话框,也必须处理了这个对话框才能退出。 |
Coffee
版主 發表:31 回覆:878 積分:561 註冊:2006-11-15 發送簡訊給我 |
我想Word跟Excel應該是一樣的吧..我之前寫的大概是這樣..
type TWordProcessor=class constructor Create;overload; constructor Create(FilePath : WideString);overload; destructor Destroy;override; private fWordInUse : boolean; fWordApp : Variant; fDocument : Variant; fDocName : WideString; fSelection : Variant; procedure fCloseWordApp; public procedure OpenFile(FilePath : WideString); procedure CloseFile(pSave : Boolean = True); procedure ReplaceTableText(pTableItem : variant; pX : integer; pY : integer; pText : WideString); procedure AppendRow(pTableItem : variant; pFillData : variant); procedure SchemaToWord;virtual; end; implementation procedure TWordProcessor.fCloseWordApp; begin if fWordInUse then begin fDocument.Close(wdDoNotSaveChanges);//Call Save to SaveFile fDocName:=''; fWordApp.Quit; end; end; constructor TWordProcessor.Create; begin inherited; SetLength(fCatalogArray, 0); fWordInUse:=false; fCatalogStyleName:=CATALOG_STYLE_TITLE; end; constructor TWordProcessor.Create(FilePath : WideString); begin Create; OpenFile(FilePath); end; procedure TWordProcessor.OpenFile(FilePath : WideString); begin if FileExists(FilePath) then begin fWordApp:=CreateOleObject('Word.Application'); fWordApp.Visible:=false; fDocument:=fWordApp.Documents.Open(FilePath); fDocument.ReadOnlyRecommended:=false; fSelection:=fWordApp.Selection; //fDocName:=ExtractFilePath( fWordInUse:=True; fLoadCatalogArray end else Exception.Create('Word檔不存在下列路徑:' FilePath); end; destructor TWordProcessor.Destroy; begin if fWordInUse then fCloseWordApp; inherited; end; procedure TWordProcessor.CloseFile(pSave : Boolean = True); begin if pSave then fDocument.Save; fCloseWordApp; end; 我是拿來作輸出資料庫對應表格資料,fWordApp本身就是一個指向Word OLE的OleVariant, 只有在Exception時才會產生異常。
------
不論是否我發的文,在能力範圍皆很樂意為大家回答問題。 為了補我的能力不足之處,以及讓答案可以被重複的使用,希望大家能儘量以公開的方式問問題。 在引述到我的文時自然會儘量替各位想辦法,謝謝大家! |
eaglewolf
資深會員 發表:4 回覆:268 積分:429 註冊:2006-07-06 發送簡訊給我 |
突然有一個想法:
利用API去判斷excel.exe 的 process handle是否存在(可能會有excel version的問題) 若handle大於0表示已存在,則直接調用。 若handle等於0表示不存在,則使用CreateOleObject。 ===================引 用 文 章=================== 的確, 我是把OLE變數宣告在PRIVATE, 或 PUBLIC的地方, 而我發現一旦OLE在被CREATE之後, 系統已經在記憶體上切出使用, 而我找不到FREENIL功能, 所以就算把EXCEL關閉, 該變數仍存在, 才導致 EXCEL.EXE無法從PROCESS中被釋放, 而如果我把 OLE宣告在 PROCEDURE 中, 當該PROCEDURE 完成THEAD之後, PROCEDURE被自然釋放, 跟著EXCEL也會被釋放掉, 所以EXCEL.EXE就不存在(我不知道這個理論是否正確, 但實測確實如此), 所以我現在也是用這樣的方法來判斷EXCEL.EXE是否存在, 如果存在就不要CREATEOLE, 直接調用即可! 以上, 謝謝!
------
先查HELP 再查GOOGLE 最後才發問 沒人有義務替你解答問題 在標題或文章中標明很急 並不會增加網友回答速度 Developing Tool: 1.Delphi 6 2.Visual Studio 2005 3.Visual Studio 2008 DBMS: MS-SQL |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
function ListAllProcWnd(var SL: TStringList): TStringList;
var hSS: THandle ; ppp: TProcessEntry32 ; dwPID: DWORD ; begin SL.Sorted:= True; GetWindowThreadProcessID(0,@dwPID); hSS:= CreateToolhelp32Snapshot(TH32CS_SNAPProcess,dwPID); if Process32First(hSS, ppp) then begin // SL.Add(strpas(ppp.szExeFile)); --> 加入 [System Process] 字樣 while Process32Next(hSS,ppp) do SL.Add(strpas(ppp.szExeFile)); end ; closeHandle(hSS); result:= SL; end; function FindProcWnd(exename: string): boolean; var hSS: THandle; ppp: TProcessEntry32; dwPID: DWORD; msl: string; mrest: boolean; begin mrest:= False; GetWindowThreadProcessID(0,@dwPID); hSS:= CreateToolhelp32Snapshot(TH32CS_SNAPProcess,dwPID); if Process32First(hSS, ppp) then begin while Process32Next(hSS,ppp) do begin msl:= Ansiuppercase(strpas(ppp.szExeFile)); if msl=exename then begin mrest:= True; break; end; end; end ; closeHandle(hSS); result:= mrest; end; 我現在就是利用這兩組來檢查Process是否存在, 如果不存在就CreateOleOjbect, 這兩組不是我寫出來的, 而站上的前輩提供的資訊, 我再做小部份修正成我要的function ===================引 用 文 章=================== 突然有一個想法: 利用API去判斷excel.exe 的process handle是否存在(可能會有excel version的問題) 若handle大於0表示已存在,則直接調用。 若handle等於0表示不存在,則使用CreateOleObject。 |
Mickey
版主 發表:77 回覆:1882 積分:1390 註冊:2002-12-11 發送簡訊給我 |
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
Mickey 兄好久不見囉!
您提出的方法好像可以用, 不過因為 GetActiveoleObject 回傳並不是一個boolean值, 我不太會使用如果偵測到 GetActiveoleOjbect('Excel Application') 中的process EXCEL.EXE 已經存在時的判斷, 我看過help的內容, 提到如果 找不到指定的Ojbect 會觸發EOleSysError exception的事件, 所以我這樣來寫不知道是否對不對 try GetActiveoleObject('Excel.Application'); except msexcel:= CreateOleObject('Excel.Application'); end; |
Mickey
版主 發表:77 回覆:1882 積分:1390 註冊:2002-12-11 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |