问题
Sometimes when I uninstall the setup (made with WIX) the service remain marked for deletion, and the user must restart the machine to install again. How could I verify that the service is marked for deletion and tell to the user to restart the computer before making other installation?
回答1:
Generally speaking, this scenario occurs when something remains latched onto that service, preventing Windows from removing its configuration in the registry. (In most cases, it's simply the Services applet -- services.msc -- left open by accident in the background.)
For detection, I suggest you read up on CreateService and other Service API. For example, you'll receive ERROR_SERVICE_MARKED_FOR_DELETE upon calling CreateService if the service is marked for deletion.
Regarding your proposed reboot solution... Windows has advanced far enough to not require a reboot for nearly any reason. Unless you're installing specialized kernel drivers, you do not need to reboot. Don't be lazy! Keep the user in mind! I recommend altering your installer logic to detect potentially conflicting running programs, like the Services applet, and suggest closure.
回答2:
I can't find an API way to do it (which doesn't involve calling either CreateService
or DeleteService
, both having undesired side effects), but
HKLM\SYSTEM\CurrentControlSet\Services\ServiceName
containing a DeleteFlag=1
(REG_DWORD) value seems to be pretty indicative of this unfortunate state.
回答3:
Here is an SO post that may help you. Although the original question is for service installation, the answer also covers uninstalls and statuses.
How to install a windows service programmatically in C#?
Here is an article that explains why you may receive the "marked for deletion" message in the first place and how to get around it.
http://weblogs.asp.net/avnerk/archive/2007/09/05/windows-services-services-msc-and-the-quot-this-service-is-marked-for-deletion-quot-error.aspx
EDIT
Per Christopher Painter's comment, I'm updating this answer for intentions to promote best practices. While receiving the "marked for deletion" message has more often been (in my experience) the result of having the services.msc console than unreleased resources, writing a Custom Action to reboot is not the best way.
To schedule reboot after WiX processing, use WiX XML (explained how to with Wix# here) as follows:
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
...
<InstallExecuteSequence>
<ScheduleReboot After="InstallFinalize"/>
<InstallExecuteSequence>
</Wix>
回答4:
Are you using the ServiceControl element/table to stop the service during the uninstall? If so, Does your service successfully stop? If not, look into what's going on inside your service to make sure it releases all of it's resources and shuts down gracefully when requested.
You shouldn't need to be writing any custom actions to programatically call the SCM API. Windows Installer should be able to handle this for you.
回答5:
In my case the service was marked for deletion after uninstalling it, because I didn't dispose an object properly (rabbitmq-connection in my case).
This is not a direct answer on the question but may help to solve the root-issue of it.
回答6:
I also searched for the solution that to determine whether a service is existent or marked for deletion even though OpenService
succeeds. I also found that the error code ERROR_SERVICE_MARKED_FOR_DELETE
returned by ChangeServiceConfig
. So, here is the way to check whether a service is marked for deletion through ChangeServiceConfig
with C/C++:
BOOL SetDisplayName(SC_HANDLE schService, LPCTSTR lpDisplayName)
{
return ChangeServiceConfig(schService, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, lpDisplayName);
}
//
// You need to obtain the hSCManager through OpenSCManager first
//
SC_HANDLE schService = OpenService(hSCManager, pszServiceName, SERVICE_CHANGE_CONFIG);
if (schService != nullptr)
{
//
// obtain the display name of a service
//
TCHAR szDisplayName[0x1000] = { 0 };
DWORD cchDisplayName = ARRAYSIZE(szDisplayName);
bResult = GetServiceDisplayName(schService, pszServiceName, szDisplayName, &cchDisplayName);
if (bResult)
{
//
// change the display name to the original display name
//
bResult = SetDisplayName(schService, szDisplayName);
if (!bResult)
{
DWORD dwError = GetLastError();
switch (dwError) {
case ERROR_ACCESS_DENIED:
case ERROR_CIRCULAR_DEPENDENCY:
case ERROR_DUPLICATE_SERVICE_NAME:
case ERROR_INVALID_SERVICE_ACCOUNT:
break;
case ERROR_INVALID_HANDLE:
break;
case ERROR_INVALID_PARAMETER:
break;
//
// the service is marked for deletion
//
case ERROR_SERVICE_MARKED_FOR_DELETE:
break;
default:
break;
}
}
}
}
else
{
DWORD dwError = GetLastError();
switch (dwError) {
case ERROR_ACCESS_DENIED:
break;
case ERROR_INVALID_HANDLE:
break;
case ERROR_INVALID_NAME:
break;
case ERROR_SERVICE_DOES_NOT_EXIST:
break;
default:
break;
}
}
来源:https://stackoverflow.com/questions/5321825/verify-if-a-service-is-marked-for-deletion