MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Обратная совместимость в .NET CORE"
Answer 921969
COM Interop работает в .NET Core 2.0+. В диалоге добавления ссылки для проектов .NET Core в Visual Studio нет вкладки COM, но можно нажать "Обзор" и указать tlb/dll файл вручную, для него будет корректно сформирована Interop-сборка. Однако, в .NET Core (до версии 3.0) не реализовано позднее связывание (IDispatch), поэтому большая часть функционала Office Automation действительно будет трудно использовать.
Обновление: В .NET Core 3.0+ была добавлена поддержка маршаллинга IDispatch (пример можно найти здесь: https://github.com/dotnet/samples/tree/master/core/extensions/ExcelDemo). Код ниже уже не актуален.
Применительно к Excel, к примеру, вот такой код работает:
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";
А вот такой - уже нет:
sheet.Cells[1,1] = "Hello from .NET Core"; //ноль эффекта
Чтобы задействовать интерфейс Range, использующий позднее связывание, понадобится куда более сложный код:
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; } } }
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.