Textstream object remains open in Excel after being closed by VBA - vba

I have some VBA code in Excel 2007 which creates, fills, then closes a Textstream file object (abbreviated snippet below).
Set CSV = FSO.CreateTextFile(strPathOut & Application.PathSeparator & strFileOut)
'Fill the file
CSV.Close
The code works perfectly, including the CSV.Close instruction, however if I then try to delete or modify the file (e.g. in Windows Explorer or Notepad) the system claims Excel still has the file open. Seemingly the only way to release it is to close Excel itself.
I've checked that CSV.Close is doing what it's supposed to from the VBA side; it's not causing a runtime error, and certainly the file is no longer available to be written to after that instruction.
My project is early bound to the Microsoft Scripting Runtime, scrrun.dll. I've tried removing that reference but I get the same result.
This is not a showstopper for the project, but it's a PITA during development. Anybody know what's going on?

Try this simple example - the file is available for editing through e.g. Notepad, after the code has run:
Option Explicit
Sub Test()
Dim objFSO As New FileSystemObject
Dim objStream As TextStream
Dim i As Integer
Set objStream = objFSO.CreateTextFile("D:\temp.txt")
With objStream
For i = 1 To 10
.WriteLine CStr(i)
Next i
.Close
End With
Set objStream = Nothing
Set objFSO = Nothing
End Sub

Related

Write txt first line instead of last

It is easy to find in the internet a way of write into a txt file but all I find is always writing in the very last line:
Sub write_log(sentence_to_be_written As String)
Dim strFile_Path As String
strFile_Path = "C:\Users\[user_name]\Desktop\log.txt"
Open strFile_Path For Append As #1
Print #1, Now() & " --> " & sentence_to_be_written
Close #1
End Sub
I would like to write instead into the first line of the txt file.
Try the next code, please. It needs a reference to Microsoft Scripting Runtime. It can be adapted to work without such a reference. In fact, I will also post a pice of code able to automatically add the necessary reference... It is possible to read the text using standard VBA Open, but only concatenating line by line and I think this solution is more elegant:
Sub write_log_OnTop(sentence_to_be_written As String)
'It neds a reference to 'Microsoft Script Runtime'
Dim strFile_Path As String, strText As String
Dim fso As New FileSystemObject, txtStr As TextStream
strFile_Path = "C:\Users\Fane Branesti\OneDrive\Desktop\log.txt"
If Dir(strFile_Path) <> "" Then 'check if file exists
Set txtStr = fso.OpenTextFile(strFile_Path)
strText = txtStr.ReadAll
txtStr.Close
Else
MsgBox "Wrong file path...": Exit Sub
End If
strText = Now() & " --> " & sentence_to_be_written & vbCrLf & strText
Open strFile_Path For Output As #1
Print #1, strText
Close #1
End Sub
And Microsoft Scripting Runtime reference can be automatically add by running of the next code:
Private Sub Add_Scripting_Reference() 'Adds 'Microsoft Scripting Runtime'
Dim wb As Workbook, r As Reference
Set wb = ThisWorkbook
For Each r In wb.VBProject.References
If r.name = "Scripting" Then Exit Sub
Next
wb.VBProject.References.AddFromFile Environ("windir") & "\system32\scrrun.dll"
End Sub
If you do not want the reference, even if I would not understand such a choice, it is enough to comment/replace the code line
Dim fso As New FileSystemObject, txtStr As TextStream
with:
Dim fso As Object, txtStr As Object: Set fso = CreateObject("Scripting.FileSystemObject")
There is no command to add text at the top (or the middle) of any file. I never heard about such command in any programming language. It's about (disk-)space management, if you add a line of text in front of any other text, the existing text needs to be moved, and this is a rather complicated operation.
If you deal with short files, you could solve that by reading the content of the file into memory and then recreate the file by first writing the new line(s) and the add the content - as Joerg Wood suggested in the comments. However, this would need lot of memory and/or disk IO if the file gets larger, and the process has to be repeated every time you want to add a line - maybe not an issue if you write only one line per hour, but quite an issue if you are writing multiple lines per second.
It seems you are writing a log file and probably you want to see what was going on lately. You could use a windows version of the tail command (that comes from Unix) or use the powershell command Get-Content "C:\Users\[user_name]\Desktop\log.txt" -Tail 10 (see https://stackoverflow.com/a/188126/7599798) for that - it will display the last lines of a file.
An alternative could be to write the log into an Excel sheet or a database - in both cases it is easy to fetch the data in any order.

copyfile ini to txt: permission-denied

I just want to copy the Content of a ini-File into a txt-file. But it tells me, that permission is denied.
The source file is closed
the Ini-file "Aly_complete.ini" was previously executed in the code via "java -jar"
As you see, I already tried another file, which wasn't used by the code before
Here is the code
Sub Kopieren_Ini(strPathQuelle As String, strPathErg As String)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim oFile As Object
Dim Quelle As String
Dim Ziel As String
If Sheets(1).TxtBoxIni.Text <> "" Then
Quelle = Sheets(1).TxtBoxIni.Text
Else
Quelle = strPathQuelle & "Aly_MitDatum.ini"
'Quelle = strPathQuelle & "Aly_complete.ini"
End If
Set oFile = fso.CreateTextFile(strPathErg & "\" & "Config_Test.txt")
Ziel = strPathErg & "\" & "Config_Test.txt"
FileSystem.FileCopy Quelle, Ziel
Thanks in advance for your help
Sounds like the .ini is being used by another application or process. What else is running? Does this still occur after you reboot? ( Source: my comment ☺)
Your code is incomplete (it doesn't End) so I can't say for sure, but I bet your issue is same common mistake that [imho] is the culprit in almost every complaint of Excel crashes caused by VBA code...
It's just like parenta are always telling their children:
The file is Open (and locked and taking up memory) until you .Close it.
Objects that are opened need to be closed & cleared.
Try adding these 3 lines to the end of your code (or where ever you're finished using the objects):
oFile.Close
Set oFile = Nothing
Set fso = Nothing
...then save your work, reboot, and try it again.
More Information:
Stack Overflow : Is there a need to set Objects to Nothing inside VBA Functions?
MSDN : FileSystemObject Object
MSDN : CreateTextFile Method
MSDN : Close Method (FileSystemObject)
EDIT: "Copy & Rename"
If you simply need to copy a file (and rename the copy at the same time), use this:
Option Explicit
Sub copyFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
fso.copyFile "c:\sourcePath\sourceFile.ini", "c:\destinationPath\destFile.txt"
Set fso = Nothing
End Sub
More More Information:
Rob de Bruin : Copying & Moving Files with VBA
Excel Trick : FileSystemObject in VBA – Explained
MSDN : CopyFile Method

Save Excel Sheet text only to text file VBA

I am trying to copy the values of one column in a sheet to a text file. The code I currently have causes runtime error 434.
Sheets("Output to fcf.1").Columns("A").SaveToText "P:\4_Calcs\02. Flag Mapping\test_.txt"
If I try and save the whole sheet
Sheets("Output to fcf.2").SaveToText "P:\Clear Project Drive\CLE10276 AWS SMP Model Assessmnts\4_Calcs\02. Flag Mapping\test2_.txt"
I get the entire sheet converted into text rather than just the text in the sheet. Is there a simple way to do this?
Thanks in advance!
Not sure which Excel version you have but I don't see a method for SaveToText.
But this procedure should work, or at least get you started...
Sub SaveColumn(sheetName As String, columnName As String, fileName As String)
Dim cell
Dim fso
Dim file
Set fso = CreateObject("Scripting.FileSystemObject")
Set file = fso.CreateTextFile(fileName, True)
For Each cell In Sheets(sheetName).Columns(columnName).Cells
If cell.Value <> "" Then
file.WriteLine cell.Value
End If
Next
file.Close
Set file = Nothing
Set fso = Nothing
End Sub
To call it...
SaveColumn "Output to fcf.1", "A", "P:\4_Calcs\02. Flag Mapping\test_.txt"
This is designed to be used as a macro.
Step by step guide:
1) From excel, hit Alt+F11 on your keyboard.
2) From the menu bar, click Insert, then Module
3) Copy and paste the code provided below into the new module that opens.
NOTE: DocPath = "C:\docs\data.txt" should be wherever you want the output file saved, including the file's actual name. Remember, the folder you want the output file to be located in should ALREADY exist. This does not create the folder if it can't be found.
4) From the menu bar, click Tools, then References. Make sure both "Microsoft Office 14.0 Object Library" as well as "Microsoft Word 14.0 Object Library" are checked, and hit okay (See screenshot for details)
5) Save the document as an .xlsm file (This file type supports Macros)
6) Close the VBA editor. Back in Excel, on the ribbon click View and then Macros. Your new macro should be in the list as ExportToTXT
7) Select it and hit run.
Sub ExportToTXT()
Dim DocPath As String
Dim MsgBoxCompleted
Columns("A").Select
Dim AppWord As Word.Application
Set AppWord = CreateObject("Word.Application")
AppWord.Visible = False
Selection.Copy
DocPath = "C:\docs\data.txt"
'Create and save txt file
AppWord.Documents.Add
AppWord.Selection.Paste
AppWord.ActiveDocument.SaveAs2 Filename:=DocPath, FileFormat:=wdFormatText
Application.CutCopyMode = False
AppWord.Quit (wdDoNotSaveChanges)
Set AppWord = Nothing
MsgBoxCompleted = MsgBox("Process complete.", vbOKOnly, "Process complete")
End Sub
Good luck, and if you have any questions, don't hesitate to ask.
NOTE: These directions might seem overly simplified for your skill level, but I wrote the answer like this to potentially help others in the future.
EDIT
Change
DocPath = "C:\docs\data.txt"
to
DocPath = "C:\docs\data.fcf"
And change
AppWord.ActiveDocument.SaveAs2 Filename:=DocPath, FileFormat:=wdFormatText
to
AppWord.ActiveDocument.SaveAs2 Filename:=DocPath
The output file will be .fcf format. Whether or not it will open properly is something I'm not sure of. You'd have to test in the program you're using.

Is it possible to associate an Excel Macro with a file extension?

I have built a macro for building and running SQL Queries. I am pretty happy with it so far. The only thing I would like to add is the ability in Windows to double click a .sql file and it opens inside the macro. Sample is below:
This is the code that opens an SQL file when Load Query is pressed.
Sub LoadQuery()
Dim fNameAndPath As Variant
fNameAndPath = Application.GetOpenFilename(FileFilter:="SQL Query Files (*.sql), *.sql", Title:="Select File To Be Opened")
If fNameAndPath = False Then Exit Sub
Open fNameAndPath For Input As #1
Sheets("Sheet1").SQL_Query = Input$(LOF(1), 1)
Close #1
Sheets("Sheet1").SQLFileName.Caption = fNameAndPath
End Sub
Is this even possible? I don't think it will be but thought I would check with you guys first.
What have I tried so far? Nothing, because I don't even know where to start, Uncle Google didn't hook a brother up in fact he just confused me even more.
Using the ideas below I went with this:
Option Explicit
Dim xlApp, xlBook, fNameAndPath
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("G:\Analytics Reporting Archive\SQL Client.xlsm", 0, True)
xlApp.Open WScript.Arguments(0) For Input As #1
xlBook.Sheets("Sheet1").SQL_Query = Input$(LOF(1), 1)
xlApp.Close #1
xlBook.Sheets("Sheet1").SQLFileName.Caption = fNameAndPath
Set xlBook = Nothing
Set xlApp = Nothing
WScript.Quit
This didn't work, it didn't like opening the text file (sql file) so I went with creating a small routine in the Excel app:
Sub LoadQueryDBLClick(QueryFileName As String)
Open QueryFileName For Input As #1
Sheets("Sheet1").SQL_Query = Input$(LOF(1), 1)
Close #1
Sheets("Sheet1").SQLFileName.Caption = fNameAndPath
End Sub
This is then called in the VBS like so:
Option Explicit
Dim xlApp, xlBook, fNameAndPath
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("G:\Analytics Reporting Archive\SQL Client.xlsm", 0, True)
xlApp.Run "LoadQueryDBLClick " & WScript.Arguments(0)
Set xlBook = Nothing
Set xlApp = Nothing
WScript.Quit
Brilliant right?
NO :(. It "would" work, of that I am confident (and extremely grateful to you guys that posted replies for me that got me this far) but alas Citrix strikes again:
Error: ActiveX component can't create object: 'Excel.Application'
I am confident that you guys have solved this in that Citrix is now the issue.
See here for how to create a custom extension and associate it with an action.
https://superuser.com/questions/406985/programatically-associate-file-extensions-with-application-on-windows
What might work in your case is to associate the extension with a vbs file which takes the launching SQL filepath as a parameter and opens your Excel file using automation, then loads the SQL file into the workbook.
You'll want to right-click on an SQL file and select Open With. Choose, or browse to Excel.exe. Set it as the default application to open SQL files with.
This will open your SQL files in Excel.
From here you'll need to teach your macro to detect when it was launched by an SQL file and run as desired.

Open an excel workbook after code executes

I know this has been asked before, but for the life of me I cannot get this simple code to work. I keep getting the compile error "User-defined type not defined" on Dim wbopen As Workbook
line. I know the workbook has to be open to define it, and the file path should be Z:\Manufacturing\02- Schedules\01- Buffer Prep
while the file name is the only .xls in the folder. Why is this happening? Also, this is executing in a Word file. Not sure if that matters. Thanks everyone!
Sub fileopen()
Dim wbopen As Workbook
Dim strFileName As String
Dim strFilePath As String
strFilePath = "Z:\Manufacturing\02- Schedules\01- Buffer Prep\"
strFileName = Dir(strFilePath & "*.xls")
Set wbopen = Workbook.Open(strFileName)
End Sub
It does matter that it is a Word Document. You have to add a reference to Microsoft Excel Object Library. From the top bar:
Tools -> References -> find Microsoft Excel [version number] Object Library and check it.