2013-06-28 81 views
3

我寫Delphi應用程序(基本上是爲了管理的服務的圖形用戶界面,它具有以下特徵:允許用戶設置了由服務使用的一些參數和啓動/停止/取消安裝/安裝新版本)。 因此,所有的功能中有一個「不檢點」:在某一點上的應用程序會嘗試卸載和安裝服務的新版本。指定的服務標記爲刪除上Delphi應用程序

隨着ShellExecute我運行以下命令:

C:\myPath\myService.exe /Uninstall 
C:\myPath\myService.exe /Install // this is tipically done to install a newer version of it 

如果該服務已經在運行它成功地卸載了(我得到「成功地卸載」消息),但如果我打開SERVICES.MSC我看到我的服務仍然在服務列表中,但從其popup菜單中禁用了啓動和停止(雖然我希望它沒有列出)。

在這一刻,如果我嘗試安裝,我得到以下錯誤的服務: 「指定的服務被標記爲刪除」

需要注意的是,如果我運行卸載和命令安裝命令提示卸載很好,服務不在services.msc列表中。注意:在這種情況下,我的意思是根本不使用Delphi(或編譯的exe)。

我嘗試了很多技巧,包括卸載後放置一個Sleep(10000),但它沒有工作我也試圖保持services.msc關閉(因爲我讀它可能是一個問題,讓它打開)。

我發現了一個成功的竅門使用以下步驟:

1)我把一個斷點剛剛從德爾福

調用卸載後

2)我去SERVICES.MSC:該服務仍處於列表,即使在「刷新」是STIL列表

3)我打破(從IDE:CTRL + F2)應用

4)我在SERVICES.MSC再去我點擊的exceution 「刷新」按鈕:因爲它,myservice將從列表中刪除應該是

所以我懷疑德爾福XE2(無論是在IDE中調試或運行EXE)以某種方式「鎖定服務」,不允許它被完全卸載。

注:該服務使用另一個德爾福項目建成!

你能幫助我理解由ShellExecute做確實給這個錯誤,爲什麼服務卸載?

非常感謝。

重要提示: 我忘了提及我使用IDE和cmd.exe作爲管理員。

+2

停止該服務,然後將其卸載(淨停止「yourservicename」) – whosrdaddy

+0

是的,我停止它,即使不使用淨停止,但使用WinSvc方式 – LaBracca

+0

也與淨停止我得到了相同.... – LaBracca

回答

3

我有過類似的經歷。在我的代碼中,事實證明我使用了一個變量來保持與服務控制管理器的開放連接。現在,我將所有句柄聲明爲局部變量,並且將服務安裝和卸載。

您可以通過調用DeleteService來卸載服務。在備註部分中,它的內容如下:

The DeleteService function marks a service for deletion from the service control manager database. The database entry is not removed until all open handles to the service have been closed by calls to the CloseServiceHandle function, and the service is not running. A running service is stopped by a call to the ControlService function with the SERVICE_CONTROL_STOP control code. If the service cannot be stopped, the database entry is removed when the system is restarted.

因此,必須停止並且應關閉所有手柄。下面的代碼應該做的伎倆:

function UninstallService(aServiceName: String; aTimeOut: Cardinal): Boolean; 
var 
    ComputerName: array[0..MAX_COMPUTERNAME_LENGTH + 1] of Char; 
    ComputerNameLength, StartTickCount: Cardinal; 
    SCM: SC_HANDLE; 
    ServiceHandle: SC_HANDLE; 
    ServiceStatus: TServiceStatus; 

begin 
    Result:= False; 

    ComputerNameLength:= MAX_COMPUTERNAME_LENGTH + 1; 
    if (Windows.GetComputerName(ComputerName, ComputerNameLength)) then 
    begin 
     SCM:= OpenSCManager(ComputerName, nil, SC_MANAGER_ALL_ACCESS); 
     if (SCM <> 0) then 
     begin 
      try 
       ServiceHandle:= OpenService(SCM, PChar(aServiceName), SERVICE_ALL_ACCESS); 
       if (ServiceHandle <> 0) then 
       begin 

        // make sure service is stopped 
        QueryServiceStatus(ServiceHandle, ServiceStatus); 
        if (not (ServiceStatus.dwCurrentState in [0, SERVICE_STOPPED])) then 
        begin 
         // Stop service 
         ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus); 
        end; 

        // wait for service to be stopped 
        StartTickCount:= GetTickCount; 
        QueryServiceStatus(ServiceHandle, ServiceStatus); 
        if (ServiceStatus.dwCurrentState <> SERVICE_STOPPED) then 
        begin 
         repeat 
          Sleep(1000); 
          QueryServiceStatus(ServiceHandle, ServiceStatus); 
         until (ServiceStatus.dwCurrentState = SERVICE_STOPPED) or ((GetTickCount - StartTickCount) > aTimeout); 
        end; 

        Result:= DeleteService(ServiceHandle); 
        CloseServiceHandle(ServiceHandle); 
       end; 
      finally 
       CloseServiceHandle(SCM); 
      end; 
     end; 
    end; 
end; 

我就砍上面的代碼中的幾個子功能(即QueryServiceStatus,StopService和UninstallService),但用於測試該代碼是否適用於你,我想最好還是寫它在一個簡單的解決方案。最後一點,不要忘記進程需要足夠的權限才能成功執行此代碼。

+0

完美,這工作!使用這個相同的功能。非常感謝! – LaBracca

+1

不客氣。感謝您的300分。我現在覺得非常有把握:-)更重要的一點是,我剛剛注意到上面代碼片段中的一個重要的錯誤。我糾正它,請複製。重複直到塊的超時比較是錯誤的。如果您的服務及時停止,您可能不會注意到這一點。否則,你將永遠處於循環之中,這是一段很長的時間。 – SpaghettiCook

+0

謝謝您的更新,我會檢查它。你應得的300分,這是StackOverflow的工作原理! – LaBracca

2

我覺得你的命令提示符已提升的權限,併爲此是允許真正停止該服務。德爾福可能沒有,或者至少你的項目是不是,所以它允許卸載服務(這是不是刪除從註冊表中的一些值更小),但它實際上並不能停止該服務。

該服務然後'標記爲刪除',因爲它已被卸載,但仍在運行。如果你重新啓動你的電腦,服務將不會再次啓動,你的工具可以安裝新版本。

如果我猜對了,那麼解決方案就是運行你的程序 - 本質上是一個安裝程序 - 作爲管理員,所以它也有權立即停止和刪除服務。

您可能會嘗試的另一件事是先致電net stop <service>停止服務,但我懷疑這是否能解決問題。

+0

哦,我忘了提及,我正在使用IDE和命令提示符「作爲管理員」。我會更新這個問題。 – LaBracca

+0

是的,我認爲是。但我認爲你的項目不會繼承這些管理員權限,所以即使你的IDE以管理員身份運行,你自己的程序,即使從IDE啓動,也不會。雖然不是100%確定的。 – GolezTrol

+2

由提升的IDE啓動的程序繼承了高程 –

相關問題