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_PRECONF IG = 0
hInternetOpen = InternetOpen("http generic", _
INTERNET_OPEN_TYPE_PRECONF IG, _
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(hInternetO pen, _
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(hInternetC onnect, _
"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-url encoded" _
& vbCrLf
bRet = HttpAddRequestHeaders(hHtt pOpenReque st, _
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(hHttpOpenR equest, _
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(hHttpOpen Request, _
sReadBuffer, Len(sReadBuffer), lNumberOfBytesRead)
DoEvents
sBuffer = sBuffer & _
Left(sReadBuffer, lNumberOfBytesRead)
DoEvents
If Not CBool(lNumberOfBytesRead) Then bDoLoop = False
DoEvents
Wend
PostInfo = sBuffer
bRet = InternetCloseHandle(hHttpO penRequest )
End If
bRet = InternetCloseHandle(hInter netConnect )
End If
bRet = InternetCloseHandle(hInter netOpen)
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.
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=
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_PRECONF
hInternetOpen = InternetOpen("http generic", _
INTERNET_OPEN_TYPE_PRECONF
vbNullString, _
vbNullString, _
0)
If hInternetOpen <> 0 Then
'Type of service to access.
Const INTERNET_SERVICE_HTTP = 3
Const INTERNET_DEFAULT_HTTP_PORT
'Change the server to your server name
hInternetConnect = InternetConnect(hInternetO
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(hInternetC
"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-url
& vbCrLf
bRet = HttpAddRequestHeaders(hHtt
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(hHttpOpenR
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(hHttpOpen
sReadBuffer, Len(sReadBuffer), lNumberOfBytesRead)
DoEvents
sBuffer = sBuffer & _
Left(sReadBuffer, lNumberOfBytesRead)
DoEvents
If Not CBool(lNumberOfBytesRead) Then bDoLoop = False
DoEvents
Wend
PostInfo = sBuffer
bRet = InternetCloseHandle(hHttpO
End If
bRet = InternetCloseHandle(hInter
End If
bRet = InternetCloseHandle(hInter
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.
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 & "------------------------- ---------- ---------- ---------- ------ZkdO kkdKjoHEEd Z" & 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.T ext) & vbCrLf
strFormData = strFormData & "------------------------- ---------- ---------- ---------- ------ZkdO kkdKjoHEEd Z" & 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 & "------------------------- ---------- ---------- ---------- ------ZkdO kkdKjoHEEd Z" & vbCrLf
' strFormData = StrConv(strFormData, vbFromUnicode)
With Inet1
.URL = txtAction.Text
.RequestTimeout = 120
Inet1.Execute txtAction.Text, "Post", strFormData, _
"Content-Type: multipart/form-data; boundary=----------------- ---------- ---------- ---------- ---------- --ZkdOkkdK joHEEdZ"
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.
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 & "-------------------------
strFormData = strFormData & "Content-Disposition: attachment; name=""thefile""; filename=""" & txtFile.Text & """" & vbCrLf
strFormData = strFormData & "Content-Transfer-Encoding
strFormData = strFormData & "Content-Type: image/gif" & vbCrLf
strFormData = strFormData & vbCrLf 'Extra carriage return before contents of multipart section
strFormData = strFormData & fGetFileContents(txtFile.T
strFormData = strFormData & "-------------------------
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 & "-------------------------
' strFormData = StrConv(strFormData, vbFromUnicode)
With Inet1
.URL = txtAction.Text
.RequestTimeout = 120
Inet1.Execute txtAction.Text, "Post", strFormData, _
"Content-Type: multipart/form-data; boundary=-----------------
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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