I am trying to write a code that exports data to excel after user prompted actions.
Basically, I have been able to export to Excel successfully, but the 2nd instance I want to write to a new tab instead of a new Excel application.
oExcel = CreateObject("Excel.Application")
oExcel.Visible = True
oBook = oExcel.Workbooks.Add
oSheet = oBook.Worksheets(3)
oSheet.Delete()
oSheet = oBook.Worksheets(2)
oSheet.Delete()
oSheet = oBook.Worksheets(1)
oSheet.Name = "Run " & Counter
At this point, the user will press a button, making Excel no longer active.
So when I want to write more data to a new sheet, the Object commands do not
'work unless I repeat code exactly.
I tried:
Counter +=1
'For the first instance
If Counter = 1 Then
oExcel = CreateObject("Excel.Application")
oExcel.Visible = True
oBook = oExcel.Workbooks.Add
oSheet = oBook.Worksheets(3)
oSheet.Delete()
oSheet = oBook.Worksheets(2)
oSheet.Delete()
oSheet = oBook.Worksheets(1)
oSheet.Name = "Run " & Counter
Else
'For every instance after that the user wants to do another run
oExcel.ActivateObject(Excel.Application)
oBook = oExcel.Workbooks(1)
oSheet = oBook.Worksheets.Add
oSheet.Name = "Run " & Counter
End If
I have been looking for days and am getting very frustrated. I do not know how to reference back to the open excel in order to continue to writing data ... after the user has pressed a button on the VB form confirming they want to do another run.
To get a reference to an already-running instance of excel you can use GetObject.
Eg:
' Test to see if a copy of Excel is already running.
Private Sub testExcelRunning()
On Error Resume Next
' GetObject called without the first argument returns a
' reference to an instance of the application. If the
' application is not already running, an error occurs.
Dim excelObj As Object = GetObject(, "Excel.Application")
If Err.Number = 0 Then
MsgBox("Excel is running")
Else
MsgBox("Excel is not running")
End If
Err.Clear()
excelObj = Nothing
End Sub
http://msdn.microsoft.com/en-us/library/e9waz863(v=vs.90).aspx
If Excel is not already running you can start a new instance using CreateObject.
I used to write VBA, but I was taught to get out of the habit of using CreateObject. you could also use a boolean just as well, but i imagine thats just preference. You should create the excel object outside the loop, hold reference at class level once its assigned. you then use the loop to solely assign the next sheets and add values. Keeping the dimension at class level means you do not need to get rid of the object immediately, because there is possibility the user might still need to use the reference.
Public Class Form1
Dim firstRun As Boolean = True
Dim xlApp As New Excel.Application
Dim xlWb As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'set up us some excel
xlApp.Visible = True
xlApp.SheetsInNewWorkbook = 1
xlWb = xlApp.Workbooks.Add
'imaginary loop
For i = 0 To 5
Dim msgResponse = MessageBox.Show("Do you want to loop?", "Keep Looping?", MessageBoxButtons.YesNo)
If msgResponse = Windows.Forms.DialogResult.No Then Exit For
If firstRun Then
xlSheet = xlWb.Sheets(1)
firstRun = False
Else
xlWb.Activate()
xlSheet = xlWb.Sheets.Add(After:=xlWb.Sheets(xlWb.Sheets.Count))
End If
xlSheet.Name = "TEST" & i
xlSheet.Range("A1").Value = "Some Data"
Next i
End Sub
End Class
You will need to make sure that you clean up your references once you are certain the user is done with the sheet.
Related
I am a beginner in this matter, could you help me, please?
In PowerPoint, I made code linked to a CommandButton that opens a workbook, when I click on it, Excel opens, but it is flashing on the taskbar and the PowerPoint Presentation remains open. It is possible when clicking on the button Excel opens in front of the Presentation?
Private Sub cmbFAUUSP_Click()
Dim ExcApp As Excel.Application
Set ExcApp = New Excel.Application
ExcApp.Visible = True
ExcApp.Workbooks.Open ("C:\Users\Monster PC\Desktop\tabeladedisciplinas FAUUSP.xlsx")
Set pastatrabalho = ExcApp.ActiveWorkbook
pastatrabalho.Application.ActiveWindow.WindowState = xlMaximized
pastatrabalho.Application.DisplayFullScreen = True
End Sub
If you have not, you should declare all your variables. (Use Option Explicit at the top of the module to help you with that, it will warn you if you forgot to declare a variable)
You don't need to set workbook for what you described so I have commented pastatrabalho, uncomment/remove as you need:
Private Sub cmbFAUUSP_Click()
Dim ExcApp As Excel.Application
Dim pastatrabalho As Excel.Workbook 'Uncomment / Remove as needed
On Error Resume Next
Set ExcApp = GetObject(, "Excel.Application") 'This will retrieve the existing instance of Excel if you already have an Excel running
On Error GoTo -1
If ExcApp Is Nothing Then Set ExcApp = New Excel.Application 'Create a new instance of Excel if not
ExcApp.Workbooks.Open ("C:\Users\Monster PC\Desktop\tabeladedisciplinas FAUUSP.xlsx")
'Replace above line with below if you need to refer to the workbook in the later part of your procedure, if any
'Set pastatrabalho = ExcApp.Workbooks.Open ("C:\Users\Monster PC\Desktop\tabeladedisciplinas FAUUSP.xlsx")
With ExcApp
'Setting Left and Top will brings Excel window to the same location as your Powerpoint (applicable if using multiple monitors)
.Left = Application.Left
.Top = Application.Top
.Visible = True
.WindowState = xlMaximized
.DisplayFullScreen = True
.ActiveWindow.Activate
'AppActivate ExcApp.Caption 'another way of activating, must provide the exact same title as the one shown on your Application (which can differ based on version)
End With
End Sub
In my current project, i need to modify an excel file that is already opened. That mean, i need to see the change in the excel file whenever i modify it.
Since opened file is locked and vb cannot access that file, my solution is to open another excel file, modify its content and then copy to the original file using excel vba, as excel vba can be used to copy data between opening sheets.
Here is the vb code in my other excel file (called TTHT.xlsm):
Private Sub Worksheet_CHANGE(ByVal Target As Range)
Application.ScreenUpdating = False
If Sheet1.[B5].Value = "#" Then
Application.DisplayAlerts = False
With Workbooks.Open(ThisWorkbook.Path & "\PCN.xlsm")
With ThisWorkbook.Sheets("TTHT").[B5]
.Parent.Range("B4").Copy
Sheets("PCN").[B4].PasteSpecial 7
End With
End With
Application.DisplayAlerts = True
End If
End Sub
Runs fine between my 2 opening excel file ( that TTHT one and PCN.xlsm ).
Now all I need to do, is to fill the data into TTHT, and put a "#" into B5 by my code. I think it will work, but it's not..
Private Sub btnUpdate_Click(sender As System.Object, e As System.EventArgs) Handles btnUpdate.Click
Dim oExcel As Object
Dim oBook As Object
Dim oSheet As Object
oExcel = CreateObject("Excel.Application")
oExcel.DisplayAlerts = False
oBook = oExcel.Workbooks.Open(TTHTPath)
oSheet = oBook.Worksheets("TTHT")
oSheet.Range("B4").Value = txtValue_Needed.text
oSheet.Range("B5").Value = "#"
oBook.Save()
'System.Diagnostics.Process.Start(DuongDanPhieuCongNghe)
oSheet = Nothing
oBook.Close()
oBook = Nothing
oExcel.Quit()
oExcel = Nothing
End Sub
Result is, if i open the PCN file and click button, it won't change. If I close the PCN and click button, it will change..
But i need to see the change on the fly, not by close and reopen each time i need to update.
Can someone shed me some light, as to how, or which function ... either vba or vb.net, should i use ?
If the file is already opened and has focus then you can try looking it up in the running objects table.
Dim ExcelApplication As Excel.Application
ExcelApplication = GetObject("C:\Folder\ExcelWorkbook.xls")
Then you can just make your modifications on the instance which you referenced while trying to avoid disrupting the user.
The getobject() function is great; here's a link.
https://msdn.microsoft.com/en-us/library/e9waz863(v=vs.71).aspx
I am using Access(2007) vba to process an Excel(ACCDB) workbook on a Sharepoint 2007 document library. In the process, I update two properties using the ExcelWB.ContentTypeProperties() proerty. It's been working fine literally for years. Today, it stopped working. It throws a "Object Library not registered" error. Research seems to suggest I've somehow gotten an old DLL for Excel registered, and the interface is using an old DLL that doesn't support the property.
My libraries are all found, no changes were made (by me...) in the last month to the machine. It's a client machine, so I can't speak for MS updates, etc. that were made. How can I fix this? It's literally got my client sitting on her hands, unable to work.
Dim xlApp As Excel.Application
Dim xlWB As Excel.WorkBook
Dim xlSH As Excel.Worksheet
Dim xlRA As Excel.Range
Dim bValidWorkbook As Boolean
Dim lngTrueHighestRow As Long
Dim strWorkbookName As String
WorkbookMessage , 3 'Clears the message queue
bValidWorkbook = True
strNewTimesheetStatus = "Rejected"
Set xlApp = New Excel.Application
xlApp.visible = False 'Don't let the workbook be shown
Set xlWB = xlApp.Workbooks.Open(URL) 'Open the workbook
lngCurrentVendorID = ParseVendor(strCurrentVendorName) 'Sets up the vendor recordset and the Labor rate Recordset. If it returns 0, it couldn't find the vendor
If lngCurrentVendorID = 0 Then
bValidWorkbook = False
WorkbookMessage "Workbook Rejected -- Vendor could not be validated"
GoTo ExitWorkbook
End If
'
' If the workbook is read-only, we can't proceed
'
If xlWB.ReadOnly Then
bValidWorkbook = False
WorkbookMessage "Workbook Rejected -- Workbook is read-only state"
GoTo ExitWorkbook
End If
Set xlSH = xlWB.Worksheets(1) 'Must be the first worksheet in the workbook
strWorkbookName = xlWB.NAME
Set xlRA = xlSH.UsedRange 'xlRA is the range of cells in the first workbook that are "USED"
strSheetArray = xlRA 'This sets an array of variants to the two dimensional range xlRA
xlRA.EntireRow.Hidden = False 'Unhides all rows to prevent misunderstandings.
...
...
...
...
If Not xlWB.ReadOnly Then
xlWB.ContentTypeProperties("TimesheetStatus") = strValidateWorkbook***
xlWB.ContentTypeProperties("OverrideStatus") = strNewOverrideStatus
xlWB.Save
End If
The sub below runs from the winform called frmWelcomePage. There are several buttons on my form that use that sub. The sub works as expected, but I had to add an If statement to my code, within that statement, if the condition is met, then the frmWelcomePage needs to close/hide. However, while the everything within the If statement works when the condition is met, my frmWelcomePage does not close, it remains open. If I bypass the condition, at the end of my Sub I also ask to close this form, and that works fine. I can't figure out then why it does not work within the If statement. Here is my code:
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
Cursor.Current = Cursors.WaitCursor
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
frmWelcomePage.Hide() 'it will not close here
Dim frmClientInfo As New frmClientInformation
frmClientInfo.Show()
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() ' it closes here just fine
chkForm()
Cursor.Current = Cursors.WaitCursor
End If
Catch ex As Exception
End Try
End Sub
Have you tried inverting these lines?
frmWelcomePage.Hide() 'it will not close here
Dim frmClientInfo As New frmClientInformation
frmClientInfo.Show()
to
Dim frmClientInfo As New frmClientInformation
frmClientInfo.Show()
frmWelcomePage.Hide() 'it will not close here
this should work unless you have a different event raised when creating the frmClientInfo
in the lines:
frmWelcomePage.Hide() 'frmWelcomePage is hidden as you coded
Dim frmClientInfo As New frmClientInformation
frmClientInfo.Show() 'frmClientInfo shows and implicitly shows its parent: frmWelcomePage
The form frmWelcomePage is the main form (think of it as the parent) of the form frmClientInfo. Your code hides the parent but when you ask the frmClientInfo (think of this as a child) to show the parent is automatically shown.
Try using:
frmCleintInfo.ShowDialog()
The following code works fine but seems to leave instances of excel.exe running in the background. How do I go about closing out this sub properly?
Private Sub ReadExcel(ByVal childform As Fone_Builder_Delux.frmData, ByVal FileName As String)
' In progress
childform.sampleloaded = False
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
Dim xlWorkSheet As Excel.Worksheet
xlApp = New Excel.ApplicationClass
xlWorkBook = xlApp.Workbooks.Open(FileName)
xlWorkSheet = xlWorkBook.Worksheets(1)
Dim columnrange = xlWorkSheet.Columns
Dim therange = xlWorkSheet.UsedRange
childform.datagridHeaders.Columns.Add("", "") ' Super imporant to add a blank column, could improve this
For cCnt = 1 To therange.Columns.Count
Dim Obj = CType(therange.Cells(1, cCnt), Excel.Range)
childform.datagridSample.Columns.Add(Obj.Value, Obj.Value)
childform.datagridHeaders.Columns.Add(Obj.Value, Obj.Value)
Next
For rCnt = 2 To therange.Rows.Count
Dim rowArray(therange.Columns.Count) As String
For cCnt = 1 To therange.Columns.Count
Dim Obj = CType(therange.Cells(rCnt, cCnt), Excel.Range)
Dim celltext As String
celltext = Obj.Value.ToString
rowArray((cCnt - 1)) = celltext
'MsgBox(Obj.Value)
Next
childform.datagridSample.Rows.Add(rowArray)
Next
AdjustHeaders(childform)
childform.sampleloaded = True
End Sub
Short answer: close each item appropriately, then call FinalReleaseComObject on them.
GC.Collect()
GC.WaitForPendingFinalizers()
If xlWorkSheet Is Nothing Then Marshal.FinalReleaseComObject(xlWorkSheet)
If xlWorkBook Is Nothing Then
xlWorkBook.Close(false, false)
Marshal.FinalReleaseComObject(xlWorkBook)
End If
xlApp.Quit()
Marshal.FinalReleaseComObject(xlApp)
Long answer: read this answer to another question (the entire post is helpful too).
I ran into this problem and what I found worked was making sure I called the Close() method on all Workbook and Workbooks objects, as well as the Quit() method on the Excel Application object. I also call System.Runtime.InteropServices.Marshal.ReleaseComObject on every Excel object was instantiated. I do all this in reverse order of age, so the newest object gets cleaned up first and the oldest, which is the Application object, gets taken care of last. I don't know if the order really matters, but it seems like it might.
I've seen examples where GC.Collect() was called at the very end, but I've never had to do that to get the excel.exe process to end.