In Net.Framework I can use next function to operate with open instance of excel application:
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. And I can write code for operate with excel in C#, which is more useful and powerful than VBA. Next code in VBA is used to call C# console application at click on the buttons in excel. It find apropriate exe-file near to active excel file and call it througth Shell command in VBA with necessary arguments.
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.
Now I try to migrate to 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. BUT I can't connect to open excel workbook because there is no Marshal.GetActiveObject(string ProgID) function in Net.Core. Preview Net.Core 5 doesn't have it either. And there is no similar function.
I tried to do it with Marshal.GetObjectForIUnknown(IntPtr pUnk) whith is available in Net.Core. As I know Excel.Application is a COM-object and therefore it have IUnknown interface. I tried to get this pointer throught a process of open excel application that can be found by name. 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.
Is there a way in Net.Core to get access the open Excel workbook?