I am currently trying to automate screenshot grabs from Bloomberg Terminal using DDE within VBA. Currently I have come up with a way to automatically pull screenshots by 'printing' through the Microsoft XPS Document Writer:
Dim ch As Variant
Dim CUSIP As String
CUSIP = Range("B12")
ch = DDEInitiate("winblp", "bbk")
Call DDEExecute(ch, "<blp-1>" & CUSIP & " mtge<GO>")
Call DDEExecute(ch, "<blp-1> DES<Go><print>")
Application.Wait Now + TimeValue("0:00:02")
Application.SendKeys "DES ", False
Application.SendKeys "{enter}", False
Call DDETerminate(ch)
The code seems to work fine on the first run, but then crashes the developer on each subsequent. Any feedback or further suggestions would be appreciated. Thanks!
Probably too late but this may help someone as I've had to do this as well. You can just use the <copy> command in your DDE calls and paste it into Word/Excel/Outlook without using send keys:
Call DDEExecute(ch, "<blp-1> <copy>")
Related
Good morning all.
This is a subject that I have been trying to dig for a long time but which is only very little documented on the web: How to control a third-party application via VBA?
The objective is to create a link (bridge) of an Office tool (Excel / Access) in order to carry out manipulation on a Windows application, for example pasting the clipboard in paint or in notepad. For efficiency's, I don't want to use the sendkeys command which we can't trust.
To my knowledge there is a DDE method which would allow it but it seems to be obsolete. Can you confirm ?
Here is a code using DDE in order to connect to Word and send it the Print command
...
channelNumber = Application.DDEInitiate( _
app:="WinWord", _
topic:="C:\FORMLETR.DOC")
Application.DDEExecute channelNumber, "[FILEPRINT]"
Application.DDETerminate channelNumber
...
Trying to modify it to paste our clipboard on paint, here is the code that does not work:
...
channelNumber = Application.DDEInitiate( _
app:="mspaint", _
topic:="C:\Test.png")
Application.DDEExecute channelNumber, "[PASTE]"
Application.DDETerminate channelNumber
...
Result:
I have an error "Run time error '13': Type missmatch" in the first line although the file opens.
Let's try with the notepad:
...
Sub DDEtoBlocNotes()
Dim Datarange As Range
chan = Application.DDEInitiate(app:="NOTEPAD", topic:="C:\Users\User1\Documents\Access\Test.txt")
Set Datarange = ThisWorkbook.Worksheets("Sheet1").Range("A1")
Datarange.Copy
Application.DDEExecute chan, "[EDITIONCOLLER]"
Application.DDETerminate chan
End Sub
...
Result: same error as before despite opening the document.
"Run time error '13': Type missmatch"
Can you help me solve this problem please?
Do you have documentation on the attributes of DDE commands?
Do you know of another way to connect to a third-party application to send commands to it? (OLE / ODBC / ADO)?
Thank you in advance for your answers.
I've searched the internet for the answer to this and keep running into issues getting it to work.
I need to check if a file at the below location is open/locked, and then have the code wait 15 seconds and then try again. Right now if someone else has the file open a dialog box opens asking if I want to open read only, which I don't want. I tried using Application.DisplayAlerts = False to get the message not to appear but that didn't seem to work. So I have two main issues:
Checking if the file is open and waiting to try again.
Stop the dialog box from opening asking to open as read only.
Workbooks.Open filename:= _
"https://somecorporatewebsite/sites/TNKYWest/Engr/ASE%20Updates/Shared%20Documents/ASENW Updater.xlsx"
Try something like this:
From MSDN site:
https://msdn.microsoft.com/en-us/library/office/ff193284.aspx
Sub UseCanCheckOut(docCheckOut As String)
Dim docCheckout
set docCheckout="File name to open"
' Determine if workbook can be checked out.
If Workbooks.CanCheckOut(Filename:=docCheckOut) = True Then
Workbooks.CheckOut (Filename:=docCheckOut)
Else
Found at the MSDN Website:
https://msdn.microsoft.com/en-us/library/office/ff822851.aspx
Application.Wait(Now + TimeValue("0:00:10"))
Workbooks.CheckOut (Filename:=docCheckOut) 'Try to check the file out again.
End If
End Sub
This part is covered in the
IF workbooks.cancheckout(filename:=docCheckout)=true then workbooks.checkout ' method in part 1.
I'm experiencing a 1004 runtime error when saving a workbook (wbk_New) on which I copy-pasted a group of shapes from another workbook (wbk_Old). I should tell that a macro from wbk_Old is assigned to this group.
wbk_Old.Worksheets("DashBoard").Activate
ChartTop = ActiveSheet.Shapes("Group_VesselGraphics").Top
ChartLeft = ActiveSheet.Shapes("Group_VesselGraphics").Left
ActiveSheet.Shapes("Group_VesselGraphics").OnAction = ""
ActiveSheet.Shapes("Group_VesselGraphics").Copy
wbk_New.Worksheets("DashBoard").Activate
ActiveSheet.Shapes("Group_VesselGraphics").Delete
ActiveSheet.Paste
ActiveSheet.Shapes("Group_VesselGraphics").Top = ChartTop
ActiveSheet.Shapes("Group_VesselGraphics").Left = ChartLeft
ActiveSheet.Shapes("Group_VesselGraphics").OnAction = "'" & ActiveWorkbook.Name & "'!UpdateShipGraph"
wbk_Old.Close
wbk_New.SaveAs As path_Old
I can't figure out what is causing this error...Does anyone have already faced this issue ?
Thanks a ton for your help !
(I forgot to mention that a chart also belong to this group of shapes!)
Ok, I don't understand why but it seems that some links were still existing between "wbk_New" and "wbk_Old" although I broke all the links and updated the chart to refer to intrinsic data.
Hence, closing of "wbk_Old" couldn't be properly performed and wbk_New became corrupted, so that it was impossible to save it.
The only way I found to work around this issue is to save (on itself) wbk_New before closing wbk_Old and then to call an external process that replace wbk_Old by wbk_New, using a delay of 4s, and to close wbk_New and Old before the delay completed.
I have to admit that this is an ugly solution, if someone knows a better way it would be nice to share it!
Here below is the code of my solution, where BatchCmd creates a batch file of a command and shell it:
{code above}
wbk_New.Save
cmd = "ping -n 4 127.0.0.1 >nul" + vbCrLf
cmd = cmd + "move /Y " & path_New & " " & path_Old
Call BatchCmd(cmd, status:=vbHide)
wbk_Old.Close
wbk_New.Close
I have a simple VBA code (see below), that goes to a webpage, selects some value, clicks the “Begin download” button, and then saves the file. The problem is I am stuck at the “clicking the download button” part. Can someone help?
Here is the code:
Sub Treasury_Auc_Notes()
Dim IE As Object
Set IE = Nothing
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.Navigate "http://www.treasurydirect.gov/RI/OFAuctions?form=ndnld&typesec=notes"
While IE.Busy
DoEvents
Wend
IE.Document.All.Item("begYr").Value = "2012"
With IE.Document.getElementsByName("cols")
.Item(0).Checked = True
End With
'Click "Begin download" button (this is where I am stuck)
'Choose Save Open or Cancel (I haven’t got to this part yet)
ActiveWorkbook.SaveAs Filename
End Sub
This one's tricky, and due to restrictive security on my laptop, I'm not able to verify this 100%, but try:
While IE.ReadyState <> 4
DoEvents
Wend
IE.Document.All.Item("begYr").Value = "2012"
With IE.Document.getElementsByName("cols")
.Item(0).Checked = True
End With
Dim ele As Object
For Each ele In IE.Document.Forms
If ele.Action = "/RI/OFAuctions" Then
ele.Submit
Exit For
End If
Next
You may have to use SendKeys (I think Application.SendKeys "o") method to open the file then use VBA to save the ActiveWorkbook to the desired location. I'm not able to test SendKeys for reasons mentioned below.
Or, I'm pretty sure there is a WinAPI functions that can do this more reliably than SendKeys. You'll need to get the hWnd of the Save dialog and do some other stuff to force it to open/save. This is fairly advanced VBA that I probably have a reference to somewhere, but rarely need to use it. If you have trouble with this particular part, I would urge you to ask a separate question "How to get the hWnd of File Save dialog and download file from IE" or something like that.
NOTE: I can't test the SendKeys method. When I use the above code, I am fairly certain the file is being downloaded, but it is going to a temporary folder that is hidden, and difficult to find. In any case, it does appear to be downloading with some manual intervention. I get this warning:
I click to ignore that (I have no idea how to automate this part, I'm just trying to validate that the form .Submit method actually worked), and after some creative searching (temporary internet files get dumped in a strange/hidden folder usually) I verify the file is downloaded, although it is showing as a TXT extension instead of CSV.
If instead of using VBA, I click on the button manually, and I choose to "open" the file opens as CSV and has the same path to that temporary internet location.
I am writing a macro that will scrape my company's internal SAP site for vendor information. For several reasons I have to use VBA to do so. However, I cannot figure out why I keep getting these three errors when I attempt to scrape the page. Is it possible that this has something to do with the UAC integrity model? Or is there something wrong with my code? Is it possible for a webpage using http can be handled differently in internet explorer? I am able to go to any webpage, even other internal webpages, and can scrape each of those just fine. But when i attempt to scrape the SAP page, i get these errors. The error descriptions and when they occur are:
800706B5 - The interface is unknown (occurs when I place breakpoints before running the offending code)
80004005 - Unspecified error (occurs when I don't place any errors and just let the macro run)
80010108 - The Object invoked has disconnected from its clients. (I can't seem to get a consistent occurrence of this error, it seems to happen around the time that something in excel is so corrupted that no page will load and i have to reinstall excel)
I have absolutely no idea what is going on. The Integrity page didn't make much sense to me, and all the research I found on this talked about connecting to databases and using ADO and COM references. However I am doing everything through Internet Explorer. Here is my relevant code below:
Private Sub runTest_Click()
ie.visible = True
doScrape
End Sub
'The code to run the module
Private Sub doTest()
Dim result As String
result = PageScraper.scrapeSAPPage("<some num>")
End Sub
PageScraper Module
Public Function scrapeSAPPage(num As Long) As String
'Predefined URL that appends num onto end to navigate to specific record in SAP
Dim url As String: url = "<url here>"
Dim ie as InternetExplorer
set ie = CreateObject("internetexplorer.application")
Dim doc as HTMLDocument
ie.navigate url 'Will always sucessfully open page, regardless of SAP or other
'pauses the exection of the code until the webpage has loaded
Do
'Will always fail on next line when attempting SAP site with error
If Not ie.Busy And ie.ReadyState = 4 Then
Application.Wait (Now + TimeValue("00:00:01"))
If Not ie.Busy And ie.ReadyState = 4 Then
Exit Do
End If
End If
DoEvents
Loop
Set doc = ie.document 'After implementation of Tim Williams changes, breaks here
'Scraping code here, not relevant
End Function
I am using IE9 and Excel 2010 on a Windows 7 machine. Any help or insight you can provide would be greatly appreciated. Thank you.
I do this type of scraping frequently and have found it very difficult to make IE automation work 100% reliably with errors like those you have found. As they are often timing issues it can be very frustrating to debug as they don't appear when you step through, only during live runs To minimize the errors I do the following:
Introduce more delays; ie.busy and ie.ReadyState don't necessarily give valid answers IMMEDIATELY after an ie.navigate, so introduce a short delay after ie.navigate. For things I'm loading 1 to 2 seconds normally but anything over 500ms seems to work.
Make sure IE is in a clean state by going ie.navigate "about:blank" before going to the target url.
After that you should have a valid IE object and you'll have to look at it to see what you've got inside. Generally I avoid trying to access the entire ie.document and instead use IE.document.all.tags("x") where 'x' is a suitable thing I'm looking for such as td or a.
However after all these improvements although they have increased my success rate I still have errors at random.
My real solution has been to abandon IE and instead do my work using xmlhttp.
If you are parsing out your data using text operations on the document then it will be a no-brainer to swap over. The xmlhttp object is MUCH more reliable. and you just get the "responsetext" to access the entire html of the document.
Here is a simplified version of what I'm using in production now for scraping, it's so reliable it runs overnight generating millions of rows without error.
Public Sub Main()
Dim obj As MSXML2.ServerXMLHTTP
Dim strData As String
Dim errCount As Integer
' create an xmlhttp object - you will need to reference to the MS XML HTTP library, any version will do
' but I'm using Microsoft XML, v6.0 (c:\windows\system32\msxml6.dll)
Set obj = New MSXML2.ServerXMLHTTP
' Get the url - I set the last param to Async=true so that it returns right away then lets me wait in
' code rather than trust it, but on an internal network "false" might be better for you.
obj.Open "GET", "http://www.google.com", True
obj.send ' this line actually does the HTTP GET
' Wait for a completion up to 10 seconds
errCount = 0
While obj.readyState < 4 And errCount < 10
DoEvents
obj.waitForResponse 1 ' this is an up-to-one-second delay
errCount = errCount + 1
Wend
If obj.readyState = 4 Then ' I do these on two
If obj.Status = 200 Then ' different lines to avoid certain error cases
strData = obj.responseText
End If
End If
obj.abort ' in real code I use some on error resume next, so at this point it is possible I have a failed
' get and so best to abort it before I try again
Debug.Print strData
End Sub
Hope that helps.