4
votes

I'm trying to use Winsock to download some files and save them. In my case, I have a MSHFlexGrid with 2 columns: one with URL and the other with the "path+filename" (where the file is going to be saved). I'm iterating through all rows calling the next function:

Public Function DownloadSock(ArqURL As String, ArqDestino As String) As Boolean
'ArqURL is the file URL
'ArqDestino is where the downloaded file is going to be stored, in my hard disc

Dim arquivo() As Byte
Dim ficheiroID As Integer

ficheiroID = FreeFile
On Error GoTo Trata_erro
Open ArqDestino For Binary Access Write As #ficheiroID


Me.Winsock1.Connect ArqURL, 80 
Me.Winsock1.GetData arquivo()
Put #ficheiroID, , arquivo()

Close #ficheiroID

DownloadSock = True


Exit Function

Trata_erro:

    MDIForm1.Text1 = MDIForm1.Text1 & "Error! " & Err.Number & Err.Description & " - " & Err.Source & " - URL: " & ArqURL & " - Destino: " & ArqDestino & vbNewLine
    DownloadSock = False

End Function

I'm getting this error

40006: Wrong protocol or connection state for the requested transaction or request

What am I doing wrong?

2

2 Answers

2
votes

Have you checked out this Microsoft Support page? It indicates there's a bug in the Winsock control and the hotfix may be helpful.

Another thing to try is to make sure your winsock connection is open before trying to read/send data, and if it is closed, reopen a new connection:

if winsock.state=9 ' error state
  winsock.close
  while winsock.state<>0 ' closed state
    doEvents
  wend ' you need a while loop, because it doesn't close "immediately".
end if
' now you reopen it, or do whatever else you need

You might also consider changing your connection code to something like:

With Winsock1
      If .State <> sckClosed Then .Close
      .RemoteHost = ArqURL 
      .RemotePort = 80
      .Connect
End With

One last thing. Check out this post on using the Winsock control.

1
votes

I think you have overestimated the power of the Winsock control. You can't just use the Winsock's GetData method to reach out and grab a file. There has to be an active connection between your client application and some other application on the server side. After a connection is established, this server application will feed data to your application, the Winsock's DataArrival event will fire, and then you can use the GetData method to retrieve it. Your code should look more like this:

Public Sub DownloadSock(ArqURL As String)

  Dim arquivo() As Byte
  Dim ficheiroID As Integer

  ficheiroID = FreeFile
  Me.Winsock1.Connect ArqURL, 80

End Function

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)

  Dim ArqDestino As String
  Dim arquivo() As Byte
  Dim ficheiroID As Integer

  ficheiroID = FreeFile
  Open ArqDestino For Binary Access Write As #ficheiroID
  Me.Winsock1.GetData arquivo()
  Put #ficheiroID, , arquivo()
  Close #ficheiroID

End Sub

This is far from complete however (nor is it guaranteed to be syntactically correct, consider it pseudo code). After making the connection, you then have to implement some mechanism to tell the server to begin sending the file. If the file is large enough it will take many DataArrival events to get it all, so it will have to be held in an accumulator while the data comes across. There's more to this than you think.

I would take a look at some tutorials and/or sample code (look for a VB6 project that uses the Winsock control on CodeProject, like this one).