Solved

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

Posted on 2003-11-13
6
1,569 Views
Last Modified: 2008-03-10
Hi All,

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

http://www-level3.experts-exchange.com/Programming/Q_20738529.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.

0
Comment
Question by:dmackey
  • 2
6 Comments
 
LVL 9

Expert Comment

by:tkalchev
ID: 9747168
See this question. There is an example of a POST request, containing a file : http://www.experts-exchange.com/Programming/Programming_Languages/Visual_Basic/Q_20639338.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
0
 

Author Comment

by:dmackey
ID: 9747423
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.
0
 
LVL 9

Accepted Solution

by:
tkalchev earned 500 total points
ID: 9748042
Hi,

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
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
If you’re thinking to yourself “That description sounds a lot like two people doing the work that one could accomplish,” you’re not alone.
An introduction to basic programming syntax in Java by creating a simple program. Viewers can follow the tutorial as they create their first class in Java. Definitions and explanations about each element are given to help prepare viewers for future …
In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now