The Correct Code is
Private Sub DeleteTSheets()
Dim xl As New Excel.Application
Dim wb As Excel.Workbook
Dim ws as Excel.Worksheet
wb = xl.Workbooks.Open("C:\Patches\Main_Final.xlsm")
For Each ws in wb.sheets
If InStr(1, ws.Name, "T") Then
If len(ws.name)=3 then
ws.delete()
End If
End If
Next
wb.Close(Savechanges:=vbTrue)
End Sub
The Code is running only when I removed all macros from the excel sheet!!!
Thanks, Regards
Moheb Labib
Fundamentally, for integer loops use For and not Do loop and handle code logic without On Error redirects. Additionally, since your second code implementation works, your main issue is conflating VBA and VB.Net. Though they share same constructs, these two are fundamentally different languages. VBA is an extended utility with MS Office applications while VB.Net is a standalone general purpose language with its .NET sibling, C#.
Consequently, you cannot exactly copy/paste code between the two types. Main difference with VBA and VB.Net is initializing the COM object, Excel.Application. VB.Net (like C#) requires sourcing in the Microsoft.Office.Interop API.
VBA
Dim xl As New Excel.Application
VB.Net (see docs)
Imports Microsoft.Office.Interop
...
Dim xl As Excel.Application = New Excel.Application()
C# (see docs) (as comparison)
using Excel = Microsoft.Office.Interop.Excel;
...
var xl = new Excel.Application();
Additionally, since COM (Command Object Model) is not limited to Microsoft tools but available resource on Windows machines, other COM-connected languages ike open source tools can connect to Excel. Notice like VB.Net and C#, the respective COM libraries must be imported (PHP doing so as .ini extension).
Python
import win32com.client as COM
xl = COM.Dispatch("Excel.Application")
R
libray(RDOMClient)
xl <- COMCreate("Excel.Application")
PHP
$xl = new COM("Excel.Application", NULL, CP_UTF8) or Die ("Did not instantiate Access");
In the first code try replacing the line If InStr(1, wb.Sheets(i).Name, "T") Then with
If InStr(1, wb.Sheets(i).Name, "T") > 0 Then
In the code you developed try replacing the line If InStr(1, wb.Sheets(i).Name, "T") Then with
If InStr(1, ws.Name, "T") > 0 Then
Remember you are looping with ws not i
Related
I have an error while trying to open two excel files with giving only their names and not the full path (error: file not exist), the files are both in the same folder as the project (Debug).
I am trying to not use a static path so when i change the laptop the project will always work.
This is the code that i am using.
Thanks for your help
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
xlApp = New Excel.Application
xlBook = xlApp.Workbooks.Open(Filename:="c:\EMP_.xlsx", IgnoreReadOnlyRecommended:=True, ReadOnly:=False, Editable:=True)
xlSheet = xlBook.Worksheets(1)
If DataGridView1.DataSource IsNot Nothing Then
Dim i, j As Integer
For i = 1 To DataGridView1.RowCount - 1
For j = 1 To DataGridView1.ColumnCount
xlSheet.Cells(i + 1, j) = DataGridView1.Rows(i - 1).Cells(j - 1).Value
Next
Next
xlApp.Visible = True
xlApp.UserControl = True
xlApp.Quit()
xlApp = Nothing
Else
MsgBox("Le tableau est vide")
End If
Per Jimi's comment, something like this will read an xlsx that is alongside the exe:
Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "emp_.xlsx")
Path.Combine(Application.StartupPath, "emp_.xlsx")
Always use Path.Combine to combine paths, not string concatenation
You asked about moving the app to another PC:
THe new pc does NOT need Vsual Studio installed - visual studio creates a standalone EXE that will run without needing VS
The new PC WILL need to have an appropriate version of the .Net Framework installed. Most Windows 10 PCs will meet this requirement, but users will see a message that tells them to install it if not
The new PC WILL need to have Excel installed. Per my comment, if you dont want this or cannot guarantee it (paying for an office licence just to read an excel file is expensive and unnecessary) you should use the ACE driver or EPPlus to read your excel; neither needs Excel and both are free
Use an OpenFileDialog to show a user interface that you can choose which excel file you want to open. They're easy to use:
Dim ofd as New OpenFileDialog
Dim result = ofd.ShowDialog
If result <> DialogResult.OK Then Return 'if the user cancels
xlApp.Workbooks.Open(Filename:= ofd.Filename ...
I would like to use a macro on several excels automatically every day on my linux (debian 9). so I looked for a little bit, and I found that it is possible using VB.NET.
After added microsoft package I installed dotnet-sdk
sudo apt-get install dotnet-sdk-2.1
then create my project with dotnet new console -lang VB
I modified Program.vb to that:
Imports System
Imports System.Text
Imports System.IO
Imports Microsoft.VisualBasic.ControlChars
Imports Excel = Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop
Module Program
Sub Main(args As String())
ProcessFiles
End Sub
End Module
Sub ProcessFiles()
Dim Filename, Pathname As String
Dim wb As Excel.Workbook
Pathname = ActiveWorkbook.Path & "/path/xlsx/"
Filename = Dir(Pathname & "*.xlsx")
Do While Filename <> ""
wb = Workbooks.Open(Pathname & Filename)
DoWork( wb )
wb.Close( SaveChanges:=True )
Filename = Dir()
Loop
End Sub
Sub DoWork(wb As Excel.Workbook)
With wb
.Worksheets(1).Range("A1").Select
.Selection.End(xlUp).Select
.Rows("1:1").Select
.Selection.AutoFilter
.ActiveSheet.Range("$A$1:$L$999999").AutoFilter( Field:=1 , Criteria1:="<>*2018*" )
.Range("A2:L999999").Select
.Selection.EntireRow.Delete
.Selection.End(xlUp).Select
.ActiveSheet.Range("$A$1:$L$999999").AutoFilter( Field:=1 )
.Rows("1:1").Select
.Selection.AutoFilter
.Range("A2").Select
End With
End Sub
And now, i'm trying run with dotnet run and I have the error : error BC30002: The type 'Excel.Workbook' is not defined.
I've found a lot of answer that give the good import :
Imports Excel = Microsoft.Office.Interop.Excel
but this is not enough. I also found solutions using Visual Studio, but I do not have it and don't want to ...
Thank's for your help
The Excel Interop layer requires (wait for it . . . ) Excel. 8-)
Unless you have found a copy of Microsoft Office for Linux and all the Magic that implements the COM interface, you're out of luck.
Thank's to Terry Carmen for his answer.
We've found another answer without use VB and Excel macro for our needs.
In the case where we would have been forced to use VB and Excels, we could have done it under macOS.
I'm having some problems closing Excel files. I am doing a program that opens some Excel files, uses the information and then close them.
I tried some different codes, but they didn't work because the EXCEL process is still running.
My first code:
Dim aplicacaoexcel As New Excel.Application
Dim livroexcel As Object
Dim folhaexcel As Excel.Worksheet
livroexcel = aplicacaoexcel.Workbooks.Open("C:\Users\LPO1BRG\Desktop\Software Fiabilidade\Tecnicos.xlsx", UpdateLinks:=False, ReadOnly:=False, Password:="qmm7", WriteResPassword:="qmm7")
folhaexcel = livroexcel.sheets("Folha1")
aplicacaoexcel.DisplayAlerts = False
aplicacaoexcel.Visible = False
folhaexcel = Nothing
livroexcel.Close()
livroexcel = Nothing
aplicacaoexcel.Quit()
aplicacaoexcel = Nothing
Then I added this: System.GC.Collect() but it still not closing the Excel process.
Now I am trying this:
Dim process() As Process = system.Diagnostics.Process.GetProcessesByName("EXCEL")
For Each p As Process In process
p.Kill()
Next
Actually, this one is working, but it closes all the Excel files (even those that are not opened by my program).
What can I do to close just the Excel files opened by my program? :)
Releasing the Excel.Application Interop COM object is a little bit trickier than other Office Interop objects, because some objects are created without your knowledge, and they all must be released before the main Application can be actually closed.
These objects include:
The Excel.Application
The Excel.Application.WorkBooks collection
The WorkBooks collection opened WorkBook
The WorkBook Sheets collection
The Sheets collection referenced Worksheet
These objects must all be released in order to terminate the EXCEL process.
A simple solution is to use explicit declarations/assignment for all the COM objects:
Dim ExcelApplication As New Microsoft.Office.Interop.Excel.Application()
Dim ExcelWorkbooks As Workbooks = ExcelApplication.Workbooks
Dim MyWorkbook As Workbook = ExcelWorkbooks.Open("[WorkBookPath]", False)
Dim worksheets As Sheets = MyWorkbook.Worksheets
Dim MyWorksheet As Worksheet = CType(worksheets("Sheet1"), Worksheet)
When you're done, release them all:
Imports System.Runtime.InteropServices
Marshal.ReleaseComObject(MyWorksheet)
Marshal.ReleaseComObject(worksheets)
MyWorkbook.Close(False) '<= False if you don't want to save it!
Marshal.ReleaseComObject(MyWorkbook)
ExcelWorkbooks.Close()
Marshal.ReleaseComObject(ExcelWorkbooks)
ExcelApplication.Quit()
Marshal.FinalReleaseComObject(ExcelApplication)
Marshal.CleanupUnusedObjectsInCurrentContext()
Try something like workbook.Save, workbook.close
I'm a little rusty on my VB and don't have access to Visual Studio right now to test this, but I will try writing the code from memory.
The problem you are running into is that setting an object equal to Nothing still leaves the object allocated in memory and doesn't dispose of the object entirely. Even the Close() and Quit() methods of the object still leave it allocated in memory in case the program needs to access them again later. The Kill() method works because it simply kills the Excel application that is running in memory, which closes any open Excel documents as well as the ones used by COM objects. What you want to do is dispose of the specific COM objects that your application is using.
Try this change in your code though.
Dim aplicacaoexcel As New Excel.Application
Dim livroexcel As Object
Dim folhaexcel As Excel.Worksheet
livroexcel = aplicacaoexcel.Workbooks.Open("C:\Users\LPO1BRG\Desktop\Software Fiabilidade\Tecnicos.xlsx", UpdateLinks:=False, ReadOnly:=False, Password:="qmm7", WriteResPassword:="qmm7")
folhaexcel = livroexcel.sheets("Folha1")
aplicacaoexcel.DisplayAlerts = False
aplicacaoexcel.Visible = False
DisposeComObj(folhaexcel)
DisposeComObj(livroexcel)
DisposeComObj(aplicacaoexcel)
Then add the following to your application as well.
Private Sub DisposeComObj(ByRef Reference As Object)
Try
Do Until _
System.Runtime.InteropServices.Marshal.ReleaseComObject(Reference)<=0
Loop
Catch
Finally
Reference = Nothing
End Try
End Sub
Hopefully my memory is serving me well. I haven't written any code in VB or C# in more than a year and feel very out of practice. I only saw your question because I clicked on the wrong link and remembered how I used to struggle with garbage collection when I started programming.
I need to copy/paste table from Excel to owrd to a specific line. I have written the code and it works fine in the Excel and Word 2016 I used, but when I tried running in other versions (2013,2010,2007) it didn't work at all. So i try to use late binding, but it throws a Bad Parameters error in .selection
How to remove Bad Parameters? Thanks,
Here's the code :
Sub Movetable ()
'Name of the existing Word document
Const stWordDocument As String = "Test.docx"
'Word objects.
Dim wdApp As Object
Dim wdDoc As Object
Dim wdRange As Object
'Excel objects
Dim wbBook As Workbook
Dim wsSheet As Worksheet
Dim xlRange As Excel.Range
'Initialize the Excel objects
Set wbBook = ThisWorkbook
Worksheets("RJ").Select
LastRow = Range("A" & Rows.Count).End(xlUp).Row
Set xlRange = Range("A4:D" & LastRow)
xlRange.Select
xlRange.Copy
'Instantiate Word and open the "Test" document.
Set wdApp = CreateObject("Word.Application")
Set wdDoc = wdApp.Documents.Open(wbBook.Path & "\" & stWordDocument)
wdDoc.Application.Selection.Find.Execute "Table 1. Summary", MatchCase:=True
wdApp.Selection.MoveDown Unit:=wdLine, Count:=2, Extend:=wdMove
wdApp.Selection.PasteExcelTable False, False, False
wdDoc.Tables(1).AutoFitBehavior wdAutoFitWindow
'Save and close the Word doc.
With wdDoc
.Save
.Close
End With
wdApp.Quit
'Null out the variables.
Set wdRange = Nothing
Set wdDoc = Nothing
Set wdApp = Nothing
End Sub
Very probably, the reason is that you've set a Refernce to the Microsoft Word library for version 2016. When you open and run the project in an earlier version, the reference doesn't change to the Microsoft Word library for that version. This is expected behavior.
To fix the problem you can either
Open the project in the earliest version of Office (2007,
apparently). Go to Tools/References in the VBA Editor and select the
Microsoft Word library for that version. Test, then save.
Office applications will change References to a newer version, but they don't do so the other way around. That's why it's always recommended to develop using the oldest version of Office the project should work in.
Don't use named arguments in the method calls. Remove, for example, MatchCase:=, Unit, Count, Extend. In addition, don't use the Word enumerations: wdLine, wdMove, wdAutoFitWindow- these all have numerical equivalents, use those instead.
This is known as "late-binding", which makes your project independent of the version of Word. You can then completely remove the Reference to the Microsoft Word library.
In order to find out the numerical equivalents you can look up the enumerations in the VBA Object Browser (F2 in the VBA Editor), look them up in the Word VBA Help or query them in the VBA Editor Immediate Window (Ctrl + G) using syntax like this: ?wdLine and then press Enter to execute.
I have a project written in Vb .NET in which I take input from the user, open a Excel template and run a macro in it(vba) with input from main form.
I can do all of this without a problem using a path to the template but I need it to be part of the project when I publish it.
This is my path version code(excess code deleted):
Imports Excel = Microsoft.Office.Interop.Excel
private sub OpenExcel()
Dim objApp As Object
Me.Hide()
objApp = CreateObject("Excel.Application")
objApp.WorkBooks.Open("ExampleWorkBook.xlsm")
objApp.visible = True
objApp.Run("MacroName", Var1, Var2)
Me.Close()
End Sub
I have found this post but it doesn't work, maybe because my templates are in a folder(which is located in same location as form1.vb etc).
My templates must be separate from other files so they are easy to find.
If anyone could provide me with a solution/modify code from other post in such a way it works I would be really thankful
I'm using Visual Studio 2017 and Excel 2010
Code from linked post:
Dim filename as String = My.Application.Info.DirectoryPath & System.IO.Path.DirectorySeparatorChar & "WorkbookName.xlsx"
Process.Start(filename)
I have managed to find a solution but then I have run into another problem: I would get an error saying the path is invalid, object is missing. I was sure it was a problem with path but it was related to resource properties(type:content instead of none and copy always so it is in the folder with the application).
Code for opening the excel template:
Imports Excel = Microsoft.Office.Interop.Excel
private sub OpenExcel()
Dim objApp As Object
Me.Hide()
'This path is independent of where the program is installed as it refers to program itself
Dim ResourcePath As String = My.Application.Info.DirectoryPath &
System.IO.Path.DirectorySeparatorChar & "Templates\Rate_Reach_ATT finished.xlsm"
objApp = CreateObject("Excel.Application")
objApp.WorkBooks.Open(ResourcePath)
objApp.visible = True
objApp.Run("MacroName", Var1, Var2)
Me.Close()
End Sub
As for resource itself:
Project>Add existing item>browse>add
Then find the item in solution explorer, open it's properties and change:
Type:Content
Copy to Output Directory: Copy Always
The issue has been fixed so I close this thread