Skip to content

InstallServiceAsync: SetServiceDescription called with zero handle when CreateService fails #158

@Christophe-Rogiers

Description

@Christophe-Rogiers

Bug

In ServiceManager.InstallServiceAsync, when CreateService fails (returns IntPtr.Zero) and the service does not already exist, execution falls through to line 508 where SetServiceDescription(serviceHandle, ...) is called with serviceHandle = IntPtr.Zero.

Flow

CreateService() → returns IntPtr.Zero (failure)

if (serviceHandle == IntPtr.Zero)          // line 452
{
    if (IsServiceInstalled(...))           // line 454
    {
        // Service exists → update config → return true
    }
    // ⚠️ If service is NOT installed: falls through
}

SetServiceDescription(serviceHandle, ...)  // line 508 → serviceHandle is ZERO

Impact

  • SetServiceDescription only checks if description is empty — not if the handle is valid
  • If a description is provided, ChangeServiceConfig2W is called with a zero handle
  • This throws a Win32Exception that masks the real reason CreateService failed (e.g. insufficient permissions, invalid binary path)
  • The misleading exception makes debugging harder

Suggested fix

Add an early return after the if block when serviceHandle is still zero:

if (serviceHandle == IntPtr.Zero)
{
    var isInstalled = IsServiceInstalled(options.ServiceName);
    if (isInstalled)
    {
        // ... existing update logic ...
        return true;
    }

    int error = Marshal.GetLastWin32Error();
    Logger.Error($"Failed to create service '{options.ServiceName}'. Win32 error: {error}");
    return false;   // ← missing early return
}

// serviceHandle is guaranteed valid here
SetServiceDescription(serviceHandle, options.Description);

File

src/Servy.Core/Services/ServiceManager.cs — line ~508

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions