[英]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.