線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:6525
推到 Plurk!
推到 Facebook!

CreateOldObject 關閉的問題

答題得分者是:Kingron
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#1 引用回覆 回覆 發表時間:2006-10-12 02:57:27 IP:61.67.xxx.xxx 未訂閱
請問各位:
這是一個老問題, 我查過站上相關討論並沒有確實的答案, 想再重提一次
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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2006-10-25 14:25:53 IP:218.210.xxx.xxx 未訂閱
我想你可以試試 多建立一個Class 而這一個class 功能單純只是用來create Excel ole物件
當你excel關閉時,也free 這一個物件,看看Excel 物件是否會被釋放
00156
高階會員


發表:45
回覆:195
積分:112
註冊:2002-06-01

發送簡訊給我
#3 引用回覆 回覆 發表時間:2006-10-30 22:06:51 IP:61.56.xxx.xxx 未訂閱
您好:
我測試下面的程式碼,並沒有您說的問題耶...
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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2006-10-30 22:07:16 IP:61.56.xxx.xxx 未訂閱
您好:
我測試下面的程式碼,並沒有您說的問題耶...
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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2006-11-05 13:37:05 IP:61.67.xxx.xxx 未訂閱
這是你把 ex: Variant 宣告在 procedure 之中, 而我是告在  public 或 private 之中的原故
Kingron
中階會員


發表:1
回覆:51
積分:60
註冊:2005-09-14

發送簡訊給我
#6 引用回覆 回覆 發表時間:2006-12-11 14:05:06 IP:61.143.xxx.xxx 未訂閱
没有退出原因是因为你有其他的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

發送簡訊給我
#7 引用回覆 回覆 發表時間:2006-12-11 14:33:51 IP:220.130.xxx.xxx 未訂閱
我之前有寫過Word的部份,我想如果會有多的Process應該是因為程式有Exception導致無法正常關閉,
我剛也試了一下,如果單純呼叫Excel作簡單的填值再關閉是沒問題的。
------
不論是否我發的文,在能力範圍皆很樂意為大家回答問題。
為了補我的能力不足之處,以及讓答案可以被重複的使用,希望大家能儘量以公開的方式問問題。
在引述到我的文時自然會儘量替各位想辦法,謝謝大家!
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#8 引用回覆 回覆 發表時間:2006-12-12 16:17:40 IP:61.67.xxx.xxx 未訂閱
的確, 我是把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

發送簡訊給我
#9 引用回覆 回覆 發表時間:2006-12-12 16:45:34 IP:220.228.xxx.xxx 未訂閱
我想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

發送簡訊給我
#10 引用回覆 回覆 發表時間:2006-12-13 17:14:55 IP:211.75.xxx.xxx 未訂閱
突然有一個想法:
利用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

發送簡訊給我
#11 引用回覆 回覆 發表時間:2006-12-14 09:29:57 IP:61.67.xxx.xxx 未訂閱
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

發送簡訊給我
#12 引用回覆 回覆 發表時間:2007-01-12 14:04:03 IP:61.219.xxx.xxx 訂閱
GetActiveOleObject('Word.Application') .....不知是不是您要的
P.D.
版主


發表:603
回覆:4038
積分:3874
註冊:2006-10-31

發送簡訊給我
#13 引用回覆 回覆 發表時間:2007-01-12 17:01:13 IP:61.67.xxx.xxx 未訂閱
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

發送簡訊給我
#14 引用回覆 回覆 發表時間:2007-01-15 09:49:38 IP:61.219.xxx.xxx 訂閱
是阿...粉久不見囉....其實是我潛水...哈哈
試試:
try
msexcel:= GetActiveoleObject('Excel.Application');
except
msexcel:= CreateOleObject('Excel.Application');
end;
註: 1. 您問題標題..打錯字...
2. 前面 kingron 兄已經詳細說明了.

系統時間:2024-07-08 2:18:25
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!