Dim ShowImgWebClient = New WebClient
Dim ImageInBytes As Byte() = ShowImgWebClient.DownloadData("http://ex.domain.com/index.php?checksum=" & lblCheckSum.Text.ToString())
Dim ImageStream As New MemoryStream(ImageInBytes)
Dim CaptchaImg As Image = New Bitmap(ImageStream)
ptbCaptcha.Image = CaptchaImg
I'm use this code for get online captcha to my picturebox name ptbCaptcha.
but when request this image my program show error Parameter is not Valid.
Why this ? and How to make it work ?
This is not the proper way to use MemoryStream.
Here is the example taken from microsoft website :
Imports System
Imports System.IO
Imports System.Text
Module MemStream
Sub Main()
Dim count As Integer
Dim byteArray As Byte()
Dim charArray As Char()
Dim uniEncoding As New UnicodeEncoding()
' Create the data to write to the stream.
Dim firstString As Byte() = _
uniEncoding.GetBytes("Invalid file path characters are: ")
Dim secondString As Byte() = _
uniEncoding.GetBytes(Path.GetInvalidPathChars())
Dim memStream As New MemoryStream(100)
Try
' Write the first string to the stream.
memStream.Write(firstString, 0 , firstString.Length)
' Write the second string to the stream, byte by byte.
count = 0
While(count < secondString.Length)
memStream.WriteByte(secondString(count))
count += 1
End While
' Write the stream properties to the console.
Console.WriteLine( _
"Capacity = {0}, Length = {1}, Position = {2}", _
memStream.Capacity.ToString(), _
memStream.Length.ToString(), _
memStream.Position.ToString())
' Set the stream position to the beginning of the stream.
memStream.Seek(0, SeekOrigin.Begin)
' Read the first 20 bytes from the stream.
byteArray = _
New Byte(CType(memStream.Length, Integer)){}
count = memStream.Read(byteArray, 0, 20)
' Read the remaining Bytes, Byte by Byte.
While(count < memStream.Length)
byteArray(count) = _
Convert.ToByte(memStream.ReadByte())
count += 1
End While
' Decode the Byte array into a Char array
' and write it to the console.
charArray = _
New Char(uniEncoding.GetCharCount( _
byteArray, 0, count)){}
uniEncoding.GetDecoder().GetChars( _
byteArray, 0, count, charArray, 0)
Console.WriteLine(charArray)
Finally
memStream.Close()
End Try
End Sub
End Module
See MemoryStream for more information.
Related
I have had a hard time finding any support for Chrome Native Messaging Hosts in VB.Net, after much trial and error I have put together something that works for a single message at a time. However I have not been able to get the
While OpenStandardStreamIn() IsNot Nothing
part to work. If anyone has any suggestions...
OTHERWISE THIS CODE WORKS GREAT, for anyone else like me looking for a VB.Net Native Message Host:
Also, this uses Newtonsoft.Json Lib for JSON serializing...
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading.Tasks
Imports System.Diagnostics
Imports System.Runtime.InteropServices
Module Module1
Public Sub Main(ByVal args As String())
'create response as an array so it can be easily converted JSON
Dim ResponseString() As String = {""}
' get input from chrome extension
Dim InputString As String = OpenStandardStreamIn()
' Do whatever you want with Input, then prepare Response
ResponseString(0) = DO_SOMETHING(InputString)
' Send Response to Chrome
OpenStandardStreamOut(ResponseString)
End Sub
Public Function OpenStandardStreamIn() As String
Dim MsgLength As Integer = 0
Dim InputData As String = ""
Dim LenBytes As Byte() = New Byte(3) {} 'first 4 bytes are length
Dim StdIn As System.IO.Stream = Console.OpenStandardInput() 'open the stream
StdIn.Read(LenBytes, 0, 4) 'length
MsgLength = System.BitConverter.ToInt32(LenBytes, 0) 'convert length to Int
Dim Buffer As Char() = New Char(MsgLength - 1) {} 'create Char array for remaining bytes
Using Reader As System.IO.StreamReader = New System.IO.StreamReader(StdIn) 'Using to auto dispose of stream reader
While Reader.Peek() >= 0 'while the next byte is not Null
Reader.Read(Buffer, 0, Buffer.Length) 'add to the buffer
End While
End Using
InputData = New String(Buffer) 'convert buffer to string
Return InputData
End Function
Private Sub OpenStandardStreamOut(ByVal ResponseData() As String) 'fit the response in an array so it can be JSON'd
Dim OutputData As String = ""
Dim LenBytes As Byte() = New Byte(3) {} 'byte array for length
Dim Buffer As Byte() 'byte array for msg
OutputData = Newtonsoft.Json.JsonConvert.SerializeObject(ResponseData) 'convert the array to JSON
Buffer = System.Text.Encoding.UTF8.GetBytes(OutputData) 'convert the response to byte array
LenBytes = System.BitConverter.GetBytes(Buffer.Length) 'convert the length of response to byte array
Using StdOut As System.IO.Stream = Console.OpenStandardOutput() 'Using for easy disposal
StdOut.WriteByte(LenBytes(0)) 'send the length 1 byte at a time
StdOut.WriteByte(LenBytes(1))
StdOut.WriteByte(LenBytes(2))
StdOut.WriteByte(LenBytes(3))
For i As Integer = 0 To Buffer.Length - 1 'loop the response out byte at a time
StdOut.WriteByte(Buffer(i))
Next
End Using
End Sub
End Module
From the Chrome Extension, open a connection, send a message, and once a response is received the host will close. Check our Chrome's Dev page for a sample app/extension: https://developer.chrome.com/apps/nativeMessaging
I hope this helps somebody, and please let me know if you make any improvements!
Sub Main() ' Recursive Version
Try
Dim stdin As Stream = Console.OpenStandardInput()
Dim stdout As Stream = Console.OpenStandardOutput()
Dim MsgLength As Integer = 0
Dim InputData As String = ""
Dim LenBytes As Byte() = New Byte(3) {}
stdin.Read(LenBytes, 0, 4)
MsgLength = BitConverter.ToInt32(LenBytes, 0)
Dim Buffer As Byte() = New Byte(MsgLength - 1) {}
stdin.Read(Buffer, 0, Buffer.Length)
InputData = Encoding.UTF8.GetString(Buffer)
Dim Str As String = Newtonsoft.Json.JsonConvert.SerializeObject("[" & Now & "] Arrrr!")
Dim buff() As Byte = Encoding.UTF8.GetBytes(Str)
stdout.Write(BitConverter.GetBytes(buff.Length), 0, 4)
stdout.Write(buff, 0, buff.Length)
Main()
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Oh, Snap!")
End Try
End Sub
Update:
I made some edits to clean up remnants of efforts that weren't helping.
I understood previously that "something" is occurring during the file-write process and that it's something that I personally am not perceiving.
Thanks to Plutonix in the comments, I know that the problem is in how I'm handling this but I don't understand exactly how to do it properly and research isn't turning anything up.
I'm attempting to write a file that must be then prefixed with an md5 checksum of itself
The result should be
[hash of "the brown fox"]the brown fox
In the example file I'm testing on, this is the hash I want to reproduce. Viewing in UTF-8 or in Hex reveals that these are the only characters within
¶ Â趓Naþ¼Wô}¾}
VB.net Debug.print produces exactly this
Hash.tostring: ¶ Â趓Naþ¼Wô}¾}
hash.length: 16
hash.tostring.length: 16
utf8hash.length: 28 -- I think this is part of the problem?
The file writes, as seen in UTF-8 or a Hex Editor
¶ Â趓Naþ¼Wô}¾}
This is one variant of most of my efforts
Dim HashMaker As New MD5CryptoServiceProvider()
Dim HashBytes As Byte() = HashMaker.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()))
Dim Hash As New StringBuilder()
For hx = 0 To HashBytes.Length - 1
Hash.Append(Chr(HashBytes(hx)))
Next
Dim HashMaker As New MD5CryptoServiceProvider()
Dim HashBytes As Byte() = HashMaker.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()))
Dim Hash As New StringBuilder()
For hx = 0 To HashBytes.Length - 1
Hash.Append(Chr(HashBytes(hx)))
Next
Debug.Print(Hash.ToString())
Dim fHeader As Byte() = New Byte(7) {}
Array.Copy(b, fHeader, 8)
Dim utf8hash As Byte() = Encoding.UTF8.GetBytes(Hash.ToString())
System.IO.File.WriteAllText(fname & "_long", "")
Dim s As New System.IO.FileStream(fname & "_long", System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite)
s.Write(b, 0, 8)
s.Write(utf8hash, 0, utf8hash.Length)
s.Write(Encoding.UTF8.GetBytes(sb.ToString()), 0, sb.Length)
s.Close()
I've tried an alternate method
Dim utf8 As String = ""
For hx = 0 To HashBytes.Length - 1
Hash.Append(Chr(HashBytes(hx)))
utf8 &= Chr(HashBytes(hx))
Next
Dim fHeader As Byte() = New Byte(7) {}
Array.Copy(b, fHeader, 8)
Dim utf8hash As Byte() = Encoding.UTF8.GetBytes(Hash.ToString())
Debug.Print("Hash.tostring: " & Hash.ToString())
Debug.Print("hash.length: " & Hash.Length)
Debug.Print("hash.tostring.length: " & Hash.ToString.Length)
Debug.Print("utf8hash.length: " & utf8.Length)
System.IO.File.WriteAllText(fname & "_long", "")
Dim s As New System.IO.FileStream(fname & "_long", System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite)
s.Write(b, 0, 8)
s.Write(Encoding.UTF8.GetBytes(utf8), 0, 16)
s.Write(Encoding.UTF8.GetBytes(sb.ToString()), 0, sb.Length)
As for a Self-contained example:
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Security.Cryptography
Public Class Form1
Private Function TestWrite()
Dim book As Integer = 5, row As Integer = 5
Dim fname As String = "c:\programtestFile.dat"
Dim sb As New StringBuilder
Dim HashMaker As New MD5CryptoServiceProvider()
Dim HashBytes As Byte() = HashMaker.ComputeHash(Encoding.UTF8.GetBytes("test"))
Dim Hash As New StringBuilder()
For hx = 0 To HashBytes.Length - 1
Hash.Append(Chr(HashBytes(hx)))
Next
Debug.Print(Hash.ToString)
Dim utf8hash As Byte() = Encoding.UTF8.GetBytes(Hash.ToString())
System.IO.File.WriteAllText(fname & "_long", "")
Dim s As New System.IO.FileStream(fname & "_long", System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite)
's.Write(b, 0, 8)
s.Write(utf8hash, 0, utf8hash.Length)
's.Write(Encoding.UTF8.GetBytes(sb.ToString()), 0, sb.Length)
s.Close()
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TestWrite()
End Sub
End Class
The code below prints this this to debug window
kÍF!ÓsÊÞNƒ&'´ö (it is prefixed by a tab, part of the computed hash)
But writes this to the file (as can be seen in a hex editor or setting the Encoding to UTF-8
ÂkÃF!ÓsÊÞNÆ’&'´ö
It turned out what I needed to do is assemble all the Bytes into a single Byte Array like so.
The first 8 bytes are a sort of header. The next 16 are an MD5 checksum of the remaining bytes.
I hope this helps someone.
Dim FileBytes(8 + HashBytes.Length + StringBytes.Length - 1) As Byte
Array.Copy(b, 0, FileBytes, 0, 8)
Array.Copy(HashBytes, 0, FileBytes, 8, 16)
Array.Copy(StringBytes, 0, FileBytes, 24, StringBytes.Length)
System.IO.File.WriteAllBytes(fname, FileBytes)
I have a code where i want to get an stream from an image and convert the memory stream to string array and store in a variable. But my problem is i also want to get the image from the string variable and paint on a picture box.
If i use this like
PictureBox1.Image = image.FromStream(memoryStream)
I am able to print the picture on picture box. But this is not my need. I just want to get the image stream from file and convert the stream as text and store it to some string variable and again i want to use the string variable and convert it to stream to print the image on picture box.
Here is my Code.(Vb Express 2008)
Public Function ImageConversion(ByVal image As System.Drawing.Image) As String
If image Is Nothing Then Return ""
Dim memoryStream As System.IO.MemoryStream = New System.IO.MemoryStream
image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Gif)
Dim value As String = ""
For intCnt As Integer = 0 To memoryStream.ToArray.Length - 1
value = value & memoryStream.ToArray(intCnt) & " "
Next
Dim strAsBytes() As Byte = New System.Text.UTF8Encoding().GetBytes(value)
Dim ms As New System.IO.MemoryStream(strAsBytes)
PictureBox1.Image = image.FromStream(ms)
Return value
End Function
This wouldn`t work in the way you have posted it (at least the part of recreating the image).
See this:
Public Function ImageConversion(ByVal image As System.Drawing.Image) As String
If image Is Nothing Then Return ""
Dim memoryStream As System.IO.MemoryStream = New System.IO.MemoryStream
image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Gif)
Dim value As String = ""
Dim content As Byte() = memoryStream.ToArray()
' instead of repeatingly call memoryStream.ToArray by using
' memoryStream.ToArray(intCnt)
For intCnt As Integer = 0 To content.Length - 1
value = value & content(intCnt) & " "
Next
value = value.TrimEnd()
Return value
End Function
To recreate the image using the created string you can`t use Encoding.GetBytes() like you did, because you would get a bytearray which represents your string. E.g "123 32 123" you would not get a byte array with the elements 123, 32 , 123
Public Function ImageConversion(ByVal stringRepOfImage As String) As System.Drawing.Image
Dim stringBytes As String() = stringRepOfImage.Split(New String() {" "}, StringSplitOptions.RemoveEmptyEntries)
Dim bytes As New List(Of Byte)
For intCount = 0 To stringBytes.Length - 1
Dim b As Byte
If Byte.TryParse(stringBytes(intCount), b) Then
bytes.Add(b)
Else
Throw new FormatException("Not a byte value")
End If
Next
Dim ms As New System.IO.MemoryStream(bytes.ToArray)
Return Image.FromStream(ms)
End Function
Reference: Byte.TryParse
I am creating an application to create a key that is unique to each computer. This info is derived from the OS serial number and processorID.
Is there a way to 'shorten' a string? Maybe by converting it to HEX or something else...
The reason is this: I used to use a VB6 section of code (http://www.planet-source-code.com/vb...48926&lngWId=1) that gets the details and the output is only 13 digits long. Mine is a lot longer, but gets the same info...
BTW, the link I posted above won multiple awards, but I am having huge trouble in converting it to .NET. Has anyone by any chance converted it, or know of someone who has? Or a tool that actually works?
Thanks
EDIT
Here is the full working link: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=48926&lngWId=1
It sounds like you want a 'hashing algorithm' or 'hash function'. They are a common concept: http://en.wikipedia.org/wiki/Hash_function
Generally speaking you can simply write your own function to take a string and return a hashed number but there is some suitable code here that uses the .NET framework: http://support.microsoft.com/kb/301053
Here is a working example which retrieves the Processor ID, for the first Processor found, and the OS Serial Number; it concatenates these to strings together and then performs various encodings on them.
This is a simple VB.Net Console project. Be sure to reference the System.Management assembly in your project. Just copy and paste this code example into the main module, set a breakpoint at the end of Sub Main(), and look at the various results.
Module Module1
Sub Main()
Dim uniqueID As String = GetUniqueID()
' convert it to a base64 string
Dim encoding As New Text.ASCIIEncoding()
Dim result1 = Convert.ToBase64String(encoding.GetBytes(uniqueID))
' compress it
Dim result2 As String = CompressString(uniqueID)
Dim result3 As String = DecompressString(result2)
' encrypt it
Dim result4 As String = AES_Encrypt(uniqueID, "password")
Dim result5 As String = AES_Decrypt(result4, "password")
' hash it
Dim result6 As String = HashString(uniqueID)
End Sub
Private Function GetUniqueID() As String
Dim result As String = GetOSSerialNumber()
Dim processorIDs() As String = GetProcessorIDs()
If ((processorIDs IsNot Nothing) AndAlso (processorIDs.Count > 0)) Then
result &= processorIDs(0)
End If
Return result
End Function
Private Function GetProcessorIDs() As String()
Dim result As New List(Of String)
Dim searcher = New System.Management.ManagementObjectSearcher("Select ProcessorId from Win32_Processor")
For Each managementObj In searcher.Get()
result.Add(CStr(managementObj.Properties("ProcessorId").Value))
Next
Return result.ToArray()
End Function
Private Function GetOSSerialNumber() As String
Dim result As String = ""
Dim searcher = New System.Management.ManagementObjectSearcher("Select SerialNumber from Win32_OperatingSystem")
For Each managementObj In searcher.Get()
result = CStr(managementObj.Properties("SerialNumber").Value)
Next
Return result
End Function
Public Function CompressString(ByVal source As String) As String
Dim result As String = ""
Dim encoding As New Text.ASCIIEncoding()
Dim bytes() As Byte = encoding.GetBytes(source)
Using ms As New IO.MemoryStream
Using gzsw As New System.IO.Compression.GZipStream(ms, IO.Compression.CompressionMode.Compress)
gzsw.Write(bytes, 0, bytes.Length)
gzsw.Close()
result = Convert.ToBase64String(ms.ToArray)
End Using
End Using
Return result
End Function
Public Function DecompressString(ByVal source As String) As String
Dim result As String = ""
Dim bytes() As Byte = Convert.FromBase64String(source)
Using ms As New IO.MemoryStream(bytes)
Using gzsw As New System.IO.Compression.GZipStream(ms, IO.Compression.CompressionMode.Decompress)
Dim data(CInt(ms.Length)) As Byte
gzsw.Read(data, 0, CInt(ms.Length))
Dim encoding As New Text.ASCIIEncoding()
result = encoding.GetString(data)
End Using
End Using
Return result
End Function
Public Function AES_Encrypt(ByVal input As String, ByVal pass As String) As String
Dim AES As New System.Security.Cryptography.RijndaelManaged
Dim Hash_AES As New System.Security.Cryptography.MD5CryptoServiceProvider
Dim encrypted As String = ""
Try
Dim hash(31) As Byte
Dim temp As Byte() = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(pass))
Array.Copy(temp, 0, hash, 0, 16)
Array.Copy(temp, 0, hash, 15, 16)
AES.Key = hash
AES.Mode = Security.Cryptography.CipherMode.ECB
Dim DESEncrypter As System.Security.Cryptography.ICryptoTransform = AES.CreateEncryptor
Dim Buffer As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(input)
encrypted = Convert.ToBase64String(DESEncrypter.TransformFinalBlock(Buffer, 0, Buffer.Length))
Catch ex As Exception
End Try
Return encrypted
End Function
Public Function AES_Decrypt(ByVal input As String, ByVal pass As String) As String
Dim AES As New System.Security.Cryptography.RijndaelManaged
Dim Hash_AES As New System.Security.Cryptography.MD5CryptoServiceProvider
Dim decrypted As String = ""
Try
Dim hash(31) As Byte
Dim temp As Byte() = Hash_AES.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(pass))
Array.Copy(temp, 0, hash, 0, 16)
Array.Copy(temp, 0, hash, 15, 16)
AES.Key = hash
AES.Mode = Security.Cryptography.CipherMode.ECB
Dim DESDecrypter As System.Security.Cryptography.ICryptoTransform = AES.CreateDecryptor
Dim Buffer As Byte() = Convert.FromBase64String(input)
decrypted = System.Text.ASCIIEncoding.ASCII.GetString(DESDecrypter.TransformFinalBlock(Buffer, 0, Buffer.Length))
Catch ex As Exception
End Try
Return decrypted
End Function
Private Function HashString(ByVal source As String) As String
Dim encoding As New Text.ASCIIEncoding()
Dim bytes() As Byte = encoding.GetBytes(source)
Dim workingHash() As Byte = New System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(bytes)
Dim result As String = ""
For Each b In workingHash
result = result & b.ToString("X2")
Next
Return result
End Function
End Module
I'm having some trouble with this, despite finding examples. I think it may be an encoding problem, but I'm just not sure. I am trying to programitally download a file from a https server, that uses cookies (and hence I'm using httpwebrequest). I'm debug printing the capacity of the streams to check, but the output [raw] files look different. Have tried other encoding to no avail.
Code:
Sub downloadzip(strURL As String, strDestDir As String)
Dim request As HttpWebRequest
Dim response As HttpWebResponse
request = Net.HttpWebRequest.Create(strURL)
request.UserAgent = strUserAgent
request.Method = "GET"
request.CookieContainer = cookieJar
response = request.GetResponse()
If response.ContentType = "application/zip" Then
Debug.WriteLine("Is Zip")
Else
Debug.WriteLine("Is NOT Zip: is " + response.ContentType.ToString)
Exit Sub
End If
Dim intLen As Int64 = response.ContentLength
Debug.WriteLine("response length: " + intLen.ToString)
Using srStreamRemote As StreamReader = New StreamReader(response.GetResponseStream(), Encoding.Default)
'Using ms As New MemoryStream(intLen)
Dim fullfile As String = srStreamRemote.ReadToEnd
Dim memstream As MemoryStream = New MemoryStream(New UnicodeEncoding().GetBytes(fullfile))
'test write out to flie
Dim data As Byte() = memstream.ToArray()
Using filestrm As FileStream = New FileStream("c:\temp\debug.zip", FileMode.Create)
filestrm.Write(data, 0, data.Length)
End Using
Debug.WriteLine("Memstream capacity " + memstream.Capacity.ToString)
'Dim strData As String = srStreamRemote.ReadToEnd
memstream.Seek(0, 0)
Dim buffer As Byte() = New Byte(2048) {}
Using zip As New ZipInputStream(memstream)
Debug.WriteLine("zip stream cap " + zip.Length.ToString)
zip.Seek(0, 0)
Dim e As ZipEntry
Dim flag As Boolean = True
Do While flag ' daft, but won't assign e=zip... tries to evaluate
e = zip.GetNextEntry
If IsNothing(e) Then
flag = False
Exit Do
Else
e.UseUnicodeAsNecessary = True
End If
If Not e.IsDirectory Then
Debug.WriteLine("Writing out " + e.FileName)
' e.Extract(strDestDir)
Using output As FileStream = File.Open(Path.Combine(strDestDir, e.FileName), _
FileMode.Create, FileAccess.ReadWrite)
Dim n As Integer
Do While (n = zip.Read(buffer, 0, buffer.Length) > 0)
output.Write(buffer, 0, n)
Loop
End Using
End If
Loop
End Using
'End Using
End Using 'srStreamRemote.Close()
response.Close()
End Sub
So I get the right size file downloaded, but dotnetzip does not recognise it, and the files that get copied out are incomplete/invalid zips. I've spent most of today on this, and am ready to give up.
I think the answer will be to break down the problem, and perhaps change a couple aspects in the code.
For example, lets get rid of converting the response stream to a string:
Dim memStream As MemoryStream
Using rdr As System.IO.Stream = response.GetResponseStream
Dim count = Convert.ToInt32(response.ContentLength)
Dim buffer = New Byte(count) {}
Dim bytesRead As Integer
Do
bytesRead += rdr.Read(buffer, bytesRead, count - bytesRead)
Loop Until bytesRead = count
rdr.Close()
memStream = New MemoryStream(buffer)
End Using
Next, there's an easier way to output the contents of a memory stream to a file. Consider your code
Dim data As Byte() = memstream.ToArray()
Using filestrm As FileStream = New FileStream("c:\temp\debug.zip", FileMode.Create)
filestrm.Write(data, 0, data.Length)
End Using
can be replaced with
Using filestrm As FileStream = New FileStream("c:\temp\debug.zip", FileMode.Create)
memstream.WriteTo(filestrm)
End Using
That eliminates the need to transfer your memory stream into another byte array, and then push the byte array down the stream, when in fact the memory stream can transfer data directly to file (via the filestream) saving the middle-man buffer.
I'll admit I haven't worked with the Zip/compression libraries you're using, but with the above amendments you have removed unnecessary transfers between streams, byte arrays, strings, etc, and hopefully eliminated the encoding issues you were having.
Give that a try and let us know how you get on. Consider attempting to open the file that you saved ("C:\temp\debug.zip") to see if it is listed as corrupt. If not, then you know at least as far as that in the code, it is working ok.
I thought I'd post my full working solution to my own question, it combines the two excellent replies I've had, thank you guys.
Sub downloadzip(strURL As String, strDestDir As String)
Try
Dim request As HttpWebRequest
Dim response As HttpWebResponse
request = Net.HttpWebRequest.Create(strURL)
request.UserAgent = strUserAgent
request.Method = "GET"
request.CookieContainer = cookieJar
response = request.GetResponse()
If response.ContentType = "application/zip" Then
Debug.WriteLine("Is Zip")
Else
Debug.WriteLine("Is NOT Zip: is " + response.ContentType.ToString)
Exit Sub
End If
Dim intLen As Int32 = response.ContentLength
Debug.WriteLine("response length: " + intLen.ToString)
Dim memStream As MemoryStream
Using stmResponse As IO.Stream = response.GetResponseStream()
'Using ms As New MemoryStream(intLen)
Dim buffer = New Byte(intLen) {}
'Dim memstream As MemoryStream = New MemoryStream(buffer)
Dim bytesRead As Integer
Do
bytesRead += stmResponse.Read(buffer, bytesRead, intLen - bytesRead)
Loop Until bytesRead = intLen
memStream = New MemoryStream(buffer)
Dim res As Boolean = False
res = ZipExtracttoFile(memStream, strDestDir)
End Using 'srStreamRemote.Close()
response.Close()
Catch ex As Exception
'to do :)
End Try
End Sub
Function ZipExtracttoFile(strm As MemoryStream, strDestDir As String) As Boolean
Try
Using zip As ZipFile = ZipFile.Read(strm)
For Each e As ZipEntry In zip
e.Extract(strDestDir)
Next
End Using
Catch ex As Exception
Return False
End Try
Return True
End Function
You can download into a MemoryStream, then examine it:
Public Sub Download(url as String)
Dim req As HttpWebRequest = System.Net.WebRequest.Create(url)
req.Method = "GET"
Dim resp As HttpWebResponse = req.GetResponse()
If resp.ContentType = "application/zip" Then
Console.Error.Write("The result is a zip file.")
Dim length As Int64 = resp.ContentLength
If length = -1 Then
Console.Error.WriteLine("... length unspecified")
length = 16 * 1024
Else
Console.Error.WriteLine("... has length {0}", length)
End If
Dim ms As New MemoryStream
CopyStream(resp.GetResponseStream(), ms) '' **see note below!!!!
'' list contents of the zip file
ms.Seek(0,SeekOrigin.Begin)
Using zip As ZipFile = ZipFile.Read (ms)
Dim e As ZipEntry
Console.Error.WriteLine("Entries:")
Console.Error.WriteLine(" {0,22} {1,10} {2,12}", _
"Name", "compressed", "uncompressed")
Console.Error.WriteLine("----------------------------------------------------")
For Each e In zip
Console.Error.WriteLine(" {0,22} {1,10} {2,12}", _
e.FileName, _
e.CompressedSize, _
e.UncompressedSize)
Next
End Using
Else
Console.Error.WriteLine("The result is Not a zip file.")
CopyStream(resp.GetResponseStream(), Console.OpenStandardOutput)
End If
End Sub
Private Shared Sub CopyStream(input As Stream, output As Stream)
Dim buffer(32768 - 1) As Byte
Dim n As Int32
Do
n = input.Read(buffer, 0, buffer.Length)
If n = 0 Then Exit Do
output.Write(buffer, 0, n)
Loop
End Sub
EDIT
Just one note - I would not advise using this code (this approach) if the Zip file is very large. How large is "very large"? Well that depends, of course. The code I suggested above downloads the file into a memory stream, which of course means the entire contents of the zip file are held in memory. If it is a 28kb zip file, then there's no problem. But if it is a 2gb zip file, then you may have a big problem.
In that case you will want to stream it to a temporary file on disk, not to a MemoryStream. I'll leave that as an exercise for the reader.
The above will work for "reasonably sized" zip files, where "reasonable" depends on your machine configuration and application scenario.