Convert a string into a stream correctly - vb.net

Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text
Namespace WindowScriptingObject
<Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _WindowScriptingObject
<DispId(1)> Function Decompress(ByVal value as String) As String
End Interface
<Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
ClassInterface(ClassInterfaceType.None), _
ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
Implements _WindowScriptingObject
Public WindowScriptingObject()
Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
Dim x As String
' on error resume next
Dim xstream As New MemoryStream(Encoding.Unicode.GetBytes(value))
Dim mem2 As New IO.MemoryStream()
'Dim streamMe As New StreamWriter(mem2,Encoding.UTF8)
'streamMe.Write(value)
'StreamMe.Close()
'mem2.Position=0
Dim gz As New System.IO.Compression.GZipStream(xstream, IO.Compression.CompressionMode.Decompress)
Dim sr As New IO.StreamReader(gz)
x = sr.ReadLine
sr.Close()
'End Using
Decompress = x
End Function
End Class
End Namespace
I verified the string I sent over contains the correct values from my VBScript. However, its says the header is bad.
The above code has to be compiled for testing
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\vbc.exe" /target:library /out:"%userprofile%\desktop\t.dll" "%userprofile%\desktop\t.txt" /verbose
Then registered
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm" /codebase "%userprofile%\desktop\t.dll" /tlb:"%userprofile%\desktop\t.tlb" /v
Then invoked
c:\windows\SysWOW64\cscript.exe old.vbs
I put code in to read the contents from a file, even though that is not the end goal. When I did that the file decompressed correctly.
Dim xstream As New MemoryStream(Encoding.Unicode.GetBytes(value))
This line hear seems to be incorrectly converting my string to a stream.
The goal is to send a compressed string and return a uncompressed string.
The code above is invoked with this code
Const adTypeBinary = 1
Set wso = CreateObject("WindowScriptingObject")
Dim objStream
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
objStream.Open
objStream.LoadFromFile "e:\download\result.gz"
'objStream.Charset = "Windows-1252"
x = objStream.Read(900)
objStream.Close
For i=1 To Len(x)
t = t & Chr(AscW(Mid(x, i, 1)) And 255)
t = t & Chr((AscW(Mid(x, i, 1)) And 65280)/256)
Next
MsgBox wso.Decompress(t), , "vbs"
I tried this, and even converted the string to base64 to get it work.
Dim gzBuffer As Byte() = Convert.FromBase64String(value)
Using ms As New MemoryStream()
Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
ms.Write(gzBuffer, 4, gzBuffer.Length - 4)
Dim buffer As Byte() = New Byte(msgLength - 1) {}
ms.Position = 0
Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
zipStream.Read(buffer, 0, buffer.Length)
End Using
Decompress=System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length)
End Using
The data did not get converted correctly as I still have magic number in GZip header is not correct.
Dumped base64 encoded value into online decoder, and the string I passed in matches to decoded value.
Version 2
Forces me to base64 encode it, but then it works.
How do I remove this annoyance.
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text
Namespace WindowScriptingObject
<Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _WindowScriptingObject
<DispId(1)> Function Decompress(ByVal value as String) As String
End Interface
<Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
ClassInterface(ClassInterfaceType.None), _
ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
Implements _WindowScriptingObject
Public WindowScriptingObject()
Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
Dim x As String
' on error resume next
Dim gzBuffer As Byte() = Convert.FromBase64String(value)
Using ms As New MemoryStream()
Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
ms.Write(gzBuffer, 0, gzBuffer.Length)
Dim buffer As Byte() = New Byte(msgLength - 1) {}
ms.Position = 0
Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
zipStream.Read(buffer, 0, buffer.Length)
End Using
Decompress=System.Text.Encoding.ASCII.GetString(buffer, 0, buffer.Length)
End Using
' Dim xstream As New MemoryStream(value.ToArray())
Dim mem2 As New IO.MemoryStream()
'Dim streamMe As New StreamWriter(mem2,Encoding.UTF8)
'streamMe.Write(value)
'StreamMe.Close()
'mem2.Position=0
'Dim gz As New System.IO.Compression.GZipStream(xstream, IO.Compression.CompressionMode.Decompress)
'Dim sr As New IO.StreamReader(gz)
' x = sr.ReadLine
'sr.Close()
'End Using
'Decompress = x
End Function
End Class
End Namespace
Update this code works except the output size is 500K, and there's only 3100 bytes of text.
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text
Namespace WindowScriptingObject
<Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _WindowScriptingObject
<DispId(1)> Function Decompress(ByVal value as string) As String
End Interface
<Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
ClassInterface(ClassInterfaceType.None), _
ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
Implements _WindowScriptingObject
Public WindowScriptingObject()
Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
' on error resume next
Dim gzBuffer() As Byte = System.Text.Encoding.Default.Getbytes(value)
Using ms As New MemoryStream()
Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
ms.Write(gzBuffer, 0, gzBuffer.Length)
msgbox(msgLength)
Dim buffer As Byte() = New Byte(msgLength - 1) {}
ms.Position = 0
Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
zipStream.Read(buffer, 0, buffer.Length)
End Using
Decompress=System.Text.Encoding.Default.GetString(buffer, 0, buffer.Length)
End Using
End Function
End Class
End Namespace
For some reason msgLength is 559,903 in size, and the decompressed text is roughly 3100 bytes. This means BitConverter.toint32 is malfunctioning as gzBuffer is 865 bytes. The final output size is only know to the GZIPStream function as the text is compressed an the input size has no correlation to the output size.
The other question(s)
can this be coded more efficiently?
What can I do to prevent malicious code injection?
Limit output to the correct size?
If I add new functions do I need more Guid's?
How do I generate a new Guid?
In code block #3 I convert X to a string t and transfer value without conversion.
The output size seems to be based on bad information.
intOutputLength=zipStream.Read(buffer, 0, buffer.Length)
End Using
Decompress=System.Text.Encoding.Default.GetString(buffer, 0, intOutputLength)
At least this reduces the amount of data return to the main program.
Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
If I read this correctly the msgLength is determined by the first 4 characters of the input stream? Since the GZip header is always 1f 8b 08 00 this seems to be a horrible idea. If the output is every greater than 559k seems like a buffer overflow just waiting to happen.
I think this solves the terrible buffer size issue.
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text
Namespace WindowScriptingObject
<Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _WindowScriptingObject
<DispId(1)> Function Decompress(ByVal value as string) As String
End Interface
<Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
ClassInterface(ClassInterfaceType.None), _
ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
Implements _WindowScriptingObject
Public WindowScriptingObject()
Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
' on error resume next
Dim gzBuffer() As Byte = System.Text.Encoding.Default.Getbytes(value)
dim intOutputLength as integer
Dim intBlock as integer
Decompress=""
Using ms As New MemoryStream()
Dim msgLength As Integer = 4096
ms.Write(gzBuffer, 0, gzBuffer.Length)
Dim buffer As Byte() = New Byte(4096) {}
ms.Position = 0
Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
intOutputLength=0
intBlock=4096
while intBlock=4096
intBlock=zipStream.Read(buffer, 0, buffer.Length)
Decompress+=System.Text.Encoding.Default.GetString(buffer, 0, intBlock)
intOutputLength+=intBlock
end while
End Using
End Using
End Function
End Class
End Namespace

I was able to get your code working by changing the VB.NET function and interface to look like this (mainly changing the parameter type):
<Guid("7448E08E-ED0F-4E23-B528-91937BB41756"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)>
Public Interface _WindowScriptingObject
<DispId(1)> Function Decompress(ByVal value As Byte()) As String
End Interface
Public Function Decompress(ByVal value As Byte()) As String Implements _WindowScriptingObject.Decompress
Using xstream As New MemoryStream(value)
Using gz As New System.IO.Compression.GZipStream(xstream, IO.Compression.CompressionMode.Decompress)
Using sr As New IO.StreamReader(gz)
Return sr.ReadLine()
End Using
End Using
End Using
End Function
My test VBS looks like this
Const adTypeBinary = 1
Dim wso
Set wso = CreateObject("WindowScriptingObject")
Dim objStream, x
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
objStream.Open
objStream.LoadFromFile "c:\users\bluem\desktop\Notes.txt.gz"
x = objStream.Read(342737)
objStream.Close
WScript.StdOut.WriteLine wso.Decompress((x))
I'm not entirely sure why I needed to enclose the x parameter in two sets of parentheses, but I think it has something to do with forcing the parameter to be passed by value instead of by reference and helps it convert to a byte array. I was getting an error before I added the extra pair of parentheses.
Edit:
To answer some of your other questions:
I don't think you need to create a new GUID for a new function, only for a new interface or class.
To create a new GUID you can just copy an existing one and change part of it (to digits between 0 and F inclusive) to be unique, or you can go to https://www.guidgenerator.com/ or you can select "Create GUID" from Visual Studio's Tools menu.
If you can clarify your data length problem based on the new code (if a problem still exists), I might be able to answer.

It's been too long since I've written vbscript, so I don't know enough anymore to give fixes. However, I can point out some serious flaws in the vbscript part of this code.
It starts by reading up to 900 bytes from a .gz file, regardless of the actual length of file. Anything longer than a mere 900 bytes will be not read.
It performs this read in binary mode. Binary mode ignores any character set or encoding info, and just reads raw bytes, which is appropriate for a .gz file. However, the next thing that happens with this data is using the Len() function, which is for strings, not binary data; Len() is not the appropriate function here. Additionally, the data is next used in the For loop via the Mid() function. Mid() is likewise intended only for strings, and the x variant is not a string. vbscript string objects are more than just the raw characters; they include meta data for things like encoding, length, and character buffers, and those string functions rely on the objects being constructed properly with all metadata.
There's no way this vbscript produces correct results. Until that is resolved, there's no point in even looking at the vb.net code. Again, I'm too far gone to suggest a real solution, but I recommend trying to pass an unaltered byte array to the .Net side, rather than a string.

Related

VB.Net and phpMyAdmin: How to connect to phpMyAdmin SQL server without needing a Username or Password?

I'm setting up a Login Form on Visual Basic .Net. I would like to have this database hosted over the internet, so people can connect wherever they are.
The trouble is, security. If I have a username and password in my code, I can easily be hacked, and my program will be cracked.
Is there any way to have a token that I can use instead of a password, that can only be accessed in through the program itself?
This is my code:
Dim connection As New MySqlConnection("datasource=localhost;port-3306;username;whatever;password=whatever;database=whatever")
And this is something like what I'm looking for:
Dim connection As New MySqlConnection("token=aFjiwqMF93JmHSazhH")
If so, how would I do this, and where would I get the database token and link from?
Anyone able to crack your program, will more likely have the knowledge to crack into MySQL too... I know, it's not an answer, I spent many weeks trying to secure my programs against similar, however, I then thought 'Why...?'
That being said, If you really need to keep your source code under wraps and passwords removed, how about loading the connection string from a text file somewhere?
Simple encryption see system.security.cryptography
I have just looked up my old code for encrypting strings simply, you can have a look at this
Imports System.Security.Cryptography
Imports System.Net
Public NotInheritable Class Encryptorr
Public TDS As New TripleDESCryptoServiceProvider
Private Function EncHash(ByVal key As String, ByVal length As Integer) As Byte()
Dim enc_Sha1 As New SHA1CryptoServiceProvider
Dim keyBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(key)
Dim hash() As Byte = enc_Sha1.ComputeHash(keyBytes)
ReDim Preserve hash(length - 1)
Return hash
End Function
Sub New(ByVal key As String)
TDS.Key = EncHash(key, TDS.KeySize \ 8)
TDS.IV = EncHash("", TDS.BlockSize \ 8)
End Sub
Public Function EncryptData(ByVal plaintext As String) As String
Dim Strbytes() As Byte = System.Text.Encoding.Unicode.GetBytes(plaintext)
Dim memStr As New System.IO.MemoryStream
Dim encStream As New CryptoStream(memStr, TDS.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
encStream.Write(Strbytes, 0, Strbytes.Length)
encStream.FlushFinalBlock()
Return Convert.ToBase64String(memStr.ToArray)
End Function
Public Function DecryptData(ByVal encryptedtext As String) As String
Try
Dim enc_Bytes() As Byte = Convert.FromBase64String(encryptedtext)
Dim mem_Str As New System.IO.MemoryStream
Dim decStream As New CryptoStream(mem_Str, TDS.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
decStream.Write(enc_Bytes, 0, enc_Bytes.Length)
decStream.FlushFinalBlock()
Return System.Text.Encoding.Unicode.GetString(mem_Str.ToArray)
Catch ex As Exception
Return "Decryption Failed"
End Try
End Function
End Class
Call with
Public Sub TestMe()
Dim encr As Encryptorr = New Encryptorr("AlovelyLong463728KeytoEncryptwith")
Dim encrytedstr As String = encr.EncryptData(textbox1.text)
Textbox2.text = encrytedstr
Dim decry As Encryptorr = New Encryptorr("AlovelyLong463728KeytoEncryptwith")
Dim decryptedtext As String = decry.DecryptData(Textbox2.text)
Textbox3.text = decryptedtext
End Sub
You can then encrypt and decrypt strings read from text files, although back to my original point. If someone can gain access to the program code, they can also work out the decryption too... :(
Still food for thought! Good luck
Update--
Just to add, you could always create the encrytped string, use that as a global variable and the decryt function to pass directly as your connection string. This means isnstead of saving the username and password in a text file, you just use Public Shared Constr as String = fhdasjifhn32437289cj (or whatever the encrypted string is) and the connection would be Dim Con as MySQLConnection = new MySQLConnection(DecryptMyStr(Constr)) with DecryptMyStr being the decrypt function

VB.net add a header/footer to every page of a PDF using iText7

I am trying to create a PDF with a header and footer. Both header and foot are images. Since my pdf creates a random amount of pages I need to automaticly add it to every page. I know I need to use some sort of eventhandler. Unfortunately I can't find any examples in the vb.net language, I only can find java/C# examples and I am really bad at reading/converting these language to vb.net. I am not a expert yet at programming.
Can anyone point me in the right direction.
Edit4: Removed random stuff no longer need to answer my question.
This piece of code below is all I got on creating the PDF itself.
Imports System.IO
Imports MySql.Data.MySqlClient
Imports iText.Kernel
Imports iText.Kernel.Pdf
Imports iText.Kernel.Font
Imports iText.Kernel.Font.PdfFont
Imports iText.Kernel.Font.PdfFontFactory
Imports iText.IO.Image
Imports iText.IO.Image.ImageData
Imports iText.IO.Image.ImageDataFactory
Imports iText.Layout.Element.Image
Imports iText.Layout
Imports iText.Layout.Element
Imports iText.Layout.Element.Table
Imports iText.Kernel.Events.Event
Imports iText.Kernel.Events.PdfDocumentEvent
Imports iText.Kernel.Geom.PageSize
Imports iText.Kernel.Geom.Rectangle
Imports iText.Kernel.Pdf.PdfDocument
Imports iText.Kernel.Pdf.PdfNumber
Imports iText.Kernel.Pdf.PdfWriter
Imports iText.Kernel.Pdf.Canvas.PdfCanvas
Imports iText.Kernel.Pdf.Canvas.PdfCanvasConstants
Imports iText.Kernel.Pdf.Xobject.PdfFormXObject
Imports iText.Layout.Canvas
Imports iText.Layout.Document
Imports iText.Layout.Style
Imports iText.Layout.Layout.LayoutArea
Imports iText.Layout.Layout.LayoutContext
Imports iText.Layout.Layout.LayoutResult
Imports iText.Layout.Renderer.CellRenderer
Imports iText.Layout.Renderer.DrawContext
Imports iText.Layout.Renderer.TableRenderer
Imports iText.Signatures.PdfSignatureAppearance
Public Sub NewiText7PdfCreation()
'Dim dest As String = "\\test\verkoop\offerte v2\Offerte " & offertenummer2 & "-" & offertenummer & " " & TextBox2.Text & ".pdf"
Dim dest As String = "iText7Test.pdf"
Dim writer As PdfWriter = New PdfWriter(dest)
Dim pdf As PdfDocument = New PdfDocument(writer)
Dim doc As Document = New Document(pdf)
Dim font As PdfFont = PdfFontFactory.CreateFont("C:\Windows\Fonts\calibri.ttf")
'header
Dim headerlocation As String = "Resources\Offerte-NL.png"
Dim headerimage2 As Image = New Image(ImageDataFactory.Create(headerlocation))
doc.Add(headerimage2)
'klant gegevens
doc.Add(New Paragraph("Debiteur gegevens").SetFont(font))
Dim debnr As String = TextBox1.Text
Dim bn As String = TextBox2.Text
Dim adr As String = TextBox3.Text
Dim pcwp As String = TextBox4.Text
Dim cp As String = TextBox5.Text
Dim km As String = TextBox6.Text
Dim klanttable As New Table(2)
klanttable.SetMaxWidth(350)
klanttable.SetHorizontalAlignment(0)
klanttable.SetFont(font)
klanttable.SetFontSize(8)
klanttable.SetWidth(350)
klanttable.SetMinWidth(120)
klanttable.AddCell("Debiteur nr.: ")
klanttable.AddCell(debnr)
klanttable.AddCell("(Bedrijfs)naam:")
klanttable.AddCell(bn)
klanttable.AddCell("Adres:")
klanttable.AddCell(adr)
klanttable.AddCell("Postcode & woonplaats:")
klanttable.AddCell(pcwp)
klanttable.AddCell("Contactpersoon:")
klanttable.AddCell(cp)
klanttable.AddCell("Kenmerk:")
klanttable.AddCell(km)
Dim cell As New Cell
klanttable.SetMarginTop(10)
klanttable.SetMarginBottom(10)
doc.Add(klanttable)
doc.Close()
End Sub
Edit:
Found a nice tutorial on the iText website.
https://developers.itextpdf.com/content/itext-7-jump-start-tutorial-net/chapter-3-using-renderers-and-event-handlers
I just don't quite get how to insert that piece of code into my own piece of code. I think I need to create a new class that handles the event.
But how do I need to call this event.
I just add the follow line to my code:
Implements IEventHandler
And this new sub.
Public Sub HandleEvent([event] As [Event]) Implements IEventHandler.HandleEvent
Throw New NotImplementedException()
End Sub
How do I adjust the sub to handle the page-start event and page-end event ( if it's even still called that way)
Edit: I just imported all the stuff just to be sure I got everything. When everything is working fine I am just gonna remove everything not being used.
With some efforts, I could implement PAGE_END event in vb.net. Here is the code for you.
(A) In main module create pdf routine add:
*Dim HandlerRLA = New VariableHeaderEventHandlerRLA
PDFfile.AddEventHandler(PdfDocumentEvent.END_PAGE, HandlerRLA)*
(B) Add anlother class after End Class. You may add text/paragraph as per requirement. I have used image as Header and Footer on specific pages.
Public Class VariableHeaderEventHandlerRLA
Implements IEventHandler
Dim header As String
Dim doc As PdfDocument
Public Sub TextFooterEventHandler(ByRef doc As PdfDocument)
Me.doc = doc
End Sub
Public Sub HandleEvent([event2] As [Event]) Implements IEventHandler.HandleEvent
Dim docEvent1 As PdfDocumentEvent = event2
Dim canvas1 As PdfCanvas = New PdfCanvas(docEvent1.GetPage())
Dim pageSize1 As iText.Kernel.Geom.Rectangle = docEvent1.GetPage().GetPageSize()
'Dim canvas As Canvas = New Canvas(docEvent.GetPage(), New iText.Kernel.Geom.Rectangle(0, 0, pageSize.GetWidth(), pageSize.GetHeight))
Dim PDoc1 As PdfDocument = docEvent1.GetDocument()
Dim Page1 = docEvent1.GetPage()
Dim PageNo1 As Integer = PDoc1.GetPageNumber(Page1)
If PageNo1 > 1 Then
Dim imageFile, BottomImage As String
imageFile = "path to image folder\secondtop.bmp"
Dim data3 = ImageDataFactory.Create(imageFile)
BottomImage = "path to image folder\secondbottom2.bmp"
Dim data4 = ImageDataFactory.Create(BottomImage)
Dim Ratio = data3.GetHeight / data3.GetWidth
Dim rect As iText.Kernel.Geom.Rectangle = New iText.Kernel.Geom.Rectangle(0, 784, 595, 595 * Ratio)
With canvas1
.AddImage(data3, 0, 784, 595, 0)
'.AddImageFittedIntoRectangle(data3, rect, 0)
Ratio = data4.GetHeight / data4.GetWidth
rect = New iText.Kernel.Geom.Rectangle(0, 0, 595, 595 * Ratio)
'.AddImageFittedIntoRectangle(data4, rect, 0)
.AddImage(data4, 0, 0, 595, 0)
End With
End If
'Throw New NotImplementedException()
End Sub
End Class

How to zip the folders and its sub-folders in vb.net 2.0?

I have folder in the name of Main1. And inside that folders, i have multiple folders. Like
Folders1
Folders2
Folders3
Folders4
Each folders have their own files. My requirement is to zip "Main1" folder including all the sub-folders and their files.
I dont want to use any third part tools. I'm planning to use namespace System.Compression with Gzip. Please guys advice.
ZipFile.CreateFromDirectory() can easily do this for you. Just pass it the path of your Day1 folder and it will zip the entire folder to a zip file. You can iterate over all the Day folders using System.IO.Directory class.
(Just realized that you want to stick to .NET Fx 2.0. There is no direct way of doing this in that version. You must either use 3rd-party lib, which you don't want to, or do low-level stuff).
Edit
If you're really inclined towards doing it by hand, here is a crude way:
Get the list of all directories (recursive) in your Day directory; call it DirList.
Get the list of all files (recursive) in your Day directory; call it FilesList.
Create a Dictionary(Of String, String) and store the name of each file in FilesList and the BASE64 representation of its contents; name as Key, content as Value.
Save the Dictionary to an XML file using .NET's built-in XML serialization.
At the very start of the file, inject the contents of DirList.
Save the file again. (you could do steps 4-6 in a single step too).
Read this file as binary and use GZip to compress the entire content.
Write it to a zip file.
To uncompress this file:
Open the file and use GZip to decompress and get your entire content.
Grab the list of directories from the top and create all recursively.
Read the remaining section in its entirety and use XML Serialization to create your Dictionary object from it.
Iterate through the Dictionary and create files using the Key part and then inject contents into the files by converting their Value from BASE64 back to binary.
Let me know if you have questions about any of these steps.
Edit 2
The following code is compiled against .NET 2.0 and will compress and decompress a directory:
Public Function ZipDirectory(DirPath As String) As Byte()
If Not Directory.Exists(DirPath) Then Return Nothing
Dim Directories = Directory.GetDirectories(DirPath, "*", SearchOption.AllDirectories)
Dim Files = Directory.GetFiles(DirPath, "*", SearchOption.AllDirectories)
Dim X As New XmlDocument
Dim RootNode = X.CreateElement("Content")
Dim DirsNode = X.CreateElement("Directories")
Dim FilesNode = X.CreateElement("Directories")
X.AppendChild(RootNode)
RootNode.AppendChild(DirsNode)
RootNode.AppendChild(FilesNode)
For Each d In Directories
Dim DirNode = X.CreateElement("Directory")
Dim PathAttrib = X.CreateAttribute("Path")
PathAttrib.Value = d.Replace(DirPath & "\", "") 'Create relative paths
DirNode.Attributes.Append(PathAttrib)
DirsNode.AppendChild(DirNode)
Next
For Each f In Files
Dim FileNode = X.CreateElement("File")
Dim PathAttrib = X.CreateAttribute("Path")
PathAttrib.Value = f.Replace(DirPath & "\", "") 'Create relative paths
FileNode.Attributes.Append(PathAttrib)
FileNode.InnerText = Convert.ToBase64String(File.ReadAllBytes(f))
FilesNode.AppendChild(FileNode)
Next
Using Mem As New MemoryStream()
X.Save(Mem)
Dim AllContentsAsByteArray = Mem.ToArray()
Dim CompressedContent = CompressArray(AllContentsAsByteArray)
Return CompressedContent
End Using
End Function
Public Sub UnzipDirectory(compressed() As Byte, outputPath As String)
If Not Directory.Exists(outputPath) Then Directory.CreateDirectory(outputPath)
Dim Uncompressed = DecompressArray(Compressed)
Dim X As New XmlDocument
Using Mem As New MemoryStream(Uncompressed)
X.Load(Mem)
Dim RootNode = X.FirstChild
Dim DirsNode = RootNode.FirstChild
Dim FilesNode = RootNode.FirstChild.NextSibling
For Each ChildDir In DirsNode.ChildNodes
Directory.CreateDirectory(Path.Combine(outputPath, DirectCast(ChildDir, XmlNode).Attributes.Item(0).Value))
Next
For Each ChildFile In FilesNode.ChildNodes
Dim FilePath = Path.Combine(outputPath, DirectCast(ChildFile, XmlNode).Attributes.Item(0).Value)
Dim Content = Convert.FromBase64String(DirectCast(ChildFile, XmlNode).InnerText)
File.WriteAllBytes(FilePath, Content)
Next
End Using
End Sub
Private Function CompressArray(ByVal content() As Byte) As Byte()
Using outFile As New MemoryStream()
Using Compress As New GZipStream(outFile, CompressionMode.Compress)
Compress.Write(content, 0, content.Length)
End Using
Return outFile.ToArray()
End Using
End Function
Private Function DecompressArray(ByVal content() As Byte) As Byte()
Using outFile As New MemoryStream()
Using inFile As New MemoryStream(content)
Using Compress As New GZipStream(inFile, CompressionMode.Decompress)
Dim buffer(1023) As Byte
Dim nRead As Integer
Do
nRead = Compress.Read(buffer, 0, buffer.Length)
outFile.Write(buffer, 0, nRead)
Loop While nRead > 0
End Using
End Using
Return outFile.ToArray()
End Using
End Function
The code should be used like this:
'To zip a directory
Dim Compressed = ZipDirectory("C:\SomeDir")
File.WriteAllBytes("C:\somedir.zip", Compressed)
'To unzip a zipped file
Dim Compressed = File.ReadAllBytes("C:\somedir.zip")
UnzipDirectory(Compressed, "C:\SomeDir2")
Below code is using System.IO.Compression
Example from MSDN site:
Link
Imports System
Imports System.Collections.Generic
imports System.IO
imports System.IO.Compression
Public Class CompressionSnippet
Public Shared Sub Main()
Dim path As String = "test.txt"
' Create the text file if it doesn't already exist.
If Not File.Exists(path) Then
Console.WriteLine("Creating a new test.txt file")
Dim text() As String = {"This is a test text file.", _
"This file will be compressed and written to the disk.", _
"Once the file is written, it can be decompressed", _
"imports various compression tools.", _
"The GZipStream and DeflateStream class use the same", _
"compression algorithms, the primary difference is that", _
"the GZipStream class includes a cyclic redundancy check", _
"that can be useful for detecting data corruption.", _
"One other side note: both the GZipStream and DeflateStream", _
"classes operate on streams as opposed to file-based", _
"compression data is read on a byte-by-byte basis, so it", _
"is not possible to perform multiple passes to determine the", _
"best compression method. Already compressed data can actually", _
"increase in size if compressed with these classes."}
File.WriteAllLines(path, text)
End If
Console.WriteLine("Contents of {0}", path)
Console.WriteLine(File.ReadAllText(path))
CompressFile(path)
Console.WriteLine()
UncompressFile(path + ".gz")
Console.WriteLine()
Console.WriteLine("Contents of {0}", path + ".gz.txt")
Console.WriteLine(File.ReadAllText(path + ".gz.txt"))
End Sub
Public Shared Sub CompressFile(ByVal path As String)
Dim sourceFile As FileStream = File.OpenRead(path)
Dim destinationFile As FileStream = File.Create(path + ".gz")
Dim buffer(sourceFile.Length) As Byte
sourceFile.Read(Buffer, 0, Buffer.Length)
Using output As New GZipStream(destinationFile, _
CompressionMode.Compress)
Console.WriteLine("Compressing {0} to {1}.", sourceFile.Name, _
destinationFile.Name, False)
output.Write(buffer, 0, buffer.Length)
End Using
' Close the files.
sourceFile.Close()
destinationFile.Close()
End Sub
Public Shared Sub UncompressFile(ByVal path As String)
Dim sourceFile As FileStream = File.OpenRead(path)
Dim destinationFile As FileStream = File.Create(path + ".txt")
' Because the uncompressed size of the file is unknown,
' we are imports an arbitrary buffer size.
Dim buffer(4096) As Byte
Dim n As Integer
Using input As New GZipStream(sourceFile, _
CompressionMode.Decompress, False)
Console.WriteLine("Decompressing {0} to {1}.", sourceFile.Name, _
destinationFile.Name)
n = input.Read(buffer, 0, buffer.Length)
destinationFile.Write(buffer, 0, n)
End Using
' Close the files.
sourceFile.Close()
destinationFile.Close()
End Sub
End Class
Truly you would be better off using SharpLibZip

zlib.net 2 files with the same lengt resulting in 2 different final lenght after compressing

is it normal for 2 files with the same length to have different lenghts after compressing there bytes using zlib.net on vb.net?
this is the compression module i use using zlib.net reference, the 2 files are almose the same, there are juste less than 100 bytes making the difference between them
Imports System.IO
Imports zlib
Module zlib_compression
Public Sub CopyStream(ByRef input As System.IO.Stream, ByRef output As System.IO.Stream)
Dim num1 As Integer
Dim buffer1 As Byte() = New Byte(2000 - 1) {}
num1 = input.Read(buffer1, 0, 2000)
Do While (num1 > 0)
output.Write(buffer1, 0, num1)
num1 = input.Read(buffer1, 0, 2000)
Loop
output.Flush()
End Sub
Public Function Compress(ByVal InputBytes As Byte()) As Byte()
Using output As New MemoryStream
Dim outZStream As Stream = New ZOutputStream(output, zlib.zlibConst.Z_BEST_SPEED)
Using input As Stream = New MemoryStream(InputBytes)
CopyStream(input, outZStream)
outZStream.Close() 'do not remove
Return output.ToArray()
End Using
End Using
End Function
Public Function Decompress(ByVal InputBytes As Byte()) As Byte()
Using output As New MemoryStream
Using outZStream As Stream = New ZOutputStream(output)
Using input As Stream = New MemoryStream(InputBytes)
CopyStream(input, outZStream)
Return output.ToArray()
End Using
End Using
End Using
End Function
End Module
Of course, yes. In fact it is necessarily true. It is not possible to losslessly compress all of the same length files to a smaller size, since there are not enough bits in the smaller size to identify all of the original files. If some are compressed, then some must be expanded.

Get Result of Private Property TcpClient.BeginConnect, IAsyncResult in VB.NET

I have an application in VB.NET When I run the application in Visual Studio 2010 and mouseover an IAsyncResult, I see the protected property Result. I would like to read the value of the property in the application. How can I do that?
Imports System.Net
Imports System.Net.Sockets
...
Friend Function StartSendGo() As String
'Declarations
Dim strSendMachineName As String = "DEV001"
Dim intSendPort As Integer = 50035
Dim socketclient As New System.Net.Sockets.TcpClient()
Dim rslt As IAsyncResult = tcpClient.BeginConnect(strSendMachineName, intSendPort, New AsyncCallback(AddressOf ConnectCallback), socketclient)
Dim blnSuccess = rslt.AsyncWaitHandle.WaitOne(intTimeOutConnect, True)
'HERE is where I need rslt.Result.Message
End Function
Public Function ConnectCallback()
'Placeholder
End Function
When I mouseover rslt, VS shows that it is of type
System.Net.Sockets.Socket+MultipleAddressConnectAsyncResult I have never seen a plus (+) in a type before, and I am not able to declare a variable of that type. If I expand the properties, there is a protected property Result, which has a property Message with a value of "No connection could be made because the target machine actively refused it 192.0.0.10:50035". I need access to that message. I would also like to access addresses, but that is less important.
I found a solution - to use Reflection to read the value of the private property.
'Imports
Imports System.Reflection
'Call functions that write to rslt
rslt = tcpClient.BeginConnect(strSendMachineName, intSendPort, New AsyncCallback(AddressOf ConnectCallback), socketclient)
blnSuccess = rslt.AsyncWaitHandle.WaitOne(intTimeOutConnect, True)
'Use Reflection
'Get Type
Dim myType As Type = rslt.GetType()
'Get properties
Dim myPropertyInfo As PropertyInfo() = myType.GetProperties((BindingFlags.NonPublic Or BindingFlags.Instance))
'The order of the properties is not guaranteed. Find by name.
For Each pi As PropertyInfo In myPropertyInfo
If pi.Name = "Result" Then
'TODO Add check for nothing.
'Assign to Exception-type variable.
exException = pi.GetValue(rslt, Nothing)
End If
Next