Post arbitary file to server from VB (like type=FILE)

Hi All,

I am hoping maybe Bhagyesh Trivedi may see this and help as his code listed in

is very close to what I need.

Basically, I need to be able to post ANY file to a server from within a VB app. The file could be a gif, jpg,exe, pdf etc.

I'm not sure how to encode the contents as base64 and set the correct content header/mime type.

If somebody could help me with even a sample project or source code, I am willing to give additional points.

USEFUL CODE FROM Bhagyesh's response in thread mentioned above:

paste the code below in a module and call it from the form.
this will not require the active x
to call the function call it as


SplitAddr strURL, strSrv, strScript
Dim LoginResponse As String
LoginResponse = PostInfo(tSrv, tScript, "login=loginname&password=mypassword" )

here the 'login' is the name of the text field containing the login and 'password' is the fields name of the password. loginname is the value u need to post so is the mypassword. then response will be stored on the loginResponse page

' code begin
Private Declare Function InternetOpen Lib "wininet.dll" _
         Alias "InternetOpenA" _
            (ByVal lpszCallerName As String, _
             ByVal dwAccessType As Long, _
             ByVal lpszProxyName As String, _
             ByVal lpszProxyBypass As String, _
             ByVal dwFlags As Long) As Long

      Private Declare Function InternetConnect Lib "wininet.dll" _
            Alias "InternetConnectA" _
            (ByVal hInternetSession As Long, _
             ByVal lpszServerName As String, _
             ByVal nProxyPort As Integer, _
             ByVal lpszUsername As String, _
             ByVal lpszPassword As String, _
             ByVal dwService As Long, _
             ByVal dwFlags As Long, _
             ByVal dwContext As Long) As Long

   Private Declare Function InternetReadFile Lib "wininet.dll" _
            (ByVal hFile As Long, _
             ByVal sBuffer As String, _
             ByVal lNumBytesToRead As Long, _
             lNumberOfBytesRead As Long) As Integer

   Private Declare Function HttpOpenRequest Lib "wininet.dll" _
            Alias "HttpOpenRequestA" _
            (ByVal hInternetSession As Long, _
             ByVal lpszVerb As String, _
             ByVal lpszObjectName As String, _
             ByVal lpszVersion As String, _
             ByVal lpszReferer As String, _
             ByVal lpszAcceptTypes As Long, _
             ByVal dwFlags As Long, _
             ByVal dwContext As Long) As Long

   Private Declare Function HttpSendRequest Lib "wininet.dll" _
            Alias "HttpSendRequestA" _
            (ByVal hHttpRequest As Long, _
             ByVal sHeaders As String, _
             ByVal lHeadersLength As Long, _
             ByVal sOptional As String, _
             ByVal lOptionalLength As Long) As Boolean

   Private Declare Function InternetCloseHandle Lib "wininet.dll" _
            (ByVal hInternetHandle As Long) As Boolean

   Private Declare Function HttpAddRequestHeaders Lib "wininet.dll" _
             Alias "HttpAddRequestHeadersA" _
             (ByVal hHttpRequest As Long, _
             ByVal sHeaders As String, _
             ByVal lHeadersLength As Long, _
             ByVal lModifiers As Long) As Integer

Public Function PostInfo(srv$, script$, postdat$) As String

  Dim hInternetOpen As Long
  Dim hInternetConnect As Long
  Dim hHttpOpenRequest As Long
  Dim bRet As Boolean
  hInternetOpen = 0
  hInternetConnect = 0
  hHttpOpenRequest = 0
  'Use registry access settings.
  hInternetOpen = InternetOpen("http generic", _
                  vbNullString, _
                  vbNullString, _
  If hInternetOpen <> 0 Then
     'Type of service to access.
     'Change the server to your server name
     hInternetConnect = InternetConnect(hInternetOpen, _
                        srv$, _
                        INTERNET_DEFAULT_HTTP_PORT, _
                        vbNullString, _
                        "HTTP/1.0", _
                        INTERNET_SERVICE_HTTP, _
                        0, _
     If hInternetConnect <> 0 Then
      'Brings the data across the wire even if it locally cached.
       Const INTERNET_FLAG_RELOAD = &H80000000
       hHttpOpenRequest = HttpOpenRequest(hInternetConnect, _
                           "POST", _
                           script$, _
                           "HTTP/1.0", _
                           vbNullString, _
                           0, _
                           INTERNET_FLAG_RELOAD, _
        If hHttpOpenRequest <> 0 Then
           Dim sHeader As String
           Const HTTP_ADDREQ_FLAG_ADD = &H20000000
           Const HTTP_ADDREQ_FLAG_REPLACE = &H80000000
  sHeader = "Content-Type: application/x-www-form-urlencoded" _
             & vbCrLf
           bRet = HttpAddRequestHeaders(hHttpOpenRequest, _
             sHeader, Len(sHeader), HTTP_ADDREQ_FLAG_REPLACE _
             Or HTTP_ADDREQ_FLAG_ADD)
           Dim lpszPostData As String
           Dim lPostDataLen As Long
           lpszPostData = postdat$
           lPostDataLen = Len(lpszPostData)
           bRet = HttpSendRequest(hHttpOpenRequest, _
                  vbNullString, _
                  0, _
                  lpszPostData, _
           Dim bDoLoop             As Boolean
           Dim sReadBuffer         As String * 2048
           Dim lNumberOfBytesRead  As Long
           Dim sBuffer             As String
           bDoLoop = True
           While bDoLoop
            sReadBuffer = vbNullString
            bDoLoop = InternetReadFile(hHttpOpenRequest, _
               sReadBuffer, Len(sReadBuffer), lNumberOfBytesRead)
            sBuffer = sBuffer & _
                 Left(sReadBuffer, lNumberOfBytesRead)
            If Not CBool(lNumberOfBytesRead) Then bDoLoop = False
           PostInfo = sBuffer
           bRet = InternetCloseHandle(hHttpOpenRequest)
        End If
        bRet = InternetCloseHandle(hInternetConnect)
     End If
     bRet = InternetCloseHandle(hInternetOpen)
  End If
End Function

Public Sub SplitAddr(ByVal addr$, srv$, script$)
'Inputs: The full url including http://
' Two variables that will be changed
'Returns: Splits the addr$ var into the server name
' and the script path

  Dim i%

  i = InStr(addr$, "/")
  srv$ = Mid(addr$, i + 2, Len(addr$) - (i + 1))
  i = InStr(srv$, "/")
  script$ = Mid(srv$, i, Len(srv$) + 1 - i)
  srv$ = Left$(srv$, i - 1)

End Sub

'this function converts non-alpha or numeric chars to ASCII equivalent
'so the webserver can read them
Public Function HTTPSafeString(Text As String) As String
    Dim lCounter As Long
    Dim sBuffer As String
    Dim sReturn As String
    sReturn = Text

    sReturn = Text
    For lCounter = Len(Text) To 1 Step -1
        sBuffer = Mid(Text, lCounter, 1)

        If Not sBuffer Like "[a-z,A-Z,0-9]" Then
            sReturn = Left$(sReturn, lCounter - 1) & "%" & Right$("00" & Hex(Asc(sBuffer)), 2) & Mid$(sReturn, lCounter + 1)
        End If
    Next lCounter
    HTTPSafeString = sReturn
End Function

Thank you in advance,


Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

See this question. There is an example of a POST request, containing a file :

And here is the list of the known mime types, provided by microsoft. Generally teh server doesn't care a lot what is the cotent type of the posted file, so if you are not sure, leave it application/octet-stream :

Also you can use the FindMimeFromData API function to get the correct MIME type :
dmackeyAuthor Commented:
Hi TKalchev,

With this sample code:

In this sample, you need Microsoft Internet Transfer Control, four text boxes, two command buttons, a common dialog (to browse for .gif file) and two command buttons.  Let me know if you have any questions.

Option Explicit

Private Sub cmdBrowse_Click()
    On Error Resume Next
    With CommonDialog1
        .CancelError = True
        If Err = 0 Then
            txtFile.Text = .FileName
        End If
        On Error Resume Next
    End With
End Sub

Private Sub cmdExecute_Click()
    Dim strFormData As String
    'Length of the separator string must be 76.  I think this is simply a limitation of the component I was using and not a rule.
    strFormData = strFormData & "-------------------------------------------------------------ZkdOkkdKjoHEEdZ" & vbCrLf
    strFormData = strFormData & "Content-Disposition: attachment; name=""thefile""; filename=""" & txtFile.Text & """" & vbCrLf
    strFormData = strFormData & "Content-Transfer-Encoding: binary" & vbCrLf
    strFormData = strFormData & "Content-Type: image/gif" & vbCrLf
    strFormData = strFormData & vbCrLf  'Extra carriage return before contents of multipart section
    strFormData = strFormData & fGetFileContents(txtFile.Text) & vbCrLf
    strFormData = strFormData & "-------------------------------------------------------------ZkdOkkdKjoHEEdZ" & vbCrLf
    strFormData = strFormData & "Content-Disposition: form-data; name=""user""" & vbCrLf
    strFormData = strFormData & vbCrLf   'Extra carriage return before contents of multipart section
    strFormData = strFormData & txtUser.Text & vbCrLf
    strFormData = strFormData & "-------------------------------------------------------------ZkdOkkdKjoHEEdZ" & vbCrLf
'    strFormData = StrConv(strFormData, vbFromUnicode)
    With Inet1
        .URL = txtAction.Text
        .RequestTimeout = 120
        Inet1.Execute txtAction.Text, "Post", strFormData, _
           "Content-Type: multipart/form-data; boundary=-----------------------------------------------------------ZkdOkkdKjoHEEdZ"
    End With
End Sub

Private Sub Inet1_StateChanged(ByVal State As Integer)
   ' Retrieve server response using the GetChunk
   ' method when State = 12. This example assumes the
   ' data is text.
   Dim i As Integer
   Select Case State
   ' ... Other cases not shown.

   Case icResponseCompleted ' 12
       Dim vtData As Variant ' Data variable.
       Dim strData As String: strData = ""
       Dim bDone As Boolean: bDone = False

       ' Get first chunk.
       vtData = Inet1.GetChunk(1024, icString)

       Do While Not bDone

           strData = strData & vtData
           ' Get next chunk.
           vtData = Inet1.GetChunk(1024, icString)

           If Len(vtData) = 0 Then
               bDone = True
           End If
           txtReturn.Text = txtReturn.Text & strData
   End Select
End Sub

Is there any ,imitation on the size of the file?

I saw in other methods where they loaded the file into a variable of type string and if the file is large, the size exceeded the string length and caused an error. For instance, strFormData above would get HUGE if the file was large and cause the same error.

Is there any way around this?

Also, what small changes would be required so you could call the INET Control using API functions instead of placing the control on the form.

While I'm at it, I'll throw up one more detail to stew on:

Can you:

1) Have it so you can detect how much is flowing out so you can create a progress bar
2) Have it done like a "thread" so the form does not lock up while its transferring?

Again, thanks for the help, it's very much appreciated and I will throw bonus points at anybody who can help me with the above. I'm not *too* familiar with VB but learning so some of my questions may be a little basic.

Thank you,

about the file size - AFAIK vb supports strings with length up to 2 GB, so it should not be a problem. The other limitation is on the server side, normally any web server has an upper limit of the size of the POST data and the size of uploaded file. If you are using PHP for the server side scripting, these limits are in php.ini and are called post_max_size and upload_max_filesize, for ASP i don't know where are exactly the settings, but for sure there is a limit.

About a progressbar - as i can see in the properties/methids/events of the MS Interet Transfer control, there is no such an option. You can only make if when downloading data from the server, not when uploading.

About a thread - you can organise it by yourself. Simply generate the control "on the fly"
( i.e.
Dim InetControl as Variant

Set InetControl = CreateObject ( ,"InetCtls.Inet" );

InetControl.Execute ....

Set InetControl = Nothing

and then put the entire routine in a separate thread

Hope it helps

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.