Link to home
Start Free TrialLog in
Avatar of dmackey
dmackey

asked on

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

http://www-level3.experts-exchange.com/questions/20738529/Local-VB-app-post-data-to-server-side-browser-app.html

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

strUrl="http://localhost/mypage.asp"

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.
  Const INTERNET_OPEN_TYPE_PRECONFIG = 0
  hInternetOpen = InternetOpen("http generic", _
                  INTERNET_OPEN_TYPE_PRECONFIG, _
                  vbNullString, _
                  vbNullString, _
                  0)
 
  If hInternetOpen <> 0 Then
     'Type of service to access.
     Const INTERNET_SERVICE_HTTP = 3
     Const INTERNET_DEFAULT_HTTP_PORT = 80
     'Change the server to your server name
     hInternetConnect = InternetConnect(hInternetOpen, _
                        srv$, _
                        INTERNET_DEFAULT_HTTP_PORT, _
                        vbNullString, _
                        "HTTP/1.0", _
                        INTERNET_SERVICE_HTTP, _
                        0, _
                        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, _
                           0)
 
        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, _
                  lPostDataLen)
 
           Dim bDoLoop             As Boolean
           Dim sReadBuffer         As String * 2048
           Dim lNumberOfBytesRead  As Long
           Dim sBuffer             As String
           bDoLoop = True
           While bDoLoop
            DoEvents
            sReadBuffer = vbNullString
            DoEvents
            bDoLoop = InternetReadFile(hHttpOpenRequest, _
               sReadBuffer, Len(sReadBuffer), lNumberOfBytesRead)
               DoEvents
            sBuffer = sBuffer & _
                 Left(sReadBuffer, lNumberOfBytesRead)
                 DoEvents
            If Not CBool(lNumberOfBytesRead) Then bDoLoop = False
            DoEvents
           Wend
           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,

Dan.

Avatar of tkalchev
tkalchev
Flag of Germany image

See this question. There is an example of a POST request, containing a file : https://www.experts-exchange.com/questions/20639338/Upload-A-File-To-A-PHP-Script-And-Also-Pass-A-Posted-Value.html

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 :
http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp?frame=true#Known_MimeTypes

Also you can use the FindMimeFromData API function to get the correct MIME type : http://msdn.microsoft.com/workshop/networking/moniker/reference/functions/findmimefromdata.asp
Avatar of dmackey
dmackey

ASKER

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
        .ShowOpen
        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)
       DoEvents

       Do While Not bDone

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

           If Len(vtData) = 0 Then
               bDone = True
           End If
       Loop
         
           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,
Dan.
ASKER CERTIFIED SOLUTION
Avatar of tkalchev
tkalchev
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial