我正在使用 vb.net 和 .net 8.0.2。应用程序在 Windows 11 上运行。 我已经尝试了几个小时来指向用户已经打开的 Excel 文件。
我尝试过:
Dim app_excel As Microsoft.Office.Interop.Excel.Application
app_excel = GetObject(, "Excel.Application")
wbk = app_excel.Workbooks("filename.xlsx")
这不起作用,oXL 正在创建一个新的 Excel 应用程序,而 wbk 为空。
我也尝试过:
app_excel = CType(System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"), Excel.Application)
wbk = app_excel.Workbooks("filename.xlsx")
但我收到 IDE 错误,指出 GetActiveObject 不是 Marshal 的成员。 显然 Marshal 已在最新版本的 .net GetActiveObject 中重建,不再存在。 我看到一些资源说他们必须完全重建 Marshal,所以我用 C# 构建了 Marshal2 类,如下所述: 未从 System.Runtime.InteropServices.Marshal C# 中找到 GetActiveObject 的定义
并在我的代码中使用它:
Dim ExcelInstance As Excel.Application = ProjectMarshal.Marshal2.GetActiveObject("Excel.Application")
wkb_configFile = ExcelInstance.Workbooks("configuration.xlsm")
它确实可以编译,但在执行时出现“无效索引”错误。 当我检查监视窗口时,尽管文件已打开,但 ExcelInstance 中似乎没有任何工作簿。
如果我将第三行替换为:
wkb_configFile = ExcelInstance.Workbooks(1)
我得到 wkb_configFile = "Book1" 这很可能是 Excel 启动时默认打开的工作簿。 ExcelInstance.Workbooks(2) 不存在(同时打开了 2 个文件)。
3 月 22 日编辑: 在社区成员,特别是 user246821 的帮助下,我得出的结论是,为项目定位 .net Framework (4.8) 而不是 .net 8.0 是更好的选择。它似乎确实适用于标准 GetObject(, "Excel.Application") 方法。 但是,现在我运行时,尽管打开了文件,但仍然找不到文件。我怀疑这可能是因为打开了其他 Excel 文件,并且每个 Excel 在代码中创建了一个 Excel 应用程序的单独实例。 我添加了对所有 Excel 实例的检查以找到正确的工作簿:
Dim ExcelInstances As Process() = Process.GetProcessesByName("EXCEL")
Dim instance As Microsoft.Office.Interop.Excel.Application'EXCEL
For Each instance In ExcelInstances
'If app_excel.Workbooks(s_pathToFileToOpen) IsNot Nothing Then
If instance.Workbooks("configuration.xlsx") IsNot Nothing Then
fun_isFileOpened = True
Exit Function
End If
Debug.WriteLine($"ExcelInstances: ProcessName: {instance.ProcessName} Id: {instance.Id}")
Next
感谢您的阅读!
以下演示如何使用 VB.NET (.NETFramework) 项目与打开的 Excel 工作簿进行交互。使用组件对象模型 (COM) 时,在使用完 COM 对象后释放它们非常重要。使用 Visual Studio 调试器并引发异常时,COM 对象可能不会被释放,并且 Microsoft Excel 进程仍然在后台运行 - 即使在关闭 Microsoft Excel 后也是如此。您可以通过打开任务管理器(即:按Ctrl-Alt-Del)并在后台进程下查找Microsoft Excel来验证这一点。在下面的代码中,检测到这种情况并终止孤立进程。
注意:虽然下面的代码似乎可以工作,但它的测试有限,这意味着应该对其进行测试以确保其行为符合预期。
尝试以下操作:
Public Sub UpdateExcel(value As String, fileMonikerName As String)
Dim excelApp As Excel.Application = Nothing
Dim desiredWb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
Try
Dim ExcelProcesses() As Process = Process.GetProcessesByName("EXCEL")
If ExcelProcesses.Count() = 0 Then
Debug.WriteLine("Info: No Excel processes found.")
Exit Sub
End If
For Each p As Process In ExcelProcesses
Debug.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} - p.Id: {p.Id} p.MainWindowHandle: {p.MainWindowHandle.ToString("X8")}")
If p.MainWindowHandle = IntPtr.Zero Then
'an exception in this method may cause Excel to remain running in
'the background even after both this program and Excel have been closed
'if the Excel process is valid p.MainWindowHandle <> IntPtr.Zero
'however, if the Excel process has been orphaned, then p.MainWindowHandle = IntPtr.Zero
'and the 'Microsoft Excel' process can be observed in Task Manager under 'Background processes'
'kill orphaned Excel process
p.Kill()
Debug.WriteLine("Info: An orphaned Excel process was terminated, but no active Excel instances were found. Open desired Excel workbook and try again.")
Exit Sub
End If
Next
'get existing Excel instance
excelApp = DirectCast(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
'prevent prompting to save
excelApp.DisplayAlerts = False
'ensure Excel is visible
excelApp.Visible = True
'get desired workbook
For Each workbook As Excel.Workbook In excelApp.Workbooks
Debug.WriteLine($" wb FullName: '{workbook.FullName}' Name: '{workbook.Name}'")
If fileMonikerName = workbook.FullName Then
'set value
desiredWb = workbook
For Each worksheet As Excel.Worksheet In desiredWb.Sheets
Debug.WriteLine($" ws Name: '{worksheet.Name}'")
'ToDo: select desired worksheet
'set value
ws = worksheet
'activate worksheet
ws.Activate()
Next
End If
Next
If desiredWb Is Nothing Then
Throw New Exception($"Error: Desired workbook not found ('{fileMonikerName}').")
End If
If ws Is Nothing Then
Throw New Exception("Error: Worksheet not found.")
End If
'set value - for A1 also known as 1,1
'format column to display date
ws.Cells().Range("A1", "A4").EntireColumn.NumberFormat = "mm/dd/yyyy"
'set value
ws.Cells(1, 1) = $"{DateTime.Now.ToOADate()}"
ws.Cells(1, 2) = value
'save
desiredWb.SaveAs(fileMonikerName, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value)
Finally
If ws IsNot Nothing Then
Marshal.ReleaseComObject(ws)
ws = Nothing
End If
If desiredWb IsNot Nothing Then
Marshal.ReleaseComObject(desiredWb)
desiredWb = Nothing
End If
If excelApp IsNot Nothing Then
Marshal.ReleaseComObject(excelApp)
excelApp = Nothing
GC.Collect()
End If
End Try
End Sub
用法:
Using ofd As OpenFileDialog = New OpenFileDialog()
ofd.Filter = "Excel File (*.xlsx)|*.xlsx"
If ofd.ShowDialog() = DialogResult.OK Then
UpdateExcel($"Test {DateTime.Now.ToString("HH:mm:ss")}", ofd.FileName)
End If
End Using
资源: