I have the following sub running on my form. It can take a while for the sub to run so I want to change the cursor to an hourglass and display a Please Wait message while the code is running. Here is my procedure:
Public Sub GoToSheets(sheetName As String)
'This sub is used to open the workbook on the selected sheet.
'This checks to see if Excel workbook is opened, if not it
'opens Excel, the workbook and then the selected sheet. If the workbook is
'opened, it goes to the selected sheet.
'#param sheetName, sheet to be displayed
Try
'get an existing excel.application object
xlApp = CType(GetObject(, "Excel.Application"), Application)
Catch ex As Exception
'no existing excel.application object - create a new one
xlApp = New Excel.Application
End Try
Dim xlWBName As String = "2011.1004.Compensation Template"
Dim xlBookPath As String = Path.Combine(Directory.GetCurrentDirectory())
xlApp.Visible = True
Try
'get the opened workbook
xlBook = xlApp.Workbooks(xlWBName & ".xlsx")
Catch ex As Exception
'open it
xlBook = xlApp.Workbooks.Open(xlBookPath & "\" & xlWBName & ".xlsx")
End Try
Try
xlSheet = CType(CType(xlBook.Sheets("summarySheet"), Excel.Worksheet), Excel.Worksheet)
Dim strChckRange As String = xlSheet.Range("A2").Value
If strChckRange Is Nothing Then
Dim frmClientInfo As New frmClientInformation
frmClientInfo.ShowDialog()
closeXLApp()
Else
xlSheet = CType(CType(xlBook.Sheets(sheetName), Excel.Worksheet), Excel.Worksheet)
'close the navigation instance on the welcome page
frmNavigation.Close()
'activate requested sheet
xlSheet.Activate()
'display as dashboard
DashboardView()
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
frmWelcomePage.Hide()
chkForm()
End If
Catch ex As Exception
End Try
End Sub
I have done some research on this, but so far nothing for Visual Basic.
I suggest creating a PleaseWaitForm that has the label of Please Wait... message on it and then have the form shown as mode-less, change the cursor to hourglass, do Excel work, change cursor back to default and hide the PleaseWaitForm.
Dim pleaseWait As New PleaseWaitForm
pleaseWait.Show()
' Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor
Application.DoEvents
' Execute your GoToSheets method here
' Set cursor as default arrow
Cursor.Current = Cursors.Default
' Hide the please wait form
pleaseWait.Hide()
Related
I have some blank instance of excel opened. I want to be able to close the instances of excel that does not have a workbook associated with it.
Public xlsApp As Excel.Application
Public xlsWB As Excel.Workbook
public openExcel()
Try
Dim path As String
path = "C:\excel.xlsm"
xlsWB = xlsApp.Workbooks.Open(path)
Catch ex As Exception
My.Application.Log.WriteException(ex, TraceEventType.Error, "Additional information or details")
Exit Sub
End Try
end sub
Public Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
====when run will open one excel, if excel window is close, the instance stays on, you will see the blank excel workbook. I want to close that instance when this sub re runs.
public doThis()
releaseObject(xlsApp)
releaseObject(xlsWB)
openExcel() <<==
end sub
For Excel to close properly you have to unload all of your COM objects
Dim xl As Excel.Application = New Excel.Application()
Dim wb As Excel.Workbook = xl.Workbooks.Add()
Dim ws As Excel.Worksheet = wb.Worksheets.Add()
wb.Close()
xl.Quit()
ReleaseComObject(ws)
ReleaseComObject(wb)
ReleaseComObject(xl)
ws = Nothing
wb = Nothing
xl = Nothing
If you aren't consuming the Excel instance and you are just displaying it then maybe try this. This will kill the process as soon as it is created so you'll want to put the p.Kill() in another place. Also note that this kills the process so no changes will be saved.
Dim p As System.Diagnostics.Process = System.Diagnostics.Process.Start(path)
p.Kill()
I am trying to list all the opened workbooks and their corresponding sheets in the task bar after that I should be able to select one workbook of the list and open it. My first try was to to show Excel process in Task-Manager but it only shows one open workbook without detecting the number of sheets.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim name As Process() = Process.GetProcessesByName("Excel")
For Each names In name
ListView1.Items.Add(names.MainWindowTitle)
If names.MainWindowTitle <> "" Then
ListBox1.Items.Add(names.MainWindowTitle)
End If
Next
End Sub
Next I tried to use this code but also I can only display one opened workbook, I don't know how to loop through them. I don't have problem of changing the whole code if you have any other method cause I am not sure that it's the solution.
Dim oXL As Microsoft.Office.Interop.Excel.Application
oXL = TryCast(System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"), Microsoft.Office.Interop.Excel.Application)
oXL.WindowState = Microsoft.Office.Interop.Excel.XlWindowState.xlMinimized
Dim y As String
y = oXL.ActiveWorkbook.Name
ListBox1.Items.Add(y)
Dim objExcel As Excel.Application = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
Dim objWorkBook As Excel.Workbook = Nothing
Dim totalWorkBooks As Integer = objExcel.Workbooks.Count
For i As Integer = 1 To totalWorkBooks
objWorkBook = objExcel.Workbooks(i)
With objWorkBook
FullName = .FullName
OnlyName = .Name
Using a button in VB.NET form, an .xlsm file is opened and saved as .xlsx. The code in the .xlsx file (Workbook_BeforeClose event) is NOT deleted after the file is saved, therefore, when I want to close the file the code runs! After reopening the file there is no code left.
This is my VB.NET class:
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Form1
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkbooks As Excel.Workbooks
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
xlApp = New Excel.Application
xlWorkbooks = xlApp.Workbooks
xlWorkBook = xlWorkbooks.Open("C:\Temp\testTemplate.xlsm")
xlApp.DisplayAlerts = False
xlWorkBook.SaveAs(Filename:="C:\Temp\testTemp.xlsx", FileFormat:=51) '51=xlOpenXMLWorkbook
xlApp.DisplayAlerts = True
xlApp.Visible = True
'Clean Up
releaseObject(xlWorkBook)
releaseObject(xlWorkbooks)
releaseObject(xlApp)
End Sub
Private Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
GC.WaitForPendingFinalizers()
End Try
End Sub
End Class
This is in the Excel file, workbook module:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "event still runs"
End Sub
How to save the file properly so that NO code would remain in it?
You're right, the code isn't deleted until after it's closed. I suppose you could set some type of flag in the xlsm's BeforeClose event that checks its file type and only runs if it's xlsm. Or you could do a Worksheets.Copy instead of the SaveAs and save the resulting workbook (which won't contain the VBA) as an xlsx, but there could be reference issues to clean up. Or you could set xlApp.EnableEvents=False, close the newly saved xlsx, set it back to True and re-open the xlsx.
Here's a post I wrote on the second option: http://yoursumbuddy.com/copy-an-xlsm-xlsx/
I have the below code. Originally, the code was a VBA macro that I built. It ended up working perfectly (sending word doc as an e-mail to a desired range of recipients, iterating through each row). The function begins at the Sub SendIt_Click (very last sub) in the code. The rest is for the add-in. When I click the button in Excel, the MsgBox's work, but the code doesn't send anything. It worked in Excel VBA, but I'm at a loss as to why it isn't working here.
Update: It does open the word doc, just doesn't send e-mail.
Imports Extensibility
Imports System.Runtime.InteropServices
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Core
<GuidAttribute("209AD741-0B95-4931-80CF-4DCE33B761C9"), ProgIdAttribute("MailMerge.Connect")> _
Public Class Connect
Implements Extensibility.IDTExtensibility2
Private applicationObject As Object
Private addInInstance As Object
Dim WithEvents SendIt As CommandBarButton
Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown
On Error Resume Next
' Notify the user you are shutting down, and delete the button.
MsgBox("MailMerge Add-in is unloading.")
SendIt.Delete()
SendIt = Nothing
End Sub
Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
End Sub
Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete
Dim oCommandBars As CommandBars
Dim oStandardBar As CommandBar
On Error Resume Next
' Set up a custom button on the "Standard" command bar.
oCommandBars = applicationObject.CommandBars
If oCommandBars Is Nothing Then
' Outlook has the CommandBars collection on the Explorer object.
oCommandBars = applicationObject.ActiveExplorer.CommandBars
End If
oStandardBar = oCommandBars.Item("Standard")
If oStandardBar Is Nothing Then
' Access names its main toolbar Database.
oStandardBar = oCommandBars.Item("Database")
End If
' In case the button was not deleted, use the exiting one.
SendIt = oStandardBar.Controls.Item("My Custom Button")
If SendIt Is Nothing Then
SendIt = oStandardBar.Controls.Add(1)
With SendIt
.Caption = "Send to Mail Group with Outlook"
.Style = MsoButtonStyle.msoButtonCaption
' The following items are optional, but recommended.
' The Tag property lets you quickly find the control
' and helps MSO keep track of it when more than
' one application window is visible. The property is required
' by some Office applications and should be provided.
.Tag = "MailMerge"
' The OnAction property is optional but recommended.
' It should be set to the ProgID of the add-in, so that if
' the add-in is not loaded when a user clicks the button,
' MSO loads the add-in automatically and then raises
' the Click event for the add-in to handle.
.OnAction = "!<MyCOMAddin.Connect>"
.Visible = True
End With
End If
' Display a simple message to show which application you started in.
MsgBox("Started in " & applicationObject.Name & ".")
oStandardBar = Nothing
oCommandBars = Nothing
End Sub
Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection
On Error Resume Next
If RemoveMode <> Extensibility.ext_DisconnectMode.ext_dm_HostShutdown Then _
Call OnBeginShutdown(custom)
applicationObject = Nothing
End Sub
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
MsgBox("On Connection In MailMerge")
applicationObject = application
addInInstance = addInInst
' If you aren't in startup, manually call OnStartupComplete.
If (connectMode <> Extensibility.ext_ConnectMode.ext_cm_Startup) Then _
Call OnStartupComplete(custom)
End Sub
Private Sub SendIt_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, ByRef CancelDefault As Boolean) Handles SendIt.Click
MsgBox("SendIt button was pressed!")
'Dimension variables.
Dim OL As Object, MailSendItem As Object
Dim myxl As Excel.Application
Dim ws As Excel.Worksheet
Dim wd As Word.Application
Dim toRange = InputBox("Input cell range in R1:C1 format.", "Input range", "B3:B4")
Dim subj = InputBox("Input subject.", "Input subject", "TESTING")
wd = CreateObject("Word.Application")
Dim doc As Word.Document
'On Error Resume Next
'Assigns Word file to send
wd = GetObject(, "Word.Application")
If wd Is Nothing Then
wd = CreateObject("Word.Application")
'blnWeOpenedWord = True (MAY NOT NEED THIS)
End If
doc = wd.Documents.Open _
(FileName:="H:\Thought Pieces\Small Cap Liquidity\A Closer Look at Small Cap Liquidity.doc", ReadOnly:=False)
'Set itm = doc.MailEnvelope.Item
'Starts Outlook session
OL = CreateObject("Outlook.Application")
MailSendItem = doc.MailEnvelope.Item
myxl = GetObject(, "Excel.application")
ws = myxl.ActiveSheet
'Creates message
For Each xRecipient In ws.Range(toRange)
With MailSendItem
.Subject = subj
.To = xRecipient
.Cc = xRecipient.Offset(0, 5)
.Attachments.Add("H:\Thought Pieces\Small Cap Liquidity\A Closer Look at Small Cap Liquidity.pdf")
.Send()
End With
doc.Close(SaveChanges:=0)
wd = GetObject(, "Word.Application")
doc = wd.Documents.Open _
(FileName:="H:\Thought Pieces\Small Cap Liquidity\A Closer Look at Small Cap Liquidity.doc", ReadOnly:=False)
MailSendItem = doc.MailEnvelope.Item
myxl.Application.Wait(Now + TimeValue("00:00:20"))
Next xRecipient
'Ends Outlook session
OL = Nothing
End Sub
End Class
At OP's request, what I am doing is just a postmortem summation :)
Whenever in doubt, debug the code yourself. Step through the code but in situations like this when you are testing your code for a VSTO Add-In, I generally put few message boxes in my code so that I know which line is executing and which is not.
Op followed this approach and found two lines which were the culprit.
.To = xRecipient
and
myxl.Application.Wait(Now + TimeValue("00:00:20"))
The first one failed because that field expects a string value. It was sorted using
.To = xRecipient.Value.ToString()
I would recommend doing the same for .CC field as well.
Regarding the other Now + TimeValue("00:00:20") was not being calculated correctly. That is because you have "+" sign. Try doing this in VB.Net
MessageBox.Show(Now + TimeValue("00:00:20"))
The alternative was to use
myxl.Application.Wait(Now.AddSeconds(20))
Hope this helps.
I have a vb .net app which opens an Excel file and puts values in it. But if the user (who I have to assume is extremely dumb :) ), closes the workbook, next time my app will try to put a value to the file, it will show an error since there is no excel file open.
How can I either prevent excel from being closed, or disable the buttons when excel is closed?
I'm working with Excel 2003 on Windows 7
EDIT: Here is the code to open Excel
Private Sub Open_button_Click(sender As Object, e As EventArgs) Handles Open_button.Click
OpenFileDialog1.FileName = ""
OpenFileDialog1.Filter = "Excel files (*.xls)|*.xls"
OpenFileDialog1.ShowDialog()
filePath = OpenFileDialog1.FileName
If System.IO.File.Exists(filePath) Then
oExcel = CreateObject("Excel.Application")
oExcel.Visible = True
oBook = oExcel.Workbooks.Open(filePath)
oSheet = oBook.WorkSheets(1)
oExcel.Sheets(1).Select()
oExcel.ScreenUpdating = True
xlDown = Microsoft.Office.Interop.Excel.XlDirection.xlDown
xlUp = Microsoft.Office.Interop.Excel.XlDirection.xlUp
Me.Activate()
End If
End Sub
You can add event handler to detect the close event and disable the button in the handler.
From https://support.microsoft.com/en-us/kb/822750
Private EventDel_BeforeBookClose As Excel.AppEvents_WorkbookBeforeCloseEventHandler
Then after you have created the Excel objects
EventDel_BeforeBookClose = New Excel.AppEvents_WorkbookBeforeCloseEventHandler( _
AddressOf BeforeBookClose)
AddHandler xlApp.WorkbookBeforeClose, EventDel_BeforeBookClose
And add a sub to handle the event
Private Sub BeforeBookClose(ByVal Wb As Excel.Workbook, ByRef Cancel As Boolean)