В Net. Рамки Я могу использовать следующую функцию для работы с открытым экземпляром приложения 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;
}
Это удобно, потому что пользователь может просто нажимать кнопки на листе Excel и вызывать все необходимые процедуры. И я могу написать код для работы с Excel на C#, который является более полезным и мощным, чем VBA. Следующий код в VBA используется для вызова C# консольного приложения при нажатии на кнопки в Excel. Он находит соответствующий exe-файл рядом с активным файлом Excel и вызывает его через команду Shell в VBA с необходимыми аргументами.
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
Ключевая функциональность, которая делает это возможным, - Marshal.GetActiveObject(string ProgID)
в C#, то есть доступно в Net.
Теперь я пытаюсь перейти на Net .Core 3.1. Можно использовать объектную модель Excel в Net .Core следующим образом: https://github.com/dotnet/samples/tree/master/core/extensions/ExcelDemo, чтобы я мог создать новый экземпляр Excel.Application и через него создать новую или открыть существующую книгу Excel и работать с ним со всеми функциями. НО я не могу подключиться к открытой книге Excel, потому что в Net .Core нет функции Marshal.GetActiveObject (string ProgID). Предварительный просмотр Net .Core 5 также не имеет. И нет аналогичной функции.
Я пытался сделать это с Marshal.GetObjectForIUnknown (IntPtr pUnk), который доступен в Net .Core. Как я знаю, Excel.Application является COM-объектом и поэтому имеет интерфейс IUnknown. Я попытался получить этот указатель в процессе открытого приложения Excel, которое можно найти по имени. Я использовал этот наивный код:
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;
}
Возникла исключительная ситуация System.ExecutionEngineException в линии вызова Marshall.GetObjectForIUnknown ().
Есть ли в Net .Core способ получить доступ к открыть книгу Excel?