I have searched for hours on the internet and have found lots of questions but not ONE answer. In every forum this question goes unanswered, even in the Microsoft Forums. They completely ignore it. I have seen just about ever guess there is and they are all just that GUESSES!!!
Error 12029 - Inet Control
Error 10061 - Winsock
As well as other assorted related errors. I even downloaded code sample projects from the Microsoft site on correct programming for these controls and still those projects don't work outside the IDE. Go Figure...
Both error messages indicate a problem connecting to a Server.
WSAECONNREFUSED
10061
0x274D
No connection could be made because the target machine actively refused it.
ERROR_INTERNET_CANNOT_CONNECT
12029
The attempt to connect to the server failed.
The title of the Thread implies that you can run successfully from within the IDE but running as an .exe fails. Is this the case? If so, what is different when you run as a .exe?
I've seen the 10061 error happen when the server was not running and / or the network wasn't working.
What is different when running from the exe???? That's what I want to know. Since one cannot change the timing of the controls, not by any means I know of. I know what the messages mean but they are bogus. It works everytime in the IDE.
It's hard for me to test this but when I run it with the same Command that you used it does run but it tells me "Invalid Version File on Server" and to contact you. Is that good or bad?
Oh and things sometimes do work differently in the exe because it's much faster than in the IDE and the solution is often to put a DoEvents in the middle (or perhaps after) some relatively-long running process.
I had a similar problem a couple years ago. no matter what i did my form would not even show when made to an exe. Worked fine in the ide. Don't remember
exactly but i know it was caused by a manifest file. I removed the manifest and it ran fine.
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim MsgString As String
'when the server sends data back to winsock1:
'capture it and write it to a file
'get the data that winsock1 recieves and store it in webData string
'Winsock1.GetData MsgString, vbString
Winsock1.GetData b, vbByte
DataAvailable = True
End Sub
This assumes that all the data will arrive in one DataArrival event which it may or may not do. When running under the IDE it's possibe, as Martin pointed out, that your code is running slower than when running as a .exe. Therefore it may be that under those conditions, the 'delay' is sufficient for the data to have all arrived in one event, whereas when running as a .exe there is no such delay and it requires 2 or more DataArrival events to be processed before all the data is received. This will result in Array b being incomplete. More importantly, it will cause DataAvailable to be set too early and this code
Code:
Private Sub Winsock1_Connect()
URLFileName = "http://www.***********/" & LCase(EXEname) & "/" & DLFileName
DataAvailable = False
GetWinsockData URLFileName
Do Until DataAvailable
DoEvents
Loop
Winsock1.Close
ProcessDownload
End Sub
will close the socket prematurely. (That might be the cause of the 10061 as you might be getting a DataArrival event on a closed socket which will send Winsock into complete confusion)
In fact, you're always running a risk of array b being incomplete / corrupted, if more than one DataArrival event happens. (ie subsequent events will overwrite the data from previous events)
2.
Code:
brwWebBrowser.Navigate2 "http://www.***********/autoupdate" & LCase(EXEname) & ".html", BrowserNavConstants.navNoReadFromCache Or BrowserNavConstants.navNoHistory
Do While brwWebBrowser.Busy
DoEvents
Loop
In my experience using the Busy property to indicate when an http request has completed is not very reliable. It can be un-set too early.
I tend to use a combination of the Busy property and the NavigateComplete2 event, checking in that event, that the "Complete" is actually for the URL that was requested. On many pages, the Home page of this forum for example, when requestig the URL, 2 or more requests for differng URL are actually made. This results in multiple NavigateComplete2 events to be triggered and, I believe, the Busy property is toggled for each one, so it's importat to check that the one you expected has completed.
Typically I'd implement the check something like:
Code:
Private Sub brwWebBrowser_NavigateComplete2(ByVal pDisp As Object, URL As Variant)
If Mid$(URL,1, Len(myURL)) = Mid$(myURL,1,len(myURL)) then boComplete = True
End Sub
where boComplete and myURL are Public variables, myURL being the URL requested and boComplete a Boolean. Note the use of Mid$ and the length of the URL requested. This is because if you make a request such as http://www.vbforums.com the URL returned in the NavigateComplete2 event has an extra "/" tagged on the end.
Then I'd use:
Code:
boComplete = False
myURL = "http://www.***********/autoupdate" & LCase(EXEname) & ".html"
brwWebBrowser.Navigate2 "http://www.***********/autoupdate" & LCase(EXEname) & ".html", BrowserNavConstants.navNoReadFromCache Or BrowserNavConstants.navNoHistory
Do Until brwWebBrowser.Busy = False And boComplete = True
DoEvents
Loop
to wait for completion.
Again, taking into account the 'time difference' when running under the IDE, perhaps whilst the Busy property has been un-set too early it doesn't matter because by the time you get to process the data etc it actually has all arrived. This may not be the case when running as a .exe and could be causing you problems.
Hope that helps.
Last edited by Doogle; Jan 29th, 2008 at 03:32 AM.
I've just realised that I've pointed out a potential issue with the Winsock DataArrival event but haven't suggested a solution. Unfortunately, in your case, nothing straightforward springs to mind. Normally when using Winsock you'd create your own Application Protocol (AP) so you can identify when all the data has been received.
Typically, when transferring files, you'd send the receiver the expected byte count, and the receiver would count the bytes as they were received and when the two were equal, it would 'know' that the transfer is complete. As you're sending an http request you don't have the luxury of being able to define the AP and as far as I know the http protocol doesn't provide any "Finished" signal in the way you're using it.
Is there any particular reason why you're using Winsock rather than a WebBrowser to perform this transfer? At least a WebBrowser control will 'speak' native http and you do get some sort of signal when something has completed. Failing that, the only thing I can think of is to use the "raw" http protocol in the Winsock transfer so you do receive all the http 'signals', but basically all you'd be doing is emulating a part of the Browser control.
Last edited by Doogle; Jan 29th, 2008 at 12:39 AM.
No, I tried Inet Control to perform the transfer as well before using Winsock and the same exact problem. It's very hard to believe that transferring 13 bytes of information is too much for on DataArrival event, but hey who knows. There must be something I can do that the IDE does to make it work. I can't use the browser control for I haven't seen a function that would transfer raw data.
Martin,
Yes, that is bad for that means that no data was transferred. As when you run in the IDE you should see that data is transferred. It doesn't matter how many DoEvents you have nothing changes.
You have turned on a light bulb. I was expecting the control to be able to handle this communication by itself from the server but I was MISTAKEN. I have had to revert back to my communication days and do that part myself. You and Martin are correct. Even 13 bytes comes in multiple events that one has to handle themselves in the application. Even though you would expect the server and the control to communicate better on how many bytes are to be transferred they do not.
Ok, got it to work (for now). I will need to do extensive testing on this and will then write an article on the proper usage since there is not ONE on the whole entire internet. It will keep a lot of people from pulling out their hair... Once they find it anyway.
Here it is. BTW, there is a testit.bat file that you can run to test it.
Try this
Add reference to WinHTTP.dll in systems32. (Browse to it, if Microsoft WinHTTP services doesn't show on the references list.)
Note this simple example doesn't do anything fancy, just dumps the downloaded bytes to disk.
OnResponseStart when you can safely access the headers.
OnResponseDataAvailable which returns a byte array of downloaded data for each chunk.
OnResponseEnd which ends the download.
Option Explicit
Private WithEvents http As WinHttpRequest
Private mContentLength As Long
Private mProgress As Long
Private Sub Command1_Click()
' Create the WinHTTPRequest ActiveX Object.
Set http = New WinHttpRequest
' Open an HTTP connection.
http.open "GET", "http://home.in.tum.de/~paula/mpeg/wg_gdo_1.mpg", True 'True means asynch.
' Send the HTTP Request.
http.send
End Sub
Private Sub http_OnResponseDataAvailable(Data() As Byte)
mProgress = mProgress + UBound(Data) + 1
ProgressBar1.Value = mProgress
Put #1, , Data
End Sub
Private Sub http_OnResponseFinished()
Close #1
MsgBox "done"
End Sub
Private Sub http_OnResponseStart(ByVal Status As Long, ByVal ContentType As String)
Text1.Text = http.getAllResponseHeaders()
mProgress = 0
mContentLength = CLng(http.getResponseHeader("Content-Length"))
ProgressBar1.Max = mContentLength
Open "C:\twg_gdo_1.mpg" For Binary As #1
That's the simplest approach I have seen and requires nothing extra in coding. The control does all the work the way it is supposed to and it works from a exe
Brilliant!!!!
Last edited by randem; Jan 29th, 2008 at 04:39 PM.
That's the simplest approach I have seen and requires nothing extra in coding. The control does all the work the way it is supposed to and it work from a exe
Simple It's still a binary download that works in exe form. It doesn't take a whole lot of effort to replace the code in the AutoUpdate code to use the one in the HTTP project to get the correct data. Plus you don't have to check for the byte counts. It's done automatically the way it's supposed to be done
If end users are going to use it you may want to include the
Private Sub http_OnError(ByVal ErrorNumber As Long, ByVal ErrorDescription As String) in case of a lost connection
If end users are going to use it you may want to include the
Private Sub http_OnError(ByVal ErrorNumber As Long, ByVal ErrorDescription As String) in case of a lost connection
Another issue i ran into was firewalls, my own firewall was blocking it when i was testing.