Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Fix ServiceController name population perf #32072

Merged
merged 21 commits into from
Sep 4, 2018
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,9 +11,9 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ChangeServiceConfig2(IntPtr serviceHandle, uint infoLevel, ref SERVICE_DESCRIPTION serviceDesc);
public static extern bool ChangeServiceConfig2(SafeServiceHandle serviceHandle, uint infoLevel, ref SERVICE_DESCRIPTION serviceDesc);

[DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ChangeServiceConfig2(IntPtr serviceHandle, uint infoLevel, ref SERVICE_DELAYED_AUTOSTART_INFO serviceDesc);
public static extern bool ChangeServiceConfig2(SafeServiceHandle serviceHandle, uint infoLevel, ref SERVICE_DELAYED_AUTOSTART_INFO serviceDesc);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,7 +11,7 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
internal extern unsafe static bool ControlService(IntPtr serviceHandle, int control, SERVICE_STATUS* pStatus);
internal extern unsafe static bool ControlService(SafeServiceHandle serviceHandle, int control, SERVICE_STATUS* pStatus);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,7 +11,7 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
public extern static IntPtr CreateService(IntPtr databaseHandle, string serviceName, string displayName, int access, int serviceType,
public extern static IntPtr CreateService(SafeServiceHandle databaseHandle, string serviceName, string displayName, int access, int serviceType,
int startType, int errorControl, string binaryPath, string loadOrderGroup, IntPtr pTagId, string dependencies,
string servicesStartName, string password);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -11,9 +12,9 @@ internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, EntryPoint = "EnumDependentServicesW", CharSet = CharSet.Unicode, SetLastError = true)]
internal extern static bool EnumDependentServices(
IntPtr serviceHandle,
SafeServiceHandle serviceHandle,
int serviceState,
IntPtr bufferOfENUM_SERVICE_STATUS,
SafeAllocHHandle bufferOfENUM_SERVICE_STATUS,
int bufSize,
ref int bytesNeeded,
ref int numEnumerated);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -11,11 +12,11 @@ internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, EntryPoint = "EnumServicesStatusExW", CharSet = CharSet.Unicode, SetLastError = true)]
internal extern static bool EnumServicesStatusEx(
IntPtr databaseHandle,
SafeServiceHandle databaseHandle,
int infolevel,
int serviceType,
int serviceState,
IntPtr status,
SafeAllocHHandle status,
int size,
out int bytesNeeded,
out int servicesReturned,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Buffers;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

internal partial class Interop
{
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, EntryPoint = "GetServiceDisplayNameW", CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true)]
private static extern bool GetServiceDisplayNamePrivate(SafeServiceHandle SCMHandle, string serviceName, ref char displayName, ref int displayNameLength);

public static unsafe string GetServiceDisplayName(SafeServiceHandle SCMHandle, string serviceName, bool throwOnError)
{
var builder = new ValueStringBuilder(4096);
int bufLen;
while (true)
{
bufLen = builder.Capacity;
if (GetServiceDisplayNamePrivate(SCMHandle, serviceName, ref builder.GetPinnableReference(), ref bufLen))
break;

int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
{
if (throwOnError)
throw new Win32Exception(lastError);

return null; // Caller may want to try something else
}

builder.EnsureCapacity(bufLen + 1); // Does not include null
}

builder.Length = bufLen;
return builder.ToString();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Buffers;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

internal partial class Interop
{
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, EntryPoint = "GetServiceKeyNameW", CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true)]
private static extern bool GetServiceKeyNamePrivate(SafeServiceHandle SCMHandle, string displayName, ref char KeyName, ref int KeyNameLength);

public static unsafe string GetServiceKeyName(SafeServiceHandle SCMHandle, string displayName, bool throwOnError)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the throwOnError is over-engineered since this is always used with the same value.

It is why we typically have the wrapper code like this in implementation, and not under Common.

{
Span<char> initialBuffer = stackalloc char[256];
var builder = new ValueStringBuilder(initialBuffer);
int bufLen;
while (true)
{
bufLen = builder.Capacity;
if (GetServiceKeyNamePrivate(SCMHandle, displayName, ref builder.GetPinnableReference(), ref bufLen))
break;

int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
{
if (throwOnError)
throw new Win32Exception(lastError);

return null; // Caller may want to try something else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is expected to be a "common" path, this should dispose the buffer.

}

builder.EnsureCapacity(bufLen + 1); // Does not include null
}

builder.Length = bufLen;
return builder.ToString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,6 +11,6 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, EntryPoint = "OpenServiceW", CharSet = CharSet.Unicode, SetLastError = true)]
internal extern static IntPtr OpenService(IntPtr databaseHandle, string serviceName, int access);
internal extern static IntPtr OpenService(SafeServiceHandle databaseHandle, string serviceName, int access);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,7 +11,7 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, EntryPoint = "QueryServiceConfigW", CharSet = CharSet.Unicode, SetLastError = true)]
internal extern static bool QueryServiceConfig(IntPtr serviceHandle, IntPtr queryServiceConfigPtr, int bufferSize, out int bytesNeeded);
internal extern static bool QueryServiceConfig(SafeServiceHandle serviceHandle, SafeAllocHHandle queryServiceConfigPtr, int bufferSize, out int bytesNeeded);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,7 +11,7 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern unsafe bool QueryServiceStatus(IntPtr serviceHandle, SERVICE_STATUS* pStatus);
internal static extern unsafe bool QueryServiceStatus(SafeServiceHandle serviceHandle, SERVICE_STATUS* pStatus);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,6 +11,6 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, EntryPoint = "StartServiceW", CharSet = CharSet.Unicode, SetLastError = true)]
internal extern static bool StartService(IntPtr serviceHandle, int argNum, IntPtr argPtrs);
internal extern static bool StartService(SafeServiceHandle serviceHandle, int argNum, IntPtr argPtrs);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

Expand All @@ -10,6 +11,6 @@ internal partial class Interop
internal partial class Advapi32
{
[DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
public extern static bool StartServiceCtrlDispatcher(IntPtr entry);
public extern static bool StartServiceCtrlDispatcher(SafeAllocHHandle entry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace Microsoft.Win32.SafeHandles
{
/// <summary>
/// Used to wrap handles gotten from OpenSCManager or OpenService
/// </summary>
internal class SafeServiceHandle : SafeHandle
{
internal SafeServiceHandle(IntPtr handle) : base(IntPtr.Zero, true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@
<value>Arguments within the 'args' array passed to Start cannot be null.</value>
</data>
<data name="BadMachineName" xml:space="preserve">
<value>MachineName value {0} is invalid.</value>
<value>MachineName '{0}' is invalid.</value>
</data>
<data name="CannotStart" xml:space="preserve">
<value>Cannot start service {0} on computer '{1}'.</value>
<value>Cannot start service '{0}' on computer '{1}'.</value>
</data>
<data name="InvalidEnumArgument" xml:space="preserve">
<value>The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.</value>
Expand All @@ -77,22 +77,22 @@
<value>MachineName was not set.</value>
</data>
<data name="NoService" xml:space="preserve">
<value>Service {0} was not found on computer '{1}'.</value>
<value>Service '{0}' was not found on computer '{1}'.</value>
</data>
<data name="OpenSC" xml:space="preserve">
<value>Cannot open Service Control Manager on computer '{0}'. This operation might require other privileges.</value>
</data>
<data name="OpenService" xml:space="preserve">
<value>Cannot open {0} service on computer '{1}'.</value>
<value>Cannot open '{0}' service on computer '{1}'.</value>
</data>
<data name="PauseService" xml:space="preserve">
<value>Cannot pause {0} service on computer '{1}'.</value>
<value>Cannot pause '{0}' service on computer '{1}'.</value>
</data>
<data name="ResumeService" xml:space="preserve">
<value>Cannot resume {0} service on computer '{1}'.</value>
<value>Cannot resume '{0}' service on computer '{1}'.</value>
</data>
<data name="StopService" xml:space="preserve">
<value>Cannot stop {0} service on computer '{1}'.</value>
<value>Cannot stop '{0}' service on computer '{1}'.</value>
</data>
<data name="Timeout" xml:space="preserve">
<value>Time out has expired and the operation has not been completed.</value>
Expand All @@ -107,7 +107,7 @@
<value>Cannot change service name when the service is running.</value>
</data>
<data name="ServiceName" xml:space="preserve">
<value>Service name {0} contains invalid characters, is empty, or is too long (max length = {1}).</value>
<value>Service name '{0}' contains invalid characters, is empty, or is too long (max length = {1}).</value>
</data>
<data name="NoServices" xml:space="preserve">
<value>Service has not been supplied. At least one object derived from ServiceBase is required in order to run.</value>
Expand Down Expand Up @@ -179,18 +179,18 @@
<value>Failed in handling the PowerEvent. The error that occurred was: {0}.</value>
</data>
<data name="InstallOK" xml:space="preserve">
<value>Service {0} has been successfully installed.</value>
<value>Service '{0}' has been successfully installed.</value>
</data>
<data name="TryToStop" xml:space="preserve">
<value>Attempt to stop service {0}.</value>
<value>Attempt to stop service '{0}'.</value>
</data>
<data name="ServiceRemoving" xml:space="preserve">
<value>Service {0} is being removed from the system...</value>
<value>Service '{0}' is being removed from the system...</value>
</data>
<data name="ServiceRemoved" xml:space="preserve">
<value>Service {0} was successfully removed from the system.</value>
<value>Service '{0}'' was successfully removed from the system.</value>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: extra '

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye, thanks!

</data>
<data name="ControlService" xml:space="preserve">
<value>Cannot control {0} service on computer '{1}'.</value>
<value>Cannot control '{0}' service on computer '{1}'.</value>
</data>
</root>
Loading