RSCG – Com
RSCG – Com
name | Com |
nuget | https://www.nuget.org/packages/System.Runtime.InteropServices/ |
link | https://learn.microsoft.com/en-us/dotnet/standard/native-interop/comwrappers-source-generation |
author | Microsoft |
Generating Com Declarations
This is how you can use Com .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <!-- <PackageReference Include="System.Runtime.InteropServices" /> --> </PropertyGroup> <PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> </Project>
The code that you will use is
using test; IShellExecute shellExecute = new ShellExecuteClass(); // Open a file using the default associated program IntPtr result = shellExecute.ShellExecute( IntPtr.Zero, // HWND (handle to parent window) "open", // Operation to perform "notepad.exe", // File to open (replace with your file or URL) "", // Parameters "", // Working directory 1 // Show command (SW_SHOWNORMAL) ); Console.WriteLine($"ShellExecute Result: {result}");
using System; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; namespace test; // Import the ShellExecute function from Shell32.dll using ComImport [ComImport] [Guid("00000000-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IUnknown { void QueryInterface(ref Guid riid, out IntPtr ppvObject); void AddRef(); void Release(); } //[ComImport] [GeneratedComInterface(StringMarshalling = StringMarshalling.Utf8)] [Guid("000214F9-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public partial interface IShellExecute { IntPtr ShellExecute(IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); } // Replace this with your actual ShellExecute COM class public class ShellExecuteClass : IShellExecute { public IntPtr ShellExecute(IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd) { // Implement the ShellExecute functionality return NativeMethods.ShellExecute(hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd); } } // NativeMethods class to import necessary functions from Shell32.dll static class NativeMethods { [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr ShellExecute( IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd ); }
The code that is generated is
// <auto-generated /> #pragma warning disable CS0612, CS0618 file unsafe class InterfaceInformation : global::System.Runtime.InteropServices.Marshalling.IIUnknownInterfaceType { public static global::System.Guid Iid { get; } = new(new global::System.ReadOnlySpan<byte>(new byte[] { 249, 20, 2, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 70 })); private static void** _vtable; public static void** ManagedVirtualMethodTable => _vtable != null ? _vtable : (_vtable = InterfaceImplementation.CreateManagedVirtualFunctionTable()); } [global::System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute] file unsafe partial interface InterfaceImplementation : global::test.IShellExecute { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Interop.ComInterfaceGenerator", "8.0.9.3103")] [global::System.Runtime.CompilerServices.SkipLocalsInitAttribute] nint global::test.IShellExecute.ShellExecute(nint hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd) { var(__this, __vtable_native) = ((global::System.Runtime.InteropServices.Marshalling.IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(typeof(global::test.IShellExecute)); byte* __lpOperation_native = default; byte* __lpFile_native = default; byte* __lpParameters_native = default; byte* __lpDirectory_native = default; nint __retVal = default; int __invokeRetVal = default; // Setup - Perform required setup. scoped global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn __lpDirectory_native__marshaller = new(); scoped global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn __lpParameters_native__marshaller = new(); scoped global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn __lpFile_native__marshaller = new(); scoped global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn __lpOperation_native__marshaller = new(); try { // Marshal - Convert managed data to native data. __lpDirectory_native__marshaller.FromManaged(lpDirectory, stackalloc byte[global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn.BufferSize]); __lpParameters_native__marshaller.FromManaged(lpParameters, stackalloc byte[global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn.BufferSize]); __lpFile_native__marshaller.FromManaged(lpFile, stackalloc byte[global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn.BufferSize]); __lpOperation_native__marshaller.FromManaged(lpOperation, stackalloc byte[global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn.BufferSize]); { // PinnedMarshal - Convert managed data to native data that requires the managed data to be pinned. __lpDirectory_native = __lpDirectory_native__marshaller.ToUnmanaged(); __lpParameters_native = __lpParameters_native__marshaller.ToUnmanaged(); __lpFile_native = __lpFile_native__marshaller.ToUnmanaged(); __lpOperation_native = __lpOperation_native__marshaller.ToUnmanaged(); __invokeRetVal = ((delegate* unmanaged[MemberFunction]<void*, nint, byte*, byte*, byte*, byte*, int, nint*, int> )__vtable_native[3])(__this, hwnd, __lpOperation_native, __lpFile_native, __lpParameters_native, __lpDirectory_native, nShowCmd, &__retVal); } // NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call. global::System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(__invokeRetVal); global::System.GC.KeepAlive(this); } finally { // CleanupCallerAllocated - Perform cleanup of caller allocated resources. __lpDirectory_native__marshaller.Free(); __lpParameters_native__marshaller.Free(); __lpFile_native__marshaller.Free(); __lpOperation_native__marshaller.Free(); } return __retVal; } } file unsafe partial interface InterfaceImplementation { [global::System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute(CallConvs = new[] { typeof(global::System.Runtime.CompilerServices.CallConvMemberFunction) })] internal static int ABI_ShellExecute(global::System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch* __this_native, nint hwnd, byte* __lpOperation_native, byte* __lpFile_native, byte* __lpParameters_native, byte* __lpDirectory_native, int nShowCmd, nint* __invokeRetValUnmanaged__param) { global::test.IShellExecute @this = default; string lpOperation = default; string lpFile = default; string lpParameters = default; string lpDirectory = default; ref nint __invokeRetValUnmanaged = ref *__invokeRetValUnmanaged__param; nint __invokeRetVal = default; int __retVal = default; try { // Unmarshal - Convert native data to managed data. lpDirectory = global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ConvertToManaged(__lpDirectory_native); lpParameters = global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ConvertToManaged(__lpParameters_native); lpFile = global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ConvertToManaged(__lpFile_native); lpOperation = global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ConvertToManaged(__lpOperation_native); @this = global::System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch.GetInstance<global::test.IShellExecute>(__this_native); __invokeRetVal = @this.ShellExecute(hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd); // NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call. __retVal = 0; // S_OK // Marshal - Convert managed data to native data. __invokeRetValUnmanaged = __invokeRetVal; } catch (global::System.Exception __exception) { __retVal = global::System.Runtime.InteropServices.Marshalling.ExceptionAsHResultMarshaller<int>.ConvertToUnmanaged(__exception); } return __retVal; } } file unsafe partial interface InterfaceImplementation { internal static void** CreateManagedVirtualFunctionTable() { void** vtable = (void**)global::System.Runtime.CompilerServices.RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(global::test.IShellExecute), sizeof(void*) * 4); { nint v0, v1, v2; global::System.Runtime.InteropServices.ComWrappers.GetIUnknownImpl(out v0, out v1, out v2); vtable[0] = (void*)v0; vtable[1] = (void*)v1; vtable[2] = (void*)v2; } { vtable[3] = (void*)(delegate* unmanaged[MemberFunction]<global::System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch*, nint, byte*, byte*, byte*, byte*, int, nint*, int> )&ABI_ShellExecute; } return vtable; } } namespace test { [global::System.Runtime.InteropServices.Marshalling.IUnknownDerivedAttribute<InterfaceInformation, InterfaceImplementation>] public partial interface IShellExecute { } } namespace test { public partial interface IShellExecute { } }
Code and pdf at https://ignatandrei.github.io/RSCG_Examples/v2/docs/Com
Leave a Reply