As I understand it, much has been cut out from .NET CORE for the sake of cross-platform.

For example, COM .

However, what if you suddenly need to work with office Microsoft.Office.Interop ? Or, for example, I needed to do something through WMI .

Earlier it was possible to say:

Do not need cross-platform? Drank on the .NET Framework

However, the .NET Framework 4.8 will be the last of its kind, and only the .NET CORE => will continue to evolve => you do not want to, you will have to use the .NET CORE if you want to use new features.

The Interop library connects to the .NET CORE, but there is a warning that full compatibility is not guaranteed.

  • Put a service next to it that can COM and access it from the core. - AK
  • one
    > Interop library for .NET CORE is connected, but there is a warning that full compatibility is not guaranteed. - so in this and salt probably. Will work, but only under Windows for example. - Monk
  • @Monk, as far as I know, backward compatibility of .NET CORE with .NET FRAMEWORK is not guaranteed, since it is rewritten from 0. For example, the restriction of 255 characters in the paths was initially removed. - iluxa1810

2 answers 2

COM Interop works in .NET Core 2.0+ . In the Add Link dialog for .NET Core projects in Visual Studio there is no COM tab, but you can click "Browse" and specify the tlb / dll file manually, the Interop-assembly will be formed correctly for it. However, late binding is not implemented in .NET Core (IDispatch), so most of the Office Automation functionality will indeed be difficult to use.

With reference to Excel, for example, this code works:

 Application app = new Application(); app.Visible = true; var books = app.Workbooks; var book = books.Add(); Worksheet sheet = book.ActiveSheet; Console.WriteLine(sheet.Name); sheet.Name = "Hello from .NET Core"; 

But this is no longer:

 sheet.Cells[1,1] = "Hello from .NET Core"; //ноль эффекта 

To use the Range interface using late binding, a much more complicated code is needed:

 using System; using System.Runtime.InteropServices; using ComTypes = System.Runtime.InteropServices.ComTypes; using Microsoft.Office.Interop.Excel; namespace NetCoreTest { class Program { static void Main(string[] args) { Application app = new Application(); app.Visible = true; var books = app.Workbooks; var book = books.Add(); _Worksheet sheet = book.ActiveSheet; Range r = sheet.get_Range("A1"); SetProperty(r, "Value", "Hello from .NET Core"); Console.ReadKey(); } //Устанавливает свойство COM-объекта с использованием позднего связывания public static void SetProperty(object obj, string property, string value) { int dispId = GetDispId(obj, property); InvokePropertySetter(obj as IDispatch, dispId, value); } const uint DISPATCH_METHOD = 0x1; const uint DISPATCH_PROPERTYGET = 0x2; const uint DISPATCH_PROPERTYPUT = 0x4; // Получение DispId для указанного метода (свойства) COM-объекта с использованием позднего связывания // Источник: https://github.com/dotnet/corefx/issues/19731 public static int GetDispId(object rcw, string methodName) { IDispatch dispatchObject = rcw as IDispatch; if (dispatchObject == null) { Console.WriteLine("Passed-in argument is not a IDispatch object"); return -1; } int[] dispIds = new int[1]; Guid emtpyRiid = Guid.Empty; dispatchObject.GetIDsOfNames( emtpyRiid, new string[] { methodName }, 1, 0, dispIds); if (dispIds[0] == -1) { Console.WriteLine("Method name {0} cannot be recognized.", methodName); } return dispIds[0]; } public static object InvokePropertySetter(IDispatch target, int dispId, string val) { const int DISPID_PROPERTYPUT = -3; IntPtr pArg = IntPtr.Zero; IntPtr pNamedArgs = IntPtr.Zero; IntPtr pStr = IntPtr.Zero; IntPtr dispIdArray = IntPtr.Zero, tmpVariants = IntPtr.Zero; if (target == null) { Console.WriteLine("Cannot cast target to IDispatch."); return null; } try { pStr = Marshal.StringToBSTR(val); Variant variant = new Variant(); variant.vt = 8; //VT_BSTR variant.p = pStr; pArg = Marshal.AllocHGlobal(Marshal.SizeOf(variant)); Marshal.StructureToPtr(variant, pArg, false); pNamedArgs = Marshal.AllocHGlobal(4); Marshal.WriteInt32(pNamedArgs, DISPID_PROPERTYPUT); var paramArray = new ComTypes.DISPPARAMS[1]; paramArray[0].rgvarg = pArg; paramArray[0].cArgs = 1; paramArray[0].cNamedArgs = 1; paramArray[0].rgdispidNamedArgs = pNamedArgs; ComTypes.EXCEPINFO info = default(ComTypes.EXCEPINFO); object result = null; uint puArgErrNotUsed = 0; target.Invoke(dispId, new Guid(), 0x0409, ComTypes.INVOKEKIND.INVOKE_PROPERTYPUT, paramArray, out result, out info, out puArgErrNotUsed); return result; } finally { if (pStr != IntPtr.Zero) Marshal.FreeBSTR(pStr); if (pArg != IntPtr.Zero) Marshal.FreeHGlobal(pArg); if (pNamedArgs != IntPtr.Zero) Marshal.FreeHGlobal(pNamedArgs); } } [DllImport("ole32.dll")] public static extern int CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] string lpszProgID, out Guid pclsid); [Guid("00020400-0000-0000-c000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface IDispatch { [PreserveSig] int GetTypeInfoCount(out int info); [PreserveSig] int GetTypeInfo(int iTInfo, int lcid, out ComTypes.ITypeInfo ppTInfo); void GetIDsOfNames( [MarshalAs(UnmanagedType.LPStruct)] Guid iid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgszNames, int cNames, int lcid, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I4)] int[] rgDispId); void Invoke( int dispIdMember, [MarshalAs(UnmanagedType.LPStruct)] Guid iid, int lcid, ComTypes.INVOKEKIND wFlags, [In, Out] [MarshalAs(UnmanagedType.LPArray)] ComTypes.DISPPARAMS[] paramArray, out object pVarResult, out ComTypes.EXCEPINFO pExcepInfo, out uint puArgErr); } [StructLayout(LayoutKind.Sequential)] public struct Variant { public ushort vt; ushort wReserved1; ushort wReserved2; ushort wReserved3; public IntPtr p; } } } 
  • And Microsoft is not planning to finish this moment? And by the way, what will happen if I sip logic on .NET FRAMEWORK, and call it through .NET CORE? Will work in this case that you described does not work? - iluxa1810
  • @ iluxa1810 " Doesn't Microsoft plan to finish this moment? " - I think it’s unlikely that if they wanted to do this, they would have done it right away. Not that it was a real problem, if this functionality is really needed, you can simply wrap your IDispatch implementation into a reusable library and connect it to all projects where it is needed. " And by the way, what will happen if I sip logic on .NET FRAMEWORK and call it through .NET CORE? " - Through the service? You can, but what's the point of creating a project for .Net Core and at the same time completely dependent on the .NET Framework. - MSDN.WhiteKnight
  • It is possible, but it seems, intellisense will not give hints => inconvenient to work with it = ( - iluxa1810
  • "Through the service?" - not, in a separate assembly, encapsulate all the work with the office, and then connect this library in the .NET CORE to call some special method in this assembly and all work with the interoptom will be correctly performed. - iluxa1810
  • @ iluxa1810 When you add a .NET Framework link to a .Net Core project, it will essentially be interpreted as .NET Standard (only what works in both platforms will work in it). So it does not solve the problem. - MSDN.WhiteKnight

Use third-party libraries - analogues. For example, to work with Office, you can work with the same EPPlus

By the way, .xlsx -> .zip container with nested xml.

  • However, there is no substitute for working with DAO for Access. And there may also be a need to work with the old Excel format, which EPPlus does not open. - iluxa1810