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

如何關閉Processes的程序

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


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

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-07-13 12:31:01 IP:61.67.xxx.xxx 未訂閱
再次請問各位!

如何取得工作管理員中我指定的某一個程序(例如EXCEL.EXE),可以透過程式將其關閉,之前我已搜尋過本站拜讀兩位前輩的資料,但測試結果都行不通
http://delphi.ktop.com.tw/board.php?cid=30&fid=67&tid=27841
http://delphi.ktop.com.tw/board.php?cid=30&fid=70&tid=70337

我需要這個功能的目的是因為,我要開啟一個EXCEL來讀入XLS資料,但有時候會發生一些狀況導致當機,結果造成剛才開啟的EXCEL.EXE殘留在Processes中,此時如果程式再重新執行一次,又開啟了一個EXCEL.EXE,如果多來幾次,系統資源就被吃光,所以我想偵測是否有前一次的EXCEL.EXE殘留,如果有則主動釋放,如下程式
但這會有個問題,如果程式很順利執行,msexcel可以取得Processes的ID,在程式完成後執行msexcel.quit可以順利釋放 EXCEL, 但如果程式中途出錯,程式無法正常結束關閉,當再次啟動程式時,msexcel是不存在的值,自然msexcel.quit就無法執行,目前我僅能透過FindProcWnd找到EXCEL.EXE 的程序名稱,但無法利用ExitProcess()來釋放
(我查了一些文獻,發現要釋放Processes,利用ExitProcesses是最乾淨的),所以要如何才能做到我想要的功能,謝謝!

<textarea class="delphi" rows="10" cols="60" name="code"> try if U_VarDef.FindProcWnd('EXCEL.EXE') then begin msexcel.DisplayAlerts:= False; msexcel.Quit; end; except on E:Exception do begin Application.MessageBox(pChar(E.Message #13 #13 '1.請開啟工作管理員' #13 '2.檢查是否有『EXCEL.EXE』的程序存在' #13 '3.如果發現有請手動執行【結束處理程序】' #13 '4.再重新進行【資料匯入】作業...'),'系統訊息',MB_OK); exit; end; end; msexcel:= CreateOleObject('Excel.Application'); workbook := msexcel.WorkBooks.Open(eFile.Text); worksheet:= msexcel.WorkSheets[1]; </textarea>
wameng
版主


發表:31
回覆:1336
積分:1188
註冊:2004-09-16

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-07-13 13:53:22 IP:61.222.xxx.xxx 訂閱
<textarea cols="60" rows="10" class="delphi" name="code"> Procedure KillTask(ProcName: string); procedure KillProcess(dwProcessId: DWORD); var ProcHandle: THandle; begin ProcHandle := OpenProcess(1, FALSE, dwProcessID); try if ProcHandle <> 0 then begin if TerminateProcess(ProcHandle, $FFFFFFFF) then WaitForSingleObject(ProcHandle, INFINITE); end; finally CloseHandle(ProcHandle); end; end; var OK: Bool; hPL: THandle; ProcessStruct: TProcessEntry32; begin hPL := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0); ProcessStruct.dwSize := SizeOf(TProcessEntry32); OK := Process32First(hPL, ProcessStruct); while OK do begin if UpperCase(ProcessStruct.szExeFile) = UpperCase(ProcName) then begin KillProcess(ProcessStruct.th32ProcessID); end; OK := Process32Next(hPL, ProcessStruct); end; CloseHandle(hPL); end; </textarea> 可以先嘗試用 PostQuitMessage 。
eaglewolf
資深會員


發表:4
回覆:268
積分:429
註冊:2006-07-06

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-07-13 14:37:15 IP:211.75.xxx.xxx 訂閱
為何不使用GetActiveOLEObject?
<textarea class="delphi" rows="10" cols="60" name="code"> try msexcel := GetActiveOleObject('Excel.Application') except msexcel := CreateOleObject('Excel.Application'); end; </textarea>
------
先查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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-07-13 23:06:50 IP:61.67.xxx.xxx 未訂閱
感謝wameng版主再次的指教,另外eaglewolf所提出的方式,我測試後的確可以取得並關閉,我只要設定以下的做法,就可以搭配找到Process先關閉
感謝兩位指導,謝謝
<textarea class="delphi" rows="10" cols="60" name="code"> if FindProcWnd('EXCEL.EXE') then begin msexcel:= GetActiveOleObject('Excel.Application'); msexcel.DisplayAlerts:= False; msexcel.Quit; end; </textarea>
Kingron
中階會員


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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-07-14 12:24:22 IP:125.89.xxx.xxx 訂閱
GetActiveOleObject的确是正确的解决之道,不过你的方法好奇怪哈。
如果有另外一个程序的档名也叫做Excel.exe,你的程序就挂了。

两个问题:
首先这样:
const
CSExcelClassName = 'Excel.Application';
try
msexcel := GetActiveOleObject(CSExcelClassName);
except
try
msexcel = CreateOleObject(CSExcelClassName );
except
ShowMessage('Excel 可能没有正常安装!');
Exit;
end;
end;
/// do something with msexcel....

另外一个问题:
你的代码没有正常Quit,是你没有正确处理异常,你应该正确处理异常!
try
....
msexcel....
finally
VarClear(excelbook);
VarClear(excelsheet);
.... and so on
msexcel.Quit; // 这里
VarClear(msexcel); ////这里
end;
===================引 用 P.D. 文 章===================
感謝wameng版主再次的指教,另外eaglewolf所提出的方式,我測試後的確可以取得並關閉,我只要設定以下的做法,就可以搭配找到Process先關閉
感謝兩位指導,謝謝
<textarea class="delphi" rows="10" cols="60" name="code">if FindProcWnd('EXCEL.EXE') then begin msexcel:= GetActiveOleObject('Excel.Application'); msexcel.DisplayAlerts:= False; msexcel.Quit; end; </textarea>
------
超级猛料:http://kingron.delphibbs.com
P.D.
版主


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

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-07-15 00:31:55 IP:61.67.xxx.xxx 未訂閱
感謝kingron的說明,讓我又學習到一個用法,否則我還真不知有varclear()的用法
不過這個varclear 與 quit 的關係如何,我看了一下說明不是很清楚,是不是與
form1.free 並未真正釋放該記憶區塊,所以都會以FreeandNil()或Form1:= nil再徹底消減該變數的道理相同呢?

但對於 worksheet, workbook 也要如此做,我就存在很大的好奇心了。

另外,對於excel.exe 未被正確處理異常,這有時實在很難控制,例如可能對方執行另一個程式也啟動excel, 或者直接呼叫excel ,或者在我的程式中啟動了excel, 但中途當機,這都不是 try ... except 可以捕捉的到然後再正常的釋放的情況,所以才會想搜尋Processes中是否有殘留的EXCEL.EXE 存在,而的確如果有很多個EXCEL.EXE存在時,GETATIVEOLDOBJECT()的確會產生一些問題,不過還好目前會用EXCEL.EXE 的基本上只有OFFICE,而且我們處理這段只是提供給使用者能減少一些手動釋放動作,如果真有問題,還是得請他們自行在工作管理員做處理。
編輯記錄
P.D. 重新編輯於 2007-07-15 00:38:25, 註解 無‧
Kingron
中階會員


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

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-07-15 03:12:02 IP:125.89.xxx.xxx 訂閱
VarClear就是和 sheet := nil一样类似的效果,可以认为是对Variant的FreeAndNil。
至于为什么对WorkSheet和WorkBook等等也要类似处理,这是因为应用计数导致的。

Delphi本身对COM是隐式进行了AddRef和ReleaseRef的,不需要我们显示调用,但这里有一个前提就是你的顺序很重要!
例如以下的例子:
假设:
Var
App, Book, Sheet: OleVariant;

// 这是创建和使用
App = Create Excel OLE Variant Object;
Book = App.WorkBooks.Add;
Sheet = Book.Sheets("Sheet1");
do something...

上面的代码会导致这些变量被顺序增加引用计数:Book这一行会隐式给App的Ref 1!其余类似

.// 以下是释放,应该严格遵守反向的顺序
VarClear(Sheet); --> 1
VarClear(Book); --> 2
App.Quit; --> 3
VarClear(App); --> 4

上面的代码中,如果 2和1交换,就可能出现一个不好的现象:
Book的计数被-1,但实际上,Book的子对象被引用了,也就是那个Sheet没有释放,从而导致Sheet在内存中还是真正存在的,但对程序代码来说,Book已经被释放掉了!
同样的道理,如果3方在1的前面,就出现问题了!
App.Quit会试图去Quit Excel,此时App变量是Free掉了,我们不能再使用,但是因为Shee和Book还在,OLE为了保证安全,在内存中还是需要维持Excel进程的,因此Quit并没有真正生效!这也就是很多时候Quit不正常的原因:在某些时候,OLE调用出错,结果某些局部的OLE变量,例如Sheet,Graph等没有正常释放,导致Quit不能正常退出Excel。

所有的错误都是可以抓住的,看你的编程习惯而已。如果偷懒,可以在调用的例程最外面添加一个try except end捕获异常即可。
如果在操作的时候,最好是Disable Excel的ScreenUpdating = False; Interactiv = False,禁止用户操作和更新界面,以保证安全和提高效率,即使中途Crash,也可以用try except 抓取得,实际上是个体力活,但可以保证代码质量。

很多病毒使用EXCEL的进程名哈~

当然,Kill Excel 进程的做法也是可取的,但可能会导致用户丢失数据

===================引 用 P.D. 文 章===================
感謝kingron的說明,讓我又學習到一個用法,否則我還真不知有varclear()的用法
不過這個varclear 與 quit 的關係如何,我看了一下說明不是很清楚,是不是與
form1.free 並未真正釋放該記憶區塊,所以都會以FreeandNil()或Form1:= nil再徹底消減該變數的道理相同呢?

但對於 worksheet, workbook 也要如此做,我就存在很大的好奇心了。

另外,對於excel.exe 未被正確處理異常,這有時實在很難控制,例如可能對方執行另一個程式也啟動excel, 或者直接呼叫excel ,或者在我的程式中啟動了excel, 但中途當機,這都不是 try ... except 可以捕捉的到然後再正常的釋放的情況,所以才會想搜尋Processes中是否有殘留的EXCEL.EXE 存在,而的確如果有很多個EXCEL.EXE存在時,GETATIVEOLDOBJECT()的確會產生一些問題,不過還好目前會用EXCEL.EXE 的基本上只有OFFICE,而且我們處理這段只是提供給使用者能減少一些手動釋放動作,如果真有問題,還是得請他們自行在工作管理員做處理。
------
超级猛料:http://kingron.delphibbs.com
P.D.
版主


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

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-07-16 09:51:35 IP:61.67.xxx.xxx 未訂閱
十分感謝 Kingron 這麼詳細的解說,我想在oleobject這塊領域Kingron應該有十足的功力,畢竟在Office的搭配上Delphi的技術資料實在少的可憐,未來要請Kingron協助的還有很多地方,希望Kingron不吝指教,謝謝!
系統時間:2024-04-27 2:55:21
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!