I am trying to create a VBA to download a google sheet into excel so I can compile stock market data daily. I would simply use power query for this but I am doing this on my personal laptop which is a mac and does not support power query. I am relatively new to coding so have been leaning on following online instructions. The instruction includes this:
Set objWebCon = CreateObject("MSXML2.XMLHTTP.3.0")
This line when ran creates an error message saying:
"
Run-time error '429':
ActiveX component can't create object
"
I think the issue lies within the fact that the instruction is based on a windows operating system. Any solution I've searched for is specific to windows operating systems.
Does anybody here know if I can change the "MSXML2.XMLHTTP.3.0" part of my code to fit it better to mac? Not sure if this is what needs to be done but any guidance would be super appreciated.
I attached my full code below but feel free to ignore it if not relavent. Thank you!!
Sub DownloadGoogleSheets()
Dim ShtUrl As String, Location As String, FileName As String
Dim objWebCon, objWrit As Object
'Sheet Url
ShtUrl = "https://docs.google.com/spreadsheets/d/1wpA_epxtlz96sxETqKttJwsy9Aubb15H8xslcSQ20T0/export?format=csv&id=1wpA_epxtlz96sxETqKttJwsy9Aubb15H8xslcSQ20T0" & gid = 1319327791
'Location
Location = ThisWorkbook.Path & "\" '/Users/[myName]/Desktop/Stock Analysis/n"
'FileName
FileName = "GoogleSheet.csv"
'Connection to Website
Set objWebCon = CreateObject("MSXML2.XMLHTTP.3.0")
'Writer
Set objWrit = CreateObject("ADODB.Stream")
'Connecting to the Website
objWebCon.Open "Get", ShtUrl, False
objWebCon.Send (ShtUrl)
'Once page is fully loaded
If objWebCon.Status = 200 Then
'Write the text of the sheet
objWrit.Open
objWrit.Type = 1
objWrit.Write objWebCon.ResponseBody
objWrit.Position = 0
objWrit.SaveToFile Location & FileName
objWrit.Close
End If
Set objWebCon = Nothing
Set objWrit = Nothing
End Sub
Long story short... I am using a pc to open a .txt file located on a server... but sometimes the .txt file is not finished (there is still data stored in a buffer of the source computer).
FilePath = "D:\test.txt"
Workbooks.Open(Filename:=FilePath, ReadOnly:=True, IgnoreReadOnlyRecommended:=True)
Someone smarter than I am has identified that the .txt file is "locked" by the operating system until it is finished but I am still able to open it. I would like to wait for the .txt file to be "not locked" before opening it. How do I do this?
Note: The "smarter" person than me explained... the .txt file can be opened by a "dumb" program like "notepad" but if you try to use "Microsoft Word" to open it... you get a message telling you that it is locked...
import time
is_open = False
while not(is_open):
try:
f = open('test.txt','w')
is_open=True
except:
time.sleep(1)
I don't know how well the code below will work for your scenario.
You could change the constants into parameters (if you think their values need to change/be determined dynamically).
You could also change the GetFileOrWait's implementation such that it allows an infinite loop (I chose to avoid this, but maybe you want this).
All in all, the below is basically a function which tries to return the workbook in 120 seconds (or times out with an error) -- which you can hopefully use in a parent subroutine/procedure.
You may be able to specify finer frequencies (seconds may be too coarse) by using Timer instead or other lower level APIs.
Option Explicit
Private Function GetFileOrNothing() As Workbook
Const FILE_PATH As String = "D:\test.txt" ' Could pass this in as argument (if needed).
On Error Resume Next
Set GetFileOrNothing = Workbooks.Open(Filename:=FILE_PATH, ReadOnly:=True, IgnoreReadOnlyRecommended:=True)
On Error GoTo 0
End Function
Private Function GetFileOrWait() As Workbook
' Attempts to open a file. If access fails, waits n seconds before trying again.
' This function raises an error (times out to prevent infinite loop) after N seconds.
Const MAXIMUM_WAIT_IN_SECONDS As Long = 10
Const INTERVAL_WAIT_IN_SECONDS As Long = 1
Dim timeToStopAt As Date
timeToStopAt = DateAdd("s", MAXIMUM_WAIT_IN_SECONDS, Now)
Do While Now < timeToStopAt
Dim outputWorkbook As Workbook
Set outputWorkbook = GetFileOrNothing()
If Not (outputWorkbook Is Nothing) Then Exit Do
Application.Wait DateAdd("s", INTERVAL_WAIT_IN_SECONDS, Now)
DoEvents
Loop
If outputWorkbook Is Nothing Then
Err.Raise vbObjectError + 5, , "Failed to access file within the specified time frame."
End If
Set GetFileOrWait = outputWorkbook
End Function
I wonder if it's possible to make a shortcut with multiple targets, because my code doesn't work with 3 paths. Below code and screenshots.
Can you help? Thank you all in advance
https://ibb.co/pWs87P9
I want something, like in the screenshot below (I've done it manually)
https://ibb.co/9tH4Rx5
C:\Windows\System32\notepad.exe "C:\Temp Logs\app.vbs" "C:\Temp Logs\try.bat"
Sub aa()
Dim sShortcutLocation As String
sShortcutLocation = "C:\Temp Logs\AA.lnk"
With CreateObject("WScript.Shell").CreateShortcut(sShortcutLocation)
.TargetPath = "C:\Windows\System32\notepad.exe ""C:\Temp Logs\app.vbs"""
.Arguments = "C:\Temp Logs\try.bat"
.Description = "Shortcut to the file"
.Save
End With
End Sub
I want to switch between two audio devices connected to my computer (Windows 7 32 bit). I had a look at question, and found nircmd.
Now, I'm able to create two VBS files to switch between the two devices. I was wondering if I could find out what the current active/default sound device is, then I could put everything in one file itself.
My current code is -
Set WshShell = CreateObject("WScript.Shell")
cmds=WshShell.RUN("L:\MyApps\NirCmd\nircmd.exe setdefaultsounddevice ""Speakers""", 0, True)
Set WshShell = Nothing
The other file has "Headphones" instead of "Speakers".
This is how I solved it currently. This sucks big time, I know. It doesn't find the current active device, instead stores the information in a text file (which has to already exist! With the current device name in it!). Yes, it's horrible. But considering my knowledge of VBScript and current knowledge of the Windows Registry, both of which are very near zero, this is the best I could come up with!
I'm posting this here, because of a lack of a simple answer anywhere else. If anybody has any better solutions, without using any other programs, I'll be very grateful to know.
Also, if anybody wants to use this code, please change the file paths and names to suit yours.
Dim objFso, objFileHandle, strDisplayString
Set objFso = WScript.CreateObject("Scripting.FileSystemObject")
Set readObjFileHandle = objFso.OpenTextFile("L:\MyApps\NirCmd\CurrentDevice.txt", 1)
strDisplayString = readObjFileHandle.ReadLine()
readObjFileHandle.Close
Set writeObjFileHandle = objFso.OpenTextFile("L:\MyApps\NirCmd\CurrentDevice.txt", 2, "True")
If StrComp(strDisplayString, "Headphones", vbTextCompare) = 0 Then
'MsgBox "Headphones - switching to Speakers"
Set WshShell = CreateObject("WScript.Shell")
cmds=WshShell.RUN("L:\MyApps\NirCmd\nircmd.exe setdefaultsounddevice ""Speakers""", 2, True)
Set WshShell = Nothing
writeObjFileHandle.Write("Speakers")
Else
'MsgBox "Speakers - switching to Headphones"
Set WshShell = CreateObject("WScript.Shell")
cmds=WshShell.RUN("L:\MyApps\NirCmd\nircmd.exe setdefaultsounddevice ""Headphones""", 2, True)
Set WshShell = Nothing
writeObjFileHandle.Write("Headphones")
End If
writeObjFileHandle.Close
Good afternoon StackOverflow,
I've just signed up here - I've been using this site for ages, and it seems to always be the site to supply the answer so I decided to be part of things.
Without further ado, here is my question -
I am writing an API for LAN parties that me and a group have monthly to help sort things out on the scorekeeping side. My friend is writing the backend for it, and I'm writing the VB6 frontend. It's been a while since I wrote VB6, and I never wrote it as intensively as the grade of frontend I'm aiming for here.
The premise of the program is this - The backend will write events from the game we're playing to a text file in realtime - Which the frontend reads from in realtime. The part I'd like to enquire about at the moment is this -
I know you can read text files line-by-line in VB6. I want the program to 'listen' (so to speak) for certain buzzwords and use their defined 'Values' to affect variables. Here is a mock example of the kind of file it'll be reading -
******************
LANrealm Match Log
******************
Game: Call of Duty 4
Game Type: Team Deathmatch
Date: 01-Jan-2013
Time: 19:00:00
Players: Tramp
Roper
d00b
Pleb
Score Limit: 150
Event: Game Start
Event: Roper killed Pleb (M4A1) shots=5 Feet=2 Body=2 Head=1
Event: Tramp committed suicide (Fall damage)
Event: Tramp killed d00b (Grenade)
Event: Pleb said "I'm saying something"
Event: Pleb teamkilled d00b (G3) shots=3 Feet=0 Body=2 Head=1
Event: Game Finished
Winner: Roper
Roper: Kills=1,Deaths=0,Suicides=0,Teamkills=0
Tramp: Kills=1,Deaths=0,Suicides=1,Teamkills=0
Pleb: Kills=0,Deaths=0,Suicides=0,Teamkills=1
d00b: Kills=0,Deaths=0,Suicides=0,Teamkills=0
Well, I think just by looking at this you can tell what I want the program to pick out of that. It would be a lot easier if I just made it fully comma delimited, but I want to maintain readability of the raw text file. But yeah, just in case you didn't get it, I'd want the program to recognise that 'Roper' had 1 'Kill' and so on and so forth. An example code snippet would be great!
Thanks in advance, guys.
Here's a function you could use to load the contents of a file:
Public Function LoadFile(dFile As String) As String
Dim ff As Integer
On Error Resume Next
ff = FreeFile
Open dFile For Binary As #ff
LoadFile = Space(LOF(ff))
Get #ff, , LoadFile
Close #ff
End Function
Next, you want to split the output of that file.
First, you will need to know what type of EOL termination character will be produced by the back-end. Assuming each line ends with a carriage return (13) and a line feed (10), you could use this code to store each line into a string array:
Dim lines() As String
lines = Split(LoadFile("LANrealm.log"), vbCrLf)
Finally, it's a matter of cycling through each line (using a For...Next loop) and look for whatever information you want to extract:
For i = 0 To Ubound(lines)
' Add here necessary logic to extract the information.
' Each line can be accessed by indexing the array as: lines(i)
Next
Hope this helps you get started...
To test the code:
Start VB6 and create a new project. VB6 will create an empty project with one form
Double click the form to view it
Right click the Toolbox and select "Components"
Locate the "Microsoft Common Dialog Control" and select it
Click OK
Now, drag the "CommonDialog" component from the Toolbox onto the form
Double click the form to view its source code
Paste the following code
NOTE: Make sure you overwrite any pre-existing code
Option Explicit
Private Sub Form_Load()
cDlg.DefaultExt = "txt"
cDlg.Filter = "Text Files|*.txt;*.log"
cDlg.ShowOpen
If cDlg.fileName <> "" Then AnalyzeFile .fileName
End Sub
Private Sub AnalyzeFile(fileName As String)
Dim fileContents As String
Dim lines() As String
Dim i As Integer
fileContents = LoadFile(fileName)
lines = Split(fileContents, vbCrLf)
For i = 0 To UBound(lines)
If InStr(1, lines(i), "event:", vbTextCompare) Then
MsgBox "Line #" & i & " contains the string 'event'" + vbCrLf + vbCrLf + lines(i)
End If
Next
End Sub
Private Function LoadFile(dFile As String) As String
Dim ff As Integer
On Error Resume Next
ff = FreeFile
Open dFile For Binary As #ff
LoadFile = Space(LOF(ff))
Get #ff, , LoadFile
Close #ff
End Function
Run the program and, when asked to supply a file, select one of the logs that will be generated by the back-end.
In this example, the program will tell you which lines contain "event information", such as "Event: Roper killed Pleb (M4A1) shots=5 Feet=2 Body=2 Head=1".
One problem I would see doing this in real-time, reading and writing is if two or more computers or apps try to open the same file. This could be a bit of a mess.
Ok, so if you REALLY want to read your file line by line, I would change your logfile a little different.
******************
LANrealm Match Log
******************
Game: Call of Duty 4
Game Type: Team Deathmatch
Date: 01-Jan-2013
Time:1 9:00:00
Players: Tramp, Roper, d00b, Pleb
Score Limit: 150
Event: Game Start
Event: Roper killed Pleb (M4A1) shots=5 Feet=2 Body=2 Head=1
Event: Tramp committed suicide (Fall damage)
Event: Tramp killed d00b (Grenade)
Event: Pleb said "I'm saying something"
Event: Pleb teamkilled d00b (G3) shots=3 Feet=0 Body=2 Head=1
Event: Game Finished
Winner: Roper
Stat: Roper Kills=1,Deaths=0,Suicides=0,Teamkills=0
Stat: Tramp Kills=1,Deaths=0,Suicides=1,Teamkills=0
Stat: Pleb Kills=0,Deaths=0,Suicides=0,Teamkills=1
Stat: d00b Kills=0,Deaths=0,Suicides=0,Teamkills=0
You can use this to read the file line by line.
Dim FileNo As Integer
Dim TempData As String
Dim TempStr As String
FileNo = FreeFile
Open "c:\game.log" For Input As FileNo
Do
Line Input #FileNo, TempStr
TempData = TempData & TempStr or do what ever you want it to do with that line.
DoEvents
Loop Until EOF(FileNo)
Close #FileNo
MsgBox TempData
However, I would suggest to read the whole file into a string, and then parse out info you want.
If you did, you can then pick out info you might want, like name of game etc.....
Try this.
Create a new module, and paste this in it.
Public Function ParseData(DataSTR As String, StartSTR As String, EndSTR As String) As String
Dim Split1
Dim Split2
Split1 = Split(DataSTR, StartSTR, , 1)
Split2 = Split(Split1(1), EndSTR, , 1)
SplitParse = Split2(0)
End Function
Then add this to a command button.
Private Sub Command2_Click()
Dim FileNo As Integer
Dim TempData As String
FileNo = FreeFile
Open "c:\game.log" For Input As FileNo
TempData = Input(LOF(FileNo), FileNo)
Close
MsgBox TempData
MsgBox Trim(ParseData(TempData, "Game:", Chr(10)))
End Sub
Now this is just a sample of what you can do.