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.
Related
I have a VBA script in Excel which works fine but when saved as script_name.vbs and executed in cmd/powershell as cscript.exe script_name.vbs it throws the error:
dir_path\script_name.vbs(30, 37) Microsoft VBScript compilation error: Expected ')'
Firstly I apologise. This seems like a well-worn question but no answer I could find explains any reasons why my particular VBA script won't work.
I learnt that you cannot Dim As when running vbs on the cmd line so I removed that, and then got the above error. No question I found seems to indicate to me as to why.
Help much appreciated!
Thanks
FYI: The macro is to iterate through all files which have passwords in a folder and
Attempt a number of any possible passwords to open the file
Same again for workbook protection passwords
Unhide all worksheets
Save the file
Move onto the next file
Sub BAUProcessVBA()
Dim wb
Dim ws
Dim myPath
Dim myFile
Dim myExtension
Dim i
'Optimize Macro Speed
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
myPath = "C:\blah\dir\"
'Target File Extension (must include wildcard "*")
myExtension = "*.xls*"
'Target Path with Ending Extention
myFile = Dir(myPath & myExtension)
'Loop through each Excel file in folder
Do While myFile <> ""
'Set variable equal to opened workbook
Debug.Print myFile
On Error Resume Next
Set wb = Workbooks.Open(Filename:=myPath & myFile, Password:="pw1", IgnoreReadOnlyRecommended:=True, ReadOnly:=False)
Set wb = Workbooks.Open(Filename:=myPath & myFile, Password:="pw2", IgnoreReadOnlyRecommended:=True, ReadOnly:=False)
On Error GoTo 0
'Ensure Workbook has opened before moving on to next line of code
DoEvents
'Remove workbook protection and, unhide all tabs, save the file
On Error Resume Next
wb.Unprotect "pw1"
wb.Unprotect "pw2"
On Error GoTo 0
On Error Resume Next
wb.Password = ""
On Error GoTo 0
For Each ws In wb.Worksheets
ws.Visible = xlSheetVisible
Next ws
'Save and Close Workbook
Application.CutCopyMode = False
wb.Close SaveChanges:=True
Application.EnableEvents = False
'Ensure Workbook has closed before moving on to next line of code
DoEvents
'Get next file name
myFile = Dir
Loop
'Reset Macro Optimization Settings
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
You seem under the impression that Visual Basic for Applications vba and Visual Basic Script vbscript are identical languages. That is not the case. They may be more closely related than Visual Basic .Net vb.net and VBA or VBS, but they are still different languages.
Which is why we have different tags for all of them.
Now, to tackle your question:
VBA has got the Microsoft Office Object Library reference, which means native support for office objects.
Application doesn't exist in vbs, so you need to create that object: Set Application = WScript.CreateObject("Excel.Application")
Excel constants don't exist:
xlCalculationManual = -4135, xlCalculationAutomatic = -4105 and xlSheetVisible = -1
Dir doesn't exist, so you need to create a FileSystemObject
Named arguments don't exist, so you need commas:
Set wb = app.Workbooks.Open(myPath & myFile, , False, , "pw1", , True)
And DoEvents doesn't exist either.
To solve this problem I have used Python to open Excel and execute the Macro I want. Below is a function that should work for anyone.
Things I have learnt: If you have VBA code in Excel and want to run it without Excel then you cannot just save this as a .vbs and execute it on the command line with cscript.exe.
VBS and VBA are different languages.
Therefore, a quick tutorial for those stuck at the same problem but are unfamiliar with Python:
Download and install Python ensuring python is added to PATH. This script was written and successfully executed with Python 3.8 64-bit for Windows. https://www.python.org/downloads/
Save the below in a file called run_macro.py
On the last line of run_macro.py, with no indentation, type what is below within Code2
Carrying on with Code2: Inside of the quotes 'like this' type in what it's asking for. The filepath_incl_filename must contain the full path AND the filename whereas filename must contain ONLY the filename. Yes, it must be provided like this.
Copy the filepath where run_macro.py is located and press win+r and type 'cmd' to open the cmd terminal, then type cd <filepath from clipboard> and press enter
Now type python run_macro.py
So long as you get no errors and it appears to "freeze" then that means it's working. Otherwise, you will need to debug the errors.
Code:
import win32com.client as wincl
def run_excel_macro(filepath_incl_filename=r'raw_filepath', filename='', module_name='', macro_name=''):
"""
:param filepath_incl_filename: Must be r'' filepath to dir with filename but also include the filename in the filepath (c:\etc\folder\wb_with_macro.xlsm)
:param filename: Filename of xlsm with the Macro (wb_with_macro.xlsm)
:param module_name: Found inside 'Modules' of macros within that workbook
:param macro_name: The 'sub name_here()' means macro is called 'name_here'
:return: Nothing. Executes the Macro.
"""
# script taken from: https://stackoverflow.com/questions/19616205/running-an-excel-macro-via-python
# DispatchEx is required in the newest versions of Python.
excel_macro = wincl.DispatchEx("Excel.application")
workbook = excel_macro.Workbooks.Open(Filename=filepath_incl_filename, ReadOnly=1)
excel_macro.Application.Run(f"{filename}!{module_name}.{macro_name}")
# Save the results in case you have generated data
workbook.Save()
excel_macro.Application.Quit()
del excel_macro
Code2
run_excel_macro(
filepath_incl_filename=r'',
filename='',
module_name='',
macro_name=''
)
We will put 100s of Excel worksheets out in the field this year. The code periodically needs to be updated when bugs are found. For last year's effort, I was able to dynamically have workbooks pull updates for .bas files. This year I want to dynamically have workbooks pull updates for the code embedded in the worksheets too.
EXPORT CODE
The export code is pretty simple, but there are artifacts in the .txt files
Sub SaveSoftwareFile(path$, name$, ext$)
ThisWorkbook.VBProject.VBComponents(name).Export path & name & ext
Example Call: SaveSoftwareFile path, "ThisWorkbook", ".txt"
The problem is that the export has a lot of header information that I don't care about (in red). I just want the part in blue. Is there switch that allows me not to save it, or do I have to manually go into the export and remove it myself?
IMPORT CODE
The import code is pretty straight forward too, but it causes the error "Can't enter break mode at this time", and I'm struggling to figure out the right path forward. If I manually try and delete this code, Excel is also unhappy. So maybe my approach is altogether incorrect. Here's the code:
Sub UpgradeSoftwareFile(path$, name$, ext$)
Dim ErrorCode%, dest As Object
On Error GoTo errhandler
Select Case ThisWorkbook.VBProject.VBComponents(name).Type
Case 1, 3 'BAS, FRM
<Not relevant for this discussion>
Case 100 'Worksheets
Set dest = ThisWorkbook.VBProject.VBComponents(name).codemodule
dest.DeleteLines 1, dest.CountOfLines 'Erase existing | Generates breakpoint error
dest.AddFromFile path & name & ext '| Also generates breakpoint error
End Select
Example Call: UpgradeSoftwareFile path, "ThisWorkbook", ".txt"
Thanks in advance for your help
Please, try the next way of exporting and you will not have the problem any more:
Sub SaveSoftwareFile(path$, sheetCodeModuleName$, FileName$)
Dim WsModuleCode As String, sCM As VBIDE.CodeModule, strPath As String, FileNum As Long
Set sCM = ThisWorkbook.VBProject.VBComponents(sheetCodeModuleName).CodeModule
WsModuleCode = sCM.Lines(1, sCM.CountOfLines)
'Debug.Print WsModuleCode
strPath = ThisWorkbook.path & "\" & FileName
FileNum = FreeFile
Open strPath For Output As #FileNum
Print #FileNum, WsModuleCode
Close #FileNum
End Sub
You can use the above Sub as following:
Sub testSaveSheetCodeModule()
Dim strPath As String, strFileName As String, strCodeModuleName As String
strPath = ThisWorkbook.path
strFileName = "SheetCode_x.txt"
strCodeModuleName = Worksheets("Test2").codename 'use here your sheet name
SaveSoftwareFile strPath, strCodeModuleName, strFileName
End Sub
Now, the created text file contains only the code itself, without the attributes saved by exporting the code...
Import part:
"Can't enter break mode at this time" does not mean that it is an error in the code. There are some operations (allowed only if a reference to Microsoft Visual Basic for Applications Extensibility ... exists) in code module manipulation, which cannot simple be run step by step. VBA needs to keep references to its VBComponents and it looks, it is not possible when changes in this area and in this way are made.
The import code is simple and it must run without problems. You must simple run the code and test its output...
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
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
I have a sub which I call to save a file
Sub SaveToFile()
maxr = Worksheets("List").Range("H1")
Worksheets("List").Range("G1:AE" & maxr).Copy
Part of the code which is failing after an upgrade to 2007 is:
With Application.FileSearch
.LookIn = "Q:\Planning Tools\Reports\"
.Filename = "Plan_" & ThisSaveTime & ".xls"
I receive a runtime error '445' object doesn't support this action, the code then continues below:
If .Execute > 0 Then 'Existing Workbook
Application.Workbooks.Open ("Q:\Planning Tools\Reports\Plan_" & ThisSaveTime & ".xls")
ActiveWorkbook.Worksheets.Add
ActiveWorkbook.Sheets("Sheet1").Select
ActiveWorkbook.Sheets("Sheet1").Name = ThisPlanSaveName
Else 'No existing Workbook, so add one
Workbooks.Add 1
ActiveWorkbook.Sheets("Sheet1").Select
ActiveWorkbook.Sheets("Sheet1").Name = ThisPlanSaveName
End If
End With
......
End Sub
I am not sure which action is failing but can anyone see why?
Thanks
Microsoft has removed FileSearch from the Excel 2007 Object Model
There are many possible replacements like Dir and using the FileSystemObject
try these links:
Mr Excel: Replacement class for FileSearch
MSDN Communities: Application.FileSearch in Excel 2007
Ozgrid Forums - Rplacement for FileSearch
Ozgrid Forums - Application.FileSearch Replacement in Excel 2007
Execl-IT.com: Replacement for FileSearch