VB.Net Add Workbook to Running EXCEL Instance - excel

I am working on AutoCAD plugin. Trying to implement function where it first looks for already running EXCEL instances so I just Add new workbook to existing instance instead of always creating new process.
My code fails at the point where it tries to find running process. For some reason it always detects running EXCEL process, I checked it at task manager, it is not there so that's why my plugin crashes at Marchal.GetActiveObject method because it's trying to get that running process...
My functions' code so far:
Private Function GetExcelWorksheet() As Excel.Worksheet
Dim excel As Excel.Application
Dim activeWorksheet As Excel.Worksheet = Nothing
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
Dim ExcelInstances As Process() = Process.GetProcessesByName("EXCEL")
If ExcelInstances.Count() = 0 Then
Exit Function
End If
excel = TryCast(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
If excel Is Nothing Then Exit Function
excel.Visible = True
wb = excel.Workbooks.Add
ws = wb.Worksheets(1)
Return ws
End Function

'Excel.vb
Imports System
Imports System.Runtime.InteropServices
Public Module AnythingYouWantToCallIt
Sub Main
Dim Excel as Object
Dim wb as Object
Dim WS as Object
On Error Resume Next
Excel = GetObject(, "Excel.Application")
If Err.number = 429 then
Msgbox("No Excel running")
err.clear
Excel = CreateObject("Excel.Application")
If err.number = 429 then
MsgBox("Excel Not Installed")
err.clear
Else
MsgBox("New Excel has started")
End If
Else
Msgbox("Existing Excel connected to")
End If
WB = Excel.Workbooks.Add
WS = wb.Worksheets(1)
MsgBox(ws.name)
'If in a function
'Main = WS
End Sub
End Module
This does the BASIC way.
To compile above file paste following lines into a batch file and name above file excel.vb. Put the bat file in same folder as excel.vb and double click batch file.
REM Excel.bat
REM This file compiles Excel.vb to Excel.exe
REM To use
REM Excel
Rem Example
Rem
Rem Excel
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\vbc.exe" /target:winexe /out:"%~dp0\Excel.exe" "%~dp0\Excel.vb"
pause
Does not require Visual Studio

One would only add a Workbook, if a Workbook wasn't already open. Try the following (comments are throughout the code):
Create a new project Windows Forms App (.NET Framework)
Add Reference:
VS 2022:
In VS menu, click Project
Select Add Reference...
Click COM
Check Microsoft Excel xx.x Object Library (ex: Microsoft Excel 16.0 Object Library)
Click OK
Add the following Imports
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Runtime.InteropServices
GetExcelWorksheet:
Private Function GetExcelWorksheet() As Excel.Worksheet
Dim excel As Excel.Application
Dim activeWorksheet As Excel.Worksheet = Nothing
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
'get existing Excel processes
Dim ExcelInstances As Process() = Process.GetProcessesByName("EXCEL")
For Each instance In ExcelInstances
Debug.WriteLine($"ExcelInstances: ProcessName: {instance.ProcessName} Id: {instance.Id}")
Next
If ExcelInstances.Count() = 0 Then
Debug.WriteLine("No Excel instances found")
Exit Function
End If
Debug.WriteLine("Getting Active Excel instance...")
excel = TryCast(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
If excel Is Nothing Then Exit Function
Debug.WriteLine("Setting Excel visible")
'ensure Excel is visible
excel.Visible = True
'get active workbook
wb = excel.ActiveWorkbook
If wb Is Nothing Then
Debug.WriteLine("Adding Workbook...")
wb = excel.Workbooks.Add()
End If
Debug.WriteLine($"wb.Sheets.Count: {wb.Sheets.Count}")
'set worksheet
ws = DirectCast(wb.Sheets(1), Excel.Worksheet)
'activate worksheet
ws.Activate()
'add new Worksheet
ws = DirectCast(wb.Sheets.Add(After:=wb.Sheets(1)), Excel.Worksheet)
ws.Name = "My Worksheet Name" 'set worksheet name
Debug.WriteLine($"wb.Sheets.Count: {wb.Sheets.Count}")
'set value - for A1 also known as 1,1
ws.Cells(1, 1) = $"{DateTime.Now.ToString("HH:mm:ss.fff")}"
Return ws
End Function
Here are some additional methods that may be useful:
Note: If your application has open resources to Excel, Excel may still be running even after clicking the X(in the upper-right corner) of the Excel window. If one opens Task Manager, Microsoft Excel can be seen under "Background processes". To quit Excel, see the code below.
Public Function IsExcelRunning() As Boolean
'get existing Excel processes
Dim ExcelInstances As Process() = Process.GetProcessesByName("EXCEL")
For Each instance In ExcelInstances
Debug.WriteLine($"ExcelInstances: ProcessName: {instance.ProcessName} Id: {instance.Id}")
Next
If ExcelInstances.Count() = 0 Then
Debug.WriteLine($"IsExcelRunning: False")
Return False
End If
Debug.WriteLine($"IsExcelRunning: True")
Return True
End Function
Public Function IsExcelVisible() As Boolean
Dim excel As Excel.Application
'get existing Excel processes
Dim ExcelInstances As Process() = Process.GetProcessesByName("EXCEL")
For Each instance In ExcelInstances
Debug.WriteLine($"ExcelInstances: ProcessName: {instance.ProcessName} Id: {instance.Id}")
Next
If ExcelInstances.Count() = 0 Then
Debug.WriteLine("No Excel instances found")
Exit Function
End If
Debug.WriteLine("Getting Active Excel instance...")
excel = TryCast(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
If excel Is Nothing Then Return False
Debug.WriteLine($"IsExcelVisible: {excel.Visible}")
Return excel.Visible
End Function
Public Sub QuitExcel()
Dim excel As Excel.Application
Dim wb As Excel.Workbook = Nothing
Dim ws As Excel.Worksheet = Nothing
'get existing Excel processes
Dim ExcelInstances As Process() = Process.GetProcessesByName("EXCEL")
For Each instance In ExcelInstances
Debug.WriteLine($"ExcelInstances: ProcessName: {instance.ProcessName} Id: {instance.Id}")
Next
If ExcelInstances.Count() = 0 Then
Debug.WriteLine("No Excel instances found")
Exit Sub
End If
Debug.WriteLine("Getting Active Excel instance...")
excel = TryCast(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
If excel Is Nothing Then Exit Sub
wb = excel.ActiveWorkbook
If wb IsNot Nothing Then
Debug.WriteLine($"Closing Excel Workbook...")
wb.Close(False)
'release resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wb)
End If
Debug.WriteLine($"Quiting Excel.")
'quit Excel
excel.Quit()
'release resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel)
GC.Collect() 'force garbage collection
End Sub
Resources
Microsoft.Office.Interop.Excel
How do you list all processes on the command line in Windows?
C# Close Excel Instance opened by another application

Related

How to open an Excel workbook from Access

I currently have a string in Microsoft Access that is delegating functions to an external Application.
I have gotten so far as to copying a set of data from the external application.
I want to paste this into an excel workbook that is not open but exists. C:\Users\abcdef\Desktop KDNR.xlsx
how can I integrate this function into my sub procedure?
Thank you in advance
I attempted simply writing
Dim x as Workbook
set x = Workbooks.Open (" workbook name ")
Howoever, i got the compile error "user defined type not defined"
when i just write
Workbooks.Open (" workbook name ")
i get the compile error
"variable not defined"
Use Excel From Access
This is a basic example of how to work with Excel from Access.
It opens a new instance of Excel (whether Excel is open or not), opens the workbook, writes the string Test to cell A1 of worksheet Sheet1, saves and closes the workbook, and finally quits the Excel instance.
' If you haven't already, create a reference to
' "Tools->References->Microsoft Excel 16.0 Object Library"!
Sub Test()
Dim DestinationFilePath As String
DestinationFilePath = Environ("USERPROFILE") & "\DeskTop\KDNR.xlsx"
Dim xlApp As Excel.Application: Set xlApp = New Excel.Application
xlApp.Visible = True ' out-comment when done developing; default is 'False'
Dim wb As Workbook: Set wb = xlApp.Workbooks.Open(DestinationFilePath)
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
ws.Range("A1").Value = "Test"
wb.Close SaveChanges:=True
xlApp.Quit
End Sub

Excel Vba Copy Method of Worksheet fails - Copy from xlApp to ThisWorkbook

I posted a question recently on interacting with another WB in a separate instance of Excel.
How to add Open Workbook to "Application.Workbooks" collection and/or interact with Workbook
But I had hardcoded the copy/paste range for testing, and now I'm having trouble with coping the entire worksheet to the "main wb". Eg: xlApp.Worksheets(1).Copy After:=Application.ActiveWorkbook.Sheets(1)
I get the error Copy Method of Worksheet Failed and ideas how to adjust this to work?
Public Sub Copy_External_WB()
Dim xlApp As Excel.Application, xlBook As Worksheet, i As Long
For i = 1 To 10
On Error Resume Next
Set xlApp = GetObject("Book" & i).Application
If Err.Number = -2147221020 Then
Err.Clear: On Error GoTo 0
Else
On Error GoTo 0
Exit For
End If
Next i
If Not xlApp Is Nothing Then
Set xlBook = xlApp.Worksheets(1)
Debug.Print xlApp.hWnd, Application.hWnd
Else
MsgBox "No Excel session with Book(1 - 10) open could be found..."
xlApp.Quit: Exit Sub
End If
'Dim CopyFrom As Range
'Set CopyFrom = xlBook.Range("A1:AQ56")
'Dim DS As Worksheet
'Set DS = ThisWorkbook.Worksheets("Merged")
'DS.Range("A1:AQ56").Resize(CopyFrom.Rows.Count).Value = CopyFrom.Value
xlApp.Worksheets(1).Copy After:=Application.ActiveWorkbook.Sheets(1)
xlApp.DisplayAlerts = False
xlApp.Quit
xlApp.DisplayAlerts = True
Set xlApp = Nothing
End Sub
You cannot copy a whole sheet object between different Excel instances.
Options:
Use VBA to save the other workbook to file, then open it in the instance where your code is running, and copy the sheet to your workbook
Copy (eg) the UsedRange from the other instance's worksheet, then paste in your primary instance workbook

How to fix closing Excel from inside Access

I want to close an Excel workbook from inside Access using VBA code. The following code opens the workbook and runs a VBA module in the workbook correctly. Closing the workbook prompts with the standard Save dialogue which I want to avoid.
I tried modifying the statement .Workbooks.Close to .Workbooks.Close SaveChanges:=True but that actually crashes the code.
Public Function Open_Share_Price_Excel()
' Change Cursor to Hourglass
Screen.MousePointer = 11
Dim Expath, ModName As String
Dim XLApp As Object
Set XLApp = CreateObject("Excel.Application")
'
'Define where the Excel Spreadsheet is and the module to run
'
Expath = "C:\Users\peter\Documents\Financial Affairs\Shares\Share Price Bing.xlsm"
ModName = "Combined_Module"
With XLApp
.Application.Visible = True
.Application.DisplayAlerts = False
.UserControl = True
.Workbooks.Open Expath
.Run ModName
.Workbooks.Close
End With
XLApp.Quit
Set XLApp = Nothing
'Change Cursor back and display finished message
Screen.MousePointer = 0
MsgBox ("Price Update Finished - OK to Continue")
End Function
I tried modifying the statement .Workbooks.Close to .Workbooks.Close SaveChanges:=True but that actually crashes the code.
Any suggestions welcome.
Secondly, I would like to ensure that I close all the excel workbooks as I understand that the workbook Personal.xlsx may also be open. When I manually close the Excel spreadsheet it closes, but then EXcel immediately re-opens with a blank workbook.
Help this newbie please
What you need to do is to set the opened workbook to a variable Set OpenedWb = .Workbooks.Open(Expath) so you can access exactly that workbook to close it OpenedWb.Close SaveChanges:=True.
.Workbooks.Close does not work because Workbooks repersents all workbooks and not a specific one (but you must close each workbook on its own).
Please note that Dim Expath, ModName As String only declares ModName As String but Expath As Variant. In VBA you need to specify a type for every variable, otherwise it is Variant by default. So you must use: Dim Expath As String, ModName As String to make them both strings.
Your Function does not return anything. Therfore it should be a procedure Sub instead of a function.
You would end up using something like below:
Public Sub Open_Share_Price_Excel()
' Change Cursor to Hourglass
Screen.MousePointer = 11
'
'Define where the Excel Spreadsheet is and the module to run
'
Dim Expath As String
Expath = "C:\Users\peter\Documents\Financial Affairs\Shares\Share Price Bing.xlsm"
Dim ModName As String
ModName = "Combined_Module"
Dim XLApp As Object
Set XLApp = CreateObject("Excel.Application")
With XLApp
.Application.Visible = True
.Application.DisplayAlerts = False
.UserControl = True
Dim OpenedWb As Object
Set OpenedWb = .Workbooks.Open(Expath)
.Run ModName
OpenedWb.Close SaveChanges:=True
End With
XLApp.Quit
Set XLApp = Nothing
'Change Cursor back and display finished message
Screen.MousePointer = 0
MsgBox ("Price Update Finished - OK to Continue")
End Sub

Create Copy Of Excel Worksheet using Word VBA

With an already-opened workbook, I want to create a copy of a worksheet ("Template") and re-name it with the value I have in an array. When I debug the code the copy is created when I execute the line but I still get an error 424: object required.
I've tried On Error Resume Next but since I already used On Error GoTo in my sub it isn't read.
Dim oXL As Excel.Application 'Requires loading "Microsoft Excel 16.0 Object Library" from Tools -> References
Dim oWB As Excel.Workbook
Set oXL = New Excel.Application
Set oWB = oXL.Workbooks.Open(FileName:=WorkbookToWorkOn) 'Opens Excel
oXL.Visible = True 'Shows Excel window while running code. Set to false after finished editing.
Dim ws As Worksheet
For i = LBound(seller_names) To UBound(seller_names)
'On Error Resume Next 'Doesn't work
Set ws = oXL.ActiveWorkbook.Sheets("Template").Copy(After:= _
oXL.ActiveWorkbook.Sheets(oXL.ActiveWorkbook.Sheets.Count))
ws.name = seller_names(i)
Next i
Sheets.Copy doesn't return a reference to the copied sheet, so you need to first copy the sheet, then get a reference to it:
With oXL.ActiveWorkbook
.Sheets("Template").Copy After:= .Sheets(.Sheets.Count)
Set ws = .Sheets(.Sheets.Count)) '<< get the copy
ws.name = seller_names(i)
End With
On Error Resume Next should always work - but is not always a good solution - unless you have "Break on all errors" enabled in your VBA Options.

Editing Excel spreadsheats from Word with VBA

How do I edit excel spreadsheets from word using VBA?
First you need to set a reference to the version of Excel you are running. In the VBE go to Tools>References and click Microsoft Excel 12.0 Object Library (12.0 for 2007, 11.0 for 2003) etc.
Then you can code something like this (opens a new instance of Excel, opens, edits and saves a new workbook). You'd use GetObject to access a running instance of Excel:
Sub EditExcelFromWord()
Dim appExcel As Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Set appExcel = CreateObject("Excel.Application")
With appExcel
.Visible = True
Set wb = .Workbooks.Add
Set ws = wb.Worksheets(1)
ws.Range("A1").Value2 = "Test"
wb.SaveAs ThisDocument.Path & Application.PathSeparator & "temp.xls"
Stop 'admire your work and then click F5 to continue
Set ws = Nothing
Set wb = Nothing
Set appExcel = Nothing
End With
End Sub

Resources