diff --git a/src/Shared/ProcessExtensions.cs b/src/Shared/ProcessExtensions.cs index 7ddd8dc6ab6..364bc2f67a5 100644 --- a/src/Shared/ProcessExtensions.cs +++ b/src/Shared/ProcessExtensions.cs @@ -3,10 +3,10 @@ using System; using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; #if NET +using System.Runtime.Versioning; +using System.Runtime.InteropServices; using System.Buffers; using System.Text; using System.IO; @@ -84,7 +84,9 @@ public static bool TryGetCommandLine(this Process? process, out string? commandL return true; } #else - commandLine = Windows.GetCommandLine(process.Id); + // While we technically can do the same COM interop on .NET Framework that we do on modern .NET, VS perf tests yell at us for more assembly loads. + // Out of deference to those tests, we artificially limit the functionality to just modern .NET. + commandLine = null; return true; #endif } @@ -161,6 +163,7 @@ private static string ParseNullSeparatedArguments(ReadOnlySpan data, int m } #endif +#if NET /// /// Windows-specific command line retrieval via WMI COM interfaces. /// Queries Win32_Process for the CommandLine property using IWbemLocator/IWbemServices. @@ -228,19 +231,6 @@ private static extern int CoSetProxyBlanket( IntPtr pAuthInfo, int dwCapabilities); -#if !NET - [DllImport("ole32.dll", EntryPoint = "CoSetProxyBlanket")] - private static extern int CoSetProxyBlanketPtr( - IntPtr pProxy, - int dwAuthnSvc, - int dwAuthzSvc, - IntPtr pServerPrincName, - int dwAuthnLevel, - int dwImpLevel, - IntPtr pAuthInfo, - int dwCapabilities); -#endif - [ComImport] [Guid("DC12A687-737F-11CF-884D-00AA004B2E24")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] @@ -553,53 +543,6 @@ int Get( int GetMethodOrigin([MarshalAs(UnmanagedType.LPWStr)] string wszMethodName, [MarshalAs(UnmanagedType.BStr)] out string pstrClassName); } -#if !NET - /// - /// Sets the proxy blanket on a COM proxy via raw interface pointers. - /// On .NET Framework, the RCW caches separate proxy stubs for IUnknown and each - /// specific COM interface. CoSetProxyBlanket must be called on both the IUnknown - /// pointer and the specific interface pointer, otherwise WMI calls fail with - /// WBEM_E_ACCESS_DENIED (0x80041003). - /// - private static void SetProxyBlanketForNetFx(object comProxy) - { - IntPtr pUnk = Marshal.GetIUnknownForObject(comProxy); - try - { - CoSetProxyBlanketPtr( - pUnk, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - IntPtr.Zero, - RPC_C_AUTHN_LEVEL_CALL, - RPC_C_IMP_LEVEL_IMPERSONATE, - IntPtr.Zero, - EOAC_NONE); - } - finally - { - Marshal.Release(pUnk); - } - - IntPtr pInterface = Marshal.GetComInterfaceForObject(comProxy, typeof(T)); - try - { - CoSetProxyBlanketPtr( - pInterface, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - IntPtr.Zero, - RPC_C_AUTHN_LEVEL_CALL, - RPC_C_IMP_LEVEL_IMPERSONATE, - IntPtr.Zero, - EOAC_NONE); - } - finally - { - Marshal.Release(pInterface); - } - } -#endif /// /// Retrieves the command line for a process by querying WMI Win32_Process via COM. @@ -645,7 +588,6 @@ private static void SetProxyBlanketForNetFx(object comProxy) $"WMI ConnectServer failed for PID {processId}. HRESULT: 0x{hr:X8}"); } -#if NET hr = CoSetProxyBlanket( services, RPC_C_AUTHN_WINNT, @@ -660,13 +602,6 @@ private static void SetProxyBlanketForNetFx(object comProxy) throw new InvalidOperationException( $"WMI CoSetProxyBlanket failed for PID {processId}. HRESULT: 0x{hr:X8}"); } -#else - // On .NET Framework, the RCW caches separate proxy stubs for IUnknown and - // each specific COM interface. CoSetProxyBlanket must be called on BOTH - // the IUnknown pointer AND the specific interface pointer, because the - // blanket set on IUnknown doesn't propagate to the specific interface's proxy. - SetProxyBlanketForNetFx(services); -#endif string query = $"SELECT CommandLine FROM Win32_Process WHERE ProcessId='{processId}'"; hr = services.ExecQuery( @@ -681,11 +616,6 @@ private static void SetProxyBlanketForNetFx(object comProxy) $"WMI ExecQuery failed for PID {processId}. HRESULT: 0x{hr:X8}"); } -#if !NET - // The enumerator is a separate COM proxy that also needs its security blanket set. - SetProxyBlanketForNetFx(enumerator); -#endif - hr = enumerator.Next(WBEM_INFINITE, 1, out IWbemClassObject obj, out uint returned); if (hr == WBEM_S_FALSE || returned == 0) { @@ -709,6 +639,7 @@ private static void SetProxyBlanketForNetFx(object comProxy) return val as string; } } +#endif #if NET /// diff --git a/src/Utilities.UnitTests/ProcessExtensions_Tests.cs b/src/Utilities.UnitTests/ProcessExtensions_Tests.cs index 8f52ca1a0dd..fe302171694 100644 --- a/src/Utilities.UnitTests/ProcessExtensions_Tests.cs +++ b/src/Utilities.UnitTests/ProcessExtensions_Tests.cs @@ -50,7 +50,7 @@ public async Task KillTree() p.ExitCode.ShouldNotBe(0); } - [Fact] + [DotNetOnlyFact] public async Task TryGetCommandLine_RunningProcess_ContainsExpectedExecutable() { using Process p = StartLongRunningProcess(); @@ -80,7 +80,7 @@ public async Task TryGetCommandLine_RunningProcess_ContainsExpectedExecutable() } } - [Fact] + [DotNetOnlyFact] public async Task TryGetCommandLine_RunningProcess_ContainsArguments() { using Process p = StartLongRunningProcess();