简体   繁体   English

如何在 net.core 3.1 中连接打开的 excel 应用程序?

[英]How to connect an open excel application in net.core 3.1?

In Net.Framework I can use next function to operate with open instance of excel application:在 Net.Framework 中,我可以使用下一个 function 来操作 excel 应用程序的打开实例:

using Excel = Microsoft.Office.Interop.Excel;
public static Excel.Workbook GetOpenedExcelWorkbook(string workBookName)
{
    Excel.Application xlsApp = null;
    try { xlsApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application"); }
    catch { return null; }

    foreach (Excel.Workbook wb in xlsApp.Workbooks)
    {
        if (wb.Name == workBookName)
            return wb;
    }
    return null;
}

It is convenient, because an user can just click buttons in excel worksheet and call all necessary procedures.这很方便,因为用户只需单击 excel 工作表中的按钮并调用所有必要的程序。 And I can write code for operate with excel in C#, which is more useful and powerful than VBA.并且我可以在 C# 中编写操作 excel 的代码,这比 VBA 更有用和更强大。 Next code in VBA is used to call C# console application at click on the buttons in excel. VBA 中的下一个代码用于在单击 excel 中的按钮时调用 C# 控制台应用程序。 It find apropriate exe-file near to active excel file and call it througth Shell command in VBA with necessary arguments.它在活动 excel 文件附近找到适当的 exe 文件,并通过 Z6E3EC7E6A9F6007B4838FC0EE793A809289777777777777777777777777777777777777777777777

Sub Button1_Click()
    Call ExeCaller("ConsoleApp.exe", "Button1_action_arg")
End Sub


Sub ExeCaller(ExeName As String, Optional cmd As String = "")
    Dim arg As String
    If Not Dir(ExeName) = "" Then
        arg = ExeName & " " & ActiveWorkbook.Name & IIf(cmd = "", "", " " & cmd)
    Else
        Dim pathToWB As String: pathToWB = ThisWorkbook.Path
        Dim pathToExe_Release As String: pathToExe_Release = pathToWB + "\bin\Release\" + ExeName
        Dim pathToExe_Debug As String:   pathToExe_Debug = pathToWB + "\bin\Debug\" + ExeName

        Dim dr As Double, dd As Double
        If Not Dir(pathToExe_Release) = "" Then dr = FileDateTime(pathToExe_Release)
        If Not Dir(pathToExe_Debug) = "" Then dd = FileDateTime(pathToExe_Debug)
        Dim dmax As Double: dmax = IIf(dr > dd, dr, dd)

        If (dmax = 0) Then
            If Not Dir(ExeName) = "" Then
                pathToExe = ExeName
            Else
                MsgBox "File " + ExeName + "not found!", vbCritical, Error
                Exit Sub
            End If
        ElseIf dmax = dr Then
            pathToExe = pathToExe_Release
        ElseIf dmax = dd Then
            pathToExe = pathToExe_Debug
        Else

            MsgBox "File " + ExeName + "not found!", vbCritical, Error
            Exit Sub
        End If

        arg = pathToExe & " " & ActiveWorkbook.Name & IIf(cmd = "", "", " " & cmd)
    End If

    Shell arg, vbNormalFocus
End Sub

The key functionality than make it possible is Marshal.GetActiveObject(string ProgID) in C#, that is available in Net.Framework.使其成为可能的关键功能是 C# 中的Marshal.GetActiveObject(string ProgID) ,它在 Net.Framework 中可用。

Now I try to migrate to Net.Core 3.1.现在我尝试迁移到 Net.Core 3.1。 It is possible to use Excel object model in Net.Core by this way: https://github.com/dotnet/samples/tree/master/core/extensions/ExcelDemo So that I can create a new instance of Excel.Application and through it create new or open exist excel workbook and operate with it with all functionality. It is possible to use Excel object model in Net.Core by this way: https://github.com/dotnet/samples/tree/master/core/extensions/ExcelDemo So that I can create a new instance of Excel.Application and通过它创建新的或打开现有的 excel 工作簿并使用它来操作所有功能。 BUT I can't connect to open excel workbook because there is no Marshal.GetActiveObject(string ProgID) function in Net.Core.但是我无法连接到打开 excel 工作簿,因为 Net.Core 中没有 Marshal.GetActiveObject(string ProgID) function。 Preview Net.Core 5 doesn't have it either. Preview Net.Core 5 也没有。 And there is no similar function.并且没有类似的function。

I tried to do it with Marshal.GetObjectForIUnknown(IntPtr pUnk) whith is available in Net.Core.我尝试使用 Net.Core 中可用的 Marshal.GetObjectForIUnknown(IntPtr pUnk) 来做到这一点。 As I know Excel.Application is a COM-object and therefore it have IUnknown interface.据我所知 Excel.Application 是一个 COM 对象,因此它具有 IUnknown 接口。 I tried to get this pointer throught a process of open excel application that can be found by name.我试图通过可以按名称找到的打开 excel 应用程序的过程来获取此指针。 I used this naive code:我使用了这个天真的代码:

public static Excel.Application GetOpenedExcelApplication()
{
    Process[] aP = Process.GetProcesses();
    foreach (Process p in aP)
    {
        string pn = p.ProcessName.ToLower();

        if (Regex.IsMatch(pn, "excel*"))
        {
            object o = Marshal.GetObjectForIUnknown(p.Handle);
            Excel.Application app = (Excel.Application)o;
            return app;
        }
    }

    return null;
}

A System.ExecutionEngineException occurred on the Marshall.GetObjectForIUnknown() call line. Marshall.GetObjectForIUnknown() 调用线路上发生 System.ExecutionEngineException。

Is there a way in Net.Core to get access the open Excel workbook? Net.Core 中有没有办法访问打开的 Excel 工作簿?

We can have a look to source code of Marshal class in .NET Framework 4.X and copy GetActiveObject method implementation to projects of .NET Core and .NET 5 and .NET 6. It works. We can have a look to source code of Marshal class in .NET Framework 4.X and copy GetActiveObject method implementation to projects of .NET Core and .NET 5 and .NET 6. It works.

public static class ExMarshal
{
    internal const String OLEAUT32 = "oleaut32.dll";
    internal const String OLE32 = "ole32.dll";

    [System.Security.SecurityCritical]  // auto-generated_required
    public static Object GetActiveObject(String progID)
    {
        Object obj = null;
        Guid clsid;

        // Call CLSIDFromProgIDEx first then fall back on CLSIDFromProgID if
        // CLSIDFromProgIDEx doesn't exist.
        try
        {
            CLSIDFromProgIDEx(progID, out clsid);
        }
        //            catch
        catch (Exception)
        {
            CLSIDFromProgID(progID, out clsid);
        }

        GetActiveObject(ref clsid, IntPtr.Zero, out obj);
        return obj;
    }

    //[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
    [DllImport(OLE32, PreserveSig = false)]
    [ResourceExposure(ResourceScope.None)]
    [SuppressUnmanagedCodeSecurity]
    [System.Security.SecurityCritical]  // auto-generated
    private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);

    //[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
    [DllImport(OLE32, PreserveSig = false)]
    [ResourceExposure(ResourceScope.None)]
    [SuppressUnmanagedCodeSecurity]
    [System.Security.SecurityCritical]  // auto-generated
    private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);

    //[DllImport(Microsoft.Win32.Win32Native.OLEAUT32, PreserveSig = false)]
    [DllImport(OLEAUT32, PreserveSig = false)]
    [ResourceExposure(ResourceScope.None)]
    [SuppressUnmanagedCodeSecurity]
    [System.Security.SecurityCritical]  // auto-generated
    private static extern void GetActiveObject(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 net.core 3.1 上使用 DI 正确配置身份核心? - How to configure properly Identity core with DI on net.core 3.1? 如何使用 C# Net.Core 脚本在我的桌面上打开文件? - How to open files on my desktop using C# Net.Core script? C# - ASP NET.CORE 3.1 - 表中更新记录的问题 - C# - ASP NET.CORE 3.1 - problem with update record's in table 极端情况:您能否将 Net.Core 3.1 配置为在与 Asp.Classic 相同的文件夹中运行? - Edge case: Can you configure Net.Core 3.1 to run in the same folder as Asp.Classic? 带有 GenericRepository 错误的依赖注入 - 没有为此 DbContext NET.Core 3.1 配置数据库提供程序 - Dependency Injection with GenericRepository error - No database provider has been configured for this DbContext NET.Core 3.1 如何解决 .NET.CORE 中的 Proxy Server 407 错误 - How to solve the Proxy Server 407 error in .NET.CORE net.core / asp.net 身份 / openid 连接中的关联失败 - Correlation failed in net.core / asp.net identity / openid connect 如何在 WPF .Net Core 3.1 中将 API 连接到我的项目 - How to connect API to my project in WPF .Net Core 3.1 为什么我的 GlobalExceptionFilter 在 NET.Core 上不起作用? - Why is my GlobalExceptionFilter not working on NET.Core? 如何在 .NET Core 3.1 应用程序中添加 WCF 服务参考? - How to add a WCF service reference in a .NET Core 3.1 application?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM