指定的服务在delphi应用程序上标记为删除

LaB*_*cca 4 delphi service uninstall delphi-xe2

我编写了一个Delphi应用程序(基本上是一个用于管理服务的GUI,它具有以下功能:允许用户设置服务使用的一些参数以及启动/停止/取消挂起/安装新版本).因此,在所有功能中,有一个"行为不正常":在某个时刻,应用程序尝试卸载并安装新版本的服务.

随着ShellExecute我运行以下命令:

C:\myPath\myService.exe /Uninstall
C:\myPath\myService.exe /Install  // this is tipically done to install a newer version of it
Run Code Online (Sandbox Code Playgroud)

如果服务已经运行,它将成功卸载(我得到"成功卸载"消息),但是如果我打开services.msc,我看到myService仍然在服务列表中,但是从其弹出菜单中禁用了"启动"和"停止"(同时我想它根本没有列出.

此时如果我尝试安装该服务,我会收到以下错误:"指定的服务被标记为删除"

请注意,如果我从命令提示符运行卸载和安装命令,卸载就可以了,服务不在services.msc列表中.注意:在这种情况下,我的意思是根本不使用Delphi(或编译的exe).

我尝试了许多技巧,包括放置Sleep(10000)后卸载但它没有工作我也尝试通过保持services.msc关闭(因为我读它可能是一个问题,让它打开).

我使用以下步骤找到了一个成功的技巧:

1)我在从Delphi调用Uninstall之后放了一个断点

2)我去了services.msc:服务仍然在列表中,即使在"刷新"之后它仍然是列表中的stil

3)我打破(从IDE:CTRL + F2)应用程序的优先级

4)我再次在services.msc中单击"刷新"按钮:myservice从列表中删除,因为它应该是

所以我怀疑Delphi XE2(无论是在IDE中调试还是运行exe)都以某种方式"锁定服务"而不允许它完全卸载.

注意:该服务是使用另一个delphi项目构建的!

你能帮我理解为什么服务卸载ShellExecute会产生这个错误吗?

非常感谢.

重要提示: 我忘了提到我使用IDE和cmd.exe作为管理员.

Spa*_*ook 5

我有类似的经历.在我的代码中,我发现我使用了一个变量来保持与服务控制管理器的开放连接.如今,我将所有句柄声明为本地变量和服务即时安装和卸载.

您可以通过调用DeleteService来卸载服务.在备注部分,它写道:

DeleteService函数标记要从服务控制管理器数据库中删除的服务.在通过调用CloseServiceHandle函数关闭服务的所有打开句柄并且服务未运行之前,不会删除数据库条目.通过使用SERVICE_CONTROL_STOP控制代码调用ControlService函数来停止正在运行的服务.如果无法停止该服务,则在重新启动系统时将删除该数据库条目.

因此,它必须停止,你应该关闭所有句柄.下面的代码应该可以解决问题:

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;
Run Code Online (Sandbox Code Playgroud)

我会在几个子函数(即QueryServiceStatus,StopService和UninstallService)中删除上面的代码,但是为了测试这段代码是否适合你,我认为最好用一个简单的解决方案来编写它.最后,请注意,进程需要足够的权限才能成功执行此代码.