Imports System
Imports System.IO
Imports Microsoft.VisualBasic.FileIO
Imports Microsoft.Office.Interop
Module Program
Dim oxl As Excel.Application
Dim owbs As Excel.Workbooks
Dim owb As Excel.Workbook
Dim osheets As Excel.Worksheets
Dim osheet As Excel.Worksheet
Dim owr As Excel.Range
Dim tempName As String
Sub Main()
oxl = CreateObject("Excel.Application")
oxl.Visible = False
Dim path As String = "G:\Matthews Asia\Matthews Raw Data"
Dim names As String() = Directory.GetFiles(path, "*.xlsx")
Dim newDetails(,) As Object
'Get the new names and the boundaries of the data set
newDetails = getNewNames(names)
'Printing the detials to check getNewNames works or not - works fine
printNewDetails(newDetails) 'Working fine
'Rename files
rename(names, newDetails)
Console.ReadLine()
End Sub
Function getNewNames(ByVal names() As String) As Object(,)
'Declare Object type array to be returned with the details
Dim newDetails(names.Length - 1, 2) As Object
Dim lastRow, lastColumn As Integer
For i =0 To names.GetUpperBound(0)
'point to the excel file
owb = CType(oxl.Workbooks.Open(names(i)), Excel.Workbook) 'Sometimes error comes here
osheet = CType(owb.Worksheets("Holdings"), Excel.Worksheet)
owr = CType(osheet.Range("A7"), Excel.Range)
'Pick new name of file and add the excel extension
tempName = CStr(owr.Value) & ".xlsx"
'row & column number of last data point in the dataset
lastColumn = CType(osheet.Range("A13").End(Excel.XlDirection.xlToRight), Excel.Range).Column
lastRow = CType(osheet.Range("A13").End(Excel.XlDirection.xlDown), Excel.Range).Row
newDetails(i, 0) = tempName
newDetails(i, 1) = lastRow
newDetails(i, 2) = lastColumn
Next
owb.Close()
Return newDetails
End Function
Function printNewDetails(ByVal details As Object(,)) As Integer
For i = 0 To details.GetUpperBound(0)
Console.WriteLine("New name: {0}", details(i, 0))
Console.WriteLine("Last row: {0}", details(i, 1))
Console.WriteLine("Last Column: {0}", details(i, 2))
Next
Return 1
End Function
Sub rename(ByVal oldName As String(), ByVal tempArray As Object(,))
For i = 0 To oldName.GetUpperBound(0)
FileSystem.RenameFile(oldName(i), CStr(tempArray(i, 0))) 'Error Here
Next
End Sub
End Module
i am trying to rename some excel files all of which is in a particular directory. The code does the following:
It opens each file which has just one sheet
Then it picks the string in cell A7 in each of those files
It also finds out the last row and last column of the data set (cell A13 is the starting point of the dataset in each of the files)
Finally, in an object array newDetails we store the string in cell A7 in the first column, the last row of the dataset (column 2) and last column of the dataset (column 3). Each row has data corresponding to one excel file
After that, the code renames the files using the rename subroutine -- the idea is to swap the old names which is stored in the names array with the string value in the first column of the newDetails array.
But When I run the code, the following error message comes: The process cannot access the file because it is being used by another process. I have opened task manager, manually closed all excel processes and even restarted the computer - even then this error comes. Have attached the screenshot of the error. Requesting help.
Strangely, when I run the code more than once, sometimes I am getting the error in the line owb = CType(oxl.Workbooks.Open(names(i)), Excel.Workbook) and that error warns me to check if the files are corrupted or not. The files are not corrupted because when I manually open them there is no problem.
When a filename starts with ~$, it usually indicates that the file is already open (in Excel). However, sometimes this file doesn't get deleted. If you're sure that Excel is no longer running, such as after a reboot, and such a file exists, one can delete it. Of course, one could also just ignore it when getting a list of files.
You haven't mentioned if you're using .NET or .NET Framework and which version. VS 2019 supports .NETCore 3.1, .NET 5 (no longer supported), and .NET Framework versions.
One may consider using NuGet package DocumentFormat.OpenXml or ClosedXml instead. However, if one desires to use Excel Interop, try the following:
Add a reference: Microsoft Excel xx.x Object Library (ex: Microsoft Excel 16.0 Object Library)
Project
Add Project Reference...
COM
Microsoft Excel xx.x Object Library (ex: Microsoft Excel 16.0 Object Library)
OK
Create a class (name: XLInfo.vb)
Public Class XLInfo
Public Property OriginalFilename As String
Public Property LastRow As Integer
Public Property LastColumn As Integer
Public Property RenamedTo As String
End Class
Create a module (name: HelperExcel.vb)
Imports Microsoft.Office.Interop
Imports System.IO
Module HelperExcel
Private Function GetExcelFilenames(folderPath As String) As List(Of String)
Dim filenames As List(Of String) = New List(Of String)
For Each fqFilename As String In Directory.GetFiles(folderPath, "*.xlsx")
'get only the filename
Dim fn As String = Path.GetFileName(fqFilename)
If Not fn.StartsWith("~") Then
Debug.WriteLine($"Info: adding '{fqFilename}'...")
filenames.Add(fqFilename) 'add
End If
Next
Return filenames
End Function
Public Function ProcessExcelFiles(folderPath As String) As List(Of XLInfo)
#Disable Warning CA1416
Dim infos As List(Of XLInfo) = New List(Of XLInfo)
Dim oxl As Excel.Application = Nothing
Dim owbs As Excel.Workbooks = Nothing
Dim owb As Excel.Workbook = Nothing
Dim osheets As Excel.Worksheets = Nothing
Dim osheet As Excel.Worksheet = Nothing
Dim owr As Excel.Range = Nothing
'get filenames
Dim names As List(Of String) = GetExcelFilenames(folderPath)
Try
'create new instance
oxl = New Excel.Application()
oxl.Visible = False
For i As Integer = 0 To names.Count - 1
'create new instance
Dim info As XLInfo = New XLInfo()
'create reference
Dim fn As String = names(i)
'set value
info.OriginalFilename = fn
'open workbook
'owb = oxl.Workbooks.Open(Filename:=fn, [ReadOnly]:=True)
owb = oxl.Workbooks.Open(Filename:=fn)
'open worksheet
osheet = owb.Worksheets(1)
'set value - this is the new filename
info.RenamedTo = Path.Combine(Path.GetDirectoryName(fn), $"{osheet.Range("A7").Value.ToString()}.xlsx")
'ToDo: get last column
'set value - last column
'info.LastColumn = DirectCast(osheet.Range("A13").End(Excel.XlDirection.xlToRight), Excel.Range).Column
'ToDo: get last row
'set value - last row
'info.LastRow = DirectCast(osheet.Range("A13").End(Excel.XlDirection.xlDown), Excel.Range).Row
'add
infos.Add(info)
If osheet IsNot Nothing Then
'release all resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(osheet)
'set value
osheet = Nothing
End If
If owb IsNot Nothing Then
'save
owb.SaveCopyAs(info.RenamedTo)
'owb.SaveAs2(Filename:=info.RenamedTo)
'close
owb.Close(False)
'release all resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(owb)
'set value
owb = Nothing
End If
Next
Finally
If osheet IsNot Nothing Then
'release all resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(osheet)
'set value
osheet = Nothing
End If
If owb IsNot Nothing Then
'close
owb.Close(False)
'release all resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(owb)
'set value
owb = Nothing
End If
If oxl IsNot Nothing Then
'quit
oxl.Quit()
'release all resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oxl)
'force garbage collection
GC.Collect()
End If
End Try
#Enable Warning CA1416
'sleep
System.Threading.Thread.Sleep(250)
'delete original filenames
If Not Directory.Exists(Path.Combine(folderPath, "Original Files")) Then
'create folder if it doesn't exist
Directory.CreateDirectory(Path.Combine(folderPath, "Original Files"))
End If
For i As Integer = 0 To names.Count - 1
If File.Exists(names(i)) Then
'move file to .\Original Files\<filename>
File.Move(names(i), Path.Combine(folderPath, "Original Files", Path.GetFileName(names(i))), True)
Debug.WriteLine($"File moved to '{Path.Combine(folderPath, "Original Files", Path.GetFileName(names(i)))}'")
'ToDo: if one desires to delete the original filenames,
'uncomment the line below
'delete file
'File.Delete(names(i))
End If
Next
Return infos
End Function
End Module
Note: The code above was tested with VS 2022 (.NET 6) since .NET 5 is no longer supported. See here for more info. If using .NET Framework, one can remove #Disable Warning CA1416 and #Enable Warning CA1416.
Usage:
Sub Main(args As String())
'ToDo: replace folder name with desired folder name
Dim infos As List(Of XLInfo) = ProcessExcelFiles("C:\Temp")
For Each info As XLInfo In infos
Dim msg As String = $"OriginalFilename: '{info.OriginalFilename}' RenamedTo: '{info.RenamedTo}' LastRow: '{info.LastRow}' LastColumn: '{info.LastColumn}'"
Debug.WriteLine(msg)
Console.WriteLine(msg)
Next
End Sub
Resources:
Excel Interop
What is .NET Framework
Microsoft .NET Framework
Microsoft .NET and .NET Core
System.IO.File
System.IO.Path
Interpolated Strings (Visual Basic Reference)
Collections (Visual Basic)
Objects and classes in Visual Basic
Option Strict Statement
Additional Resources
Programmatically getting the last filled excel row using C#
I'm having trouble with very simple piece of code.
What I'm trying to achieve is to edit lines lenght in Sketch in SolidWorks.
I saw that working in tutorial, but it doesn't work for me.
I'm getting error
Object variable or With block variable not set
I can't really see what's the problem, since everything seems properly defined to me.
Screenshot from solid
Code:
Sub main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
swModel.AddConfiguration3 "test", Empty, Empty, 0
Dim swDim As SldWorks.Dimension
Set swDim = swModel.Parameter("D1.#Szkic1")
**swDim.SetSystemValue3 0.005, swThisConfiguration, Empty (THIS LINE GETS HIGHLIGHTED)**
swModel.ForceRebuild3 True
End Sub
It might be : "D1#Szkic1" instead of "D1.#Szkic1"
To be sure, you can add the following line after "Set swDim":
If swDim Is Nothing Then MsgBox "Error Selecting Dimension"
I have this task where i need to find some type of hybridshapes and collect them in a listbox
i have done that part, but i need to create it in such a way that when user selects a item from the list box respective hybridshape or object should get selected in catia
here is the image
here is the code
Option Explicit
Dim ODoc As Document
Dim opartdoc As PartDocument
Dim oPart As Part
Dim ohybs As HybridBodies
Dim ohyb As HybridBody
Dim ohybshps As HybridShapes
Dim ohybshp As HybridShape
Dim i As Integer
Dim j As Integer
Private Sub UserForm_Initialize()
Set ODoc = CATIA.ActiveDocument
Set opartdoc = CATIA.ActiveDocument
Set oPart = opartdoc.Part
End Sub
Private Sub ListBtn_Click()
Set ohybs = oPart.HybridBodies
Set ohyb = ohybs.Item("Shapes")
Set ohybshps = ohyb.HybridShapes
For i = 1 To ohybshps.Count
Set ohybshp = ohybshps.Item(i)
ShapeBox.AddItem ohybshp.Name
ShapeBox.Font.Bold = True
ShapeBox.Font.Size = 25
Next
End Sub
Private Sub SelectBtn_Click()
End Sub
i dont know much about listbox handling
how do i create link between items in listbox and objects in catia
thanks
Hi you could add this to your code and try it. Beware your solution is pretty fragile one. You should consider more robust checks for objects validation
The trick lies in ShapeBox.Value in Shapebox click event. The rest is just catia stuff. But this solution is not foolproof because if you have more shapes with same names it might not select the right one. I would prefer creating a collection where you store real object from sets and the passing these objects to selection
Private Sub ShapeBox_Click()
Call opartdoc.Selection.Clear
Call opartdoc.Selection.Add(opartdoc.Part.FindObjectByName(ShapeBox.Value))
End Sub
I'm currently working on developing a macro that will input various forms into an access database.
Due to the nature of the beast of this program, I've had to split my main program into two sub programs and call them, but I need to use getobject to call a file path twice now.
I use getobject to open a file, and then use myrec.fields(~column name~) = xlsht.cells(1, "a") to populate various column values. I'm unsure if there are other "efficient" ways to accomplish this.
I was wondering if it is possible to use a variable in place of the filepath with the GetObject command, instead of needing to manually replace the file path in the code.
I've tested a fair amount of different code, including the path, class functionality but I don't think I understand VBA enough to truly make the best use of that.
I can make it work using this
Dim XL As Variant
Dim XLApp As Variant
Dim XLsht As Variant
Dim XLwrkbk As Variant
Set XL = CreateObject("Excel.Application")
Set XLwrkbk = GetObject(~file path~)
Set XLsht = XLwrkbk.Worksheets(1)
Set MyRec = CurrentDb.OpenRecordset("database name")
Ideally I would like it to be
Dim filename As String
Dim XL As Variant
Dim XLApp As Variant
Dim XLsht As Variant
Dim XLwrkbk As Variant
filename = " ~insert file path~ "
Set XL = CreateObject("Excel.Application")
Set XLwrkbk = GetObject(filename)
Set XLsht = XLwrkbk.Worksheets(1)
Set MyRec = CurrentDb.OpenRecordset("database name")
I receive a run time error
Run-time error '5':
Invalid procedure call or argument.
Try something like this:
Dim XL As New Excel.Application, Filename As String
Filename = "~ your file ~"
XL.Workbooks.Open (Filename)
myrec.fields(~column name~) = XL.Worksheets(1).Range("A1").value
I need to run a PowerPoint sub from R via:
shell(shQuote(normalizePath("C:/.../VBA_Script.vbs"))).
The script VBA_Script should trigger a sub called request_bank, which should open amsgboxwith the value of the variablebank(=J. P. Morgan`).
I get the error:
Application.Run: Invalid request. Sub or function not defined, Code: 80048240, MS PowerPoint 2013.
I just tried all the different Run.-Paths mentioned in this thread Run PowerPoint Sub from Excel. I still get the error. I wonder why the same code is working if I run the same Sub in Excel or if I add the rows:
Dim PSlide
Set PSlide = PPres.Slides(1).Duplicate
But that's no clean solution for me. There must be a better way.
VBS-Script:
Option Explicit
CallPMacro
Sub CallPMacro()
Dim PApp
Dim PPres
'Dim PSlide
Set PApp = CreateObject("PowerPoint.Application")
Set PPres = PApp.Presentations.Open("C:\...\test.pptm", 0, True)
'Set PSlide = PPres.Slides(1).Duplicate
PApp.Visible = True
PApp.Run "request_bank"
PApp.Quit
Set PPres = Nothing
Set PApp = Nothing
End Sub
VBA-Code from the Sub request_bank in the test.pptm:
Sub request_bank()
Dim bank As String
bank = "J.P. Morgan"
MsgBox ("bank: " & bank)
End Sub
Any idea how to fix it?