Skip to content

Spike of generated COM interop and LibraryImports #49669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions src/Cli/Microsoft.DotNet.Cli.Utils/DangerousFileDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@ public static bool IsDangerous(string filename)
// First check the zone, if they are not an untrusted zone, they aren't dangerous
if (internetSecurityManager == null)
{
#if NET
internetSecurityManager = new InternetSecurityManager();
#else
Type? iismType = Type.GetTypeFromCLSID(new Guid(CLSID_InternetSecurityManager));
if (iismType is not null)
{
internetSecurityManager = Activator.CreateInstance(iismType) as IInternetSecurityManager;
}
#endif
}
int zone = 0;
internetSecurityManager?.MapUrlToZone(Path.GetFullPath(filename), out zone, 0);
Expand Down
75 changes: 59 additions & 16 deletions src/Cli/Microsoft.DotNet.Cli.Utils/Interop.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,85 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// UrlMonTypeLib.IInternetSecurityManager
#if NET9_0_OR_GREATER
using GeneratedWhenPossibleComInterfaceAttribute = System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute;
#else
using GeneratedWhenPossibleComInterfaceAttribute = System.Runtime.InteropServices.ComImportAttribute;
#endif

using System.Runtime.CompilerServices;

#if NET
using System.Runtime.InteropServices.Marshalling;
#endif

#if NET9_0_OR_GREATER
[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling]
#endif

namespace Microsoft.DotNet.Cli.Utils;

#if NET
[GeneratedComInterface(StringMarshalling = System.Runtime.InteropServices.StringMarshalling.Utf16)]
#else
[ComImport]
[Guid("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComConversionLoss]
internal interface IInternetSecurityManager
#endif
[Guid("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B")]
// UrlMonTypeLib.IInternetSecurityManager
internal partial interface IInternetSecurityManager
{
void SetSecuritySite([In][MarshalAs(UnmanagedType.Interface)] IInternetSecurityMgrSite pSite);
void SetSecuritySite([MarshalAs(UnmanagedType.Interface)] in IInternetSecurityMgrSite pSite);

void GetSecuritySite([MarshalAs(UnmanagedType.Interface)] out IInternetSecurityMgrSite ppSite);

void MapUrlToZone([In][MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out int pdwZone, [In] int dwFlags);
void MapUrlToZone(in string pwszUrl, out int pdwZone, in int dwFlags);

void GetSecurityId(in string pwszUrl, out byte pbSecurityId, ref int pcbSecurityId, [ComAliasName("UrlMonTypeLib.ULONG_PTR")] in int dwReserved);

void GetSecurityId([In][MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out byte pbSecurityId, [In][Out] ref int pcbSecurityId, [In][ComAliasName("UrlMonTypeLib.ULONG_PTR")] int dwReserved);
void ProcessUrlAction(in string pwszUrl, in int dwAction, out byte pPolicy, in int cbPolicy, ref byte pContext, in int cbContext, in int dwFlags, in int dwReserved);

void ProcessUrlAction([In][MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [In] int dwAction, out byte pPolicy, [In] int cbPolicy, [In] ref byte pContext, [In] int cbContext, [In] int dwFlags, [In] int dwReserved);
void QueryCustomPolicy(in string pwszUrl, ref Guid guidKey, out IntPtr ppPolicy, out int pcbPolicy, ref byte pContext, in int cbContext, in int dwReserved);

void QueryCustomPolicy([In][MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [In][ComAliasName("UrlMonTypeLib.GUID")] ref GUID guidKey, [Out] IntPtr ppPolicy, out int pcbPolicy, [In] ref byte pContext, [In] int cbContext, [In] int dwReserved);
void SetZoneMapping(in int dwZone, in string lpszPattern, in int dwFlags);

void SetZoneMapping([In] int dwZone, [In][MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, [In] int dwFlags);
void GetZoneMappings(in int dwZone, [MarshalAs(UnmanagedType.Interface)] out IEnumString ppenumString, in int dwFlags);
}

void GetZoneMappings([In] int dwZone, [MarshalAs(UnmanagedType.Interface)] out IEnumString ppenumString, [In] int dwFlags);
#if NET
[GeneratedComClass]
internal partial class InternetSecurityManager : IInternetSecurityManager
{
public void SetSecuritySite([MarshalAs(UnmanagedType.Interface)] in IInternetSecurityMgrSite pSite) => throw new NotImplementedException();
public void GetSecuritySite([MarshalAs(UnmanagedType.Interface)] out IInternetSecurityMgrSite ppSite) => throw new NotImplementedException();
public void MapUrlToZone(in string pwszUrl, out int pdwZone, in int dwFlags) => throw new NotImplementedException();
public void GetSecurityId(in string pwszUrl, out byte pbSecurityId, ref int pcbSecurityId, in int dwReserved) => throw new NotImplementedException();
public void ProcessUrlAction(in string pwszUrl, in int dwAction, out byte pPolicy, in int cbPolicy, ref byte pContext, in int cbContext, in int dwFlags, in int dwReserved) => throw new NotImplementedException();
public void QueryCustomPolicy(in string pwszUrl, ref Guid guidKey, out IntPtr ppPolicy, out int pcbPolicy, ref byte pContext, in int cbContext, in int dwReserved) => throw new NotImplementedException();
public void SetZoneMapping(in int dwZone, in string lpszPattern, in int dwFlags) => throw new NotImplementedException();
public void GetZoneMappings(in int dwZone, [MarshalAs(UnmanagedType.Interface)] out IEnumString ppenumString, in int dwFlags) => throw new NotImplementedException();
}
#endif

// UrlMonTypeLib.IInternetSecurityMgrSite

#if NET
[GeneratedComInterface]
#else
[ComImport]
[ComConversionLoss]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
#endif
[Guid("79EAC9ED-BAF9-11CE-8C82-00AA004BA90B")]
interface IInternetSecurityMgrSite
partial interface IInternetSecurityMgrSite
{
void GetWindow([Out][ComAliasName("UrlMonTypeLib.wireHWND")] IntPtr phwnd);
void GetWindow([ComAliasName("UrlMonTypeLib.wireHWND")] out IntPtr phwnd);

void EnableModeless([In] int fEnable);
void EnableModeless(in int fEnable);
}


[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct GUID
{
Expand All @@ -54,16 +93,20 @@ struct GUID
public byte[] Data4;
}

#if NET
[GeneratedComInterface(StringMarshalling = System.Runtime.InteropServices.StringMarshalling.Utf16)]
#else
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
#endif
[Guid("00000101-0000-0000-C000-000000000046")]
interface IEnumString
partial interface IEnumString
{
[MethodImpl(MethodImplOptions.InternalCall)]
void RemoteNext([In] int celt, [MarshalAs(UnmanagedType.LPWStr)] out string rgelt, out int pceltFetched);
void RemoteNext(in int celt, out string rgelt, out int pceltFetched);

[MethodImpl(MethodImplOptions.InternalCall)]
void Skip([In] int celt);
void Skip(in int celt);

[MethodImpl(MethodImplOptions.InternalCall)]
void Reset();
Expand Down
96 changes: 81 additions & 15 deletions src/Cli/Microsoft.DotNet.Cli.Utils/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
#if NET
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
#endif

namespace Microsoft.DotNet.Cli.Utils;

internal static class NativeMethods
public static partial class NativeMethods
{
internal static class Windows
public unsafe static partial class Windows
{
internal enum JobObjectInfoClass : uint
{
Expand Down Expand Up @@ -68,29 +72,91 @@ internal struct PROCESS_BASIC_INFORMATION
public UIntPtr UniqueProcessId;
public UIntPtr InheritedFromUniqueProcessId;
}

#if NET
[LibraryImport("kernel32.dll", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)]
#else
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
Copy link
Member

Choose a reason for hiding this comment

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

Can probably add [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] to anything from OS.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't actually know if that attribute works with the generated stuff? It'd be good to learn more.

internal static extern SafeWaitHandle CreateJobObjectW(IntPtr lpJobAttributes, string? lpName);

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoClass jobObjectInformationClass, IntPtr lpJobObjectInformation, uint cbJobObjectInformationLength);

#endif
internal static
#if NET
partial
#else
extern
#endif
SafeWaitHandle CreateJobObjectW(IntPtr lpJobAttributes, string? lpName);

#if NET
[LibraryImport("kernel32.dll", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)]
#else
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);

#endif
[return: MarshalAs(UnmanagedType.Bool)]
internal static
#if NET
partial
#else
extern
#endif
bool SetInformationJobObject(IntPtr hJob, JobObjectInfoClass jobObjectInformationClass, IntPtr lpJobObjectInformation, uint cbJobObjectInformationLength);

#if NET
[LibraryImport("kernel32.dll", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)]
#else
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
#endif
[return: MarshalAs(UnmanagedType.Bool)]
internal static
#if NET
partial
#else
extern
#endif

bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);

#if NET
[LibraryImport("kernel32.dll", StringMarshalling = StringMarshalling.Utf16)]
#else
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern IntPtr GetCommandLine();

#endif
internal static
#if NET
partial
#else
extern
#endif
IntPtr GetCommandLine();

#if NET
[LibraryImport("ntdll.dll", SetLastError = true)]
#else
[DllImport("ntdll.dll", SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern unsafe uint NtQueryInformationProcess(SafeProcessHandle ProcessHandle, int ProcessInformationClass, void* ProcessInformation, uint ProcessInformationLength, out uint ReturnLength);
#endif
internal static
#if NET
partial
#else
extern
#endif
uint NtQueryInformationProcess(SafeProcessHandle ProcessHandle, int ProcessInformationClass, void* ProcessInformation, uint ProcessInformationLength, out uint ReturnLength);
}

internal static class Posix
internal static partial class Posix
{
#if NET
[LibraryImport("libc", SetLastError = true)]
#else
[DllImport("libc", SetLastError = true)]
internal static extern int kill(int pid, int sig);
#endif
internal static
#if NET
partial
#else
extern
#endif
int kill(int pid, int sig);

internal const int SIGINT = 2;
internal const int SIGTERM = 15;
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/Microsoft.DotNet.Cli.Utils/ProcessReaper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private static bool SetKillOnJobClose(IntPtr job, bool value)
}
};

var length = Marshal.SizeOf(typeof(NativeMethods.Windows.JobObjectExtendedLimitInformation));
var length = Marshal.SizeOf<NativeMethods.Windows.JobObjectExtendedLimitInformation>();
var informationPtr = Marshal.AllocHGlobal(length);

try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@

using Microsoft.Win32;

#if NET
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
#endif

namespace Microsoft.DotNet.Cli.Utils;

#pragma warning disable CA1416
internal class WindowsRegistryEnvironmentPathEditor : IWindowsRegistryEnvironmentPathEditor
internal partial class WindowsRegistryEnvironmentPathEditor : IWindowsRegistryEnvironmentPathEditor
{
private static string Path = "PATH";
public string? Get(SdkEnvironmentVariableTarget currentUserBeforeEvaluation)
Expand Down Expand Up @@ -60,8 +65,18 @@ public void Set(string value, SdkEnvironmentVariableTarget sdkEnvironmentVariabl
return baseKey.OpenSubKey(keyName, writable: writable);
}

[DllImport("user32.dll", EntryPoint = "SendMessageTimeoutW")]
private static extern IntPtr SendMessageTimeout(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, int flags, int timeout, out IntPtr pdwResult);
#if NET
[LibraryImport("user32.dll", EntryPoint = "SendMessageTimeoutW")]
#else
[DllImport("user32.dll", EntryPoint = "SendMessageTimeoutW")]
#endif
internal static
#if NET
partial
#else
extern
#endif
IntPtr SendMessageTimeout(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, int flags, int timeout, out IntPtr pdwResult);

private const int HWND_BROADCAST = 0xffff;
private const int WM_SETTINGCHANGE = 0x001A;
Expand Down
Loading