String length with embeded null in vb.net - vb.net

I have a simple question: How vb.net determine string length and treat string's termination?
I know in C (and its family) null character is end of string. In vb6 null character has no effect on string's termination but in vb.net it seems to be foggy!
Assume this code in vb6:
Private Sub Command1_Click()
Dim Str As String
Str = "Death is a good user," & Chr(0) & " Yes I'm good"
RichTextBox1.Text = Str
RichTextBox1.Text = RichTextBox1.Text & vbNewLine & Len(Str)
End Sub
This what happens when this code runs:
And it's alright. This is similar code in C:
#include "stdafx.h"
#include <string.h>
int main(int argc, char* argv[])
{
char *p="Death is a good user,\0 Yes I'm good";
printf("String:%s\nString length:%d\n",p,strlen(p));
return 0;
}
And this is what happens:
Which is fine too according C rules, but here is the same code in vb.net:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim str As String = "Death is a good user," & Chr(0) & " Yes I'm good"
RichTextBox1.Text = str
RichTextBox1.Text &= vbNewLine & str.Length
End Sub
And what happens:
Which doesn't seems about right!
Edit 1: Writing to file seems to be right:
Edit 2: Mark and tcarvin suggest, it may be UI's problem but it doesn't explain why vb6 shows whole string!
Edit 3: I know Windows and its API,UI,... are written in C, So it would be normal for them to react like C, but as I showed above, they don't.

In VB.NET (and C#) strings are treated very similarly to how they are in VB6, and that is they have an explicit length that is not based on any particular character or characters contained within them.
In regards to the RichTextBox, it would simply appear that it does not support an embedded null character.

There are 3 distinct string types used in your snippets by the underlying runtime support libraries:
BSTR, used by VB6. It is an COM Automation type used by all ActiveX controls that can store a Unicode string and includes an explicit length. BSTR can therefore store embedded zeros.
C strings, used by the C language. No explicit length is stored, a zero indicates end-of-string. The winapi is C based and uses C strings in its functions.
System.String, the .NET string type and used in any .NET code. Similar to a BSTR, it also has an explicit length field and can thus store strings with embedded zeros.
In all three cases interop needs to be used by the underlying runtime support libraries to make the string visible:
VB6 uses an ActiveX control for the RichEditBox. Exactly what the control looks like is hard to guess, it is pretty specific to VB6 and is named richtx32.ocx. It does use the native Windows richedit control as well (riched32.dll) so the ActiveX control very much acts as a wrapper to make the native Windows control usable in a VB6 app. You've conclusively demonstrated that it honors the behavior of a BSTR and handles embedded zeros, like any ActiveX control should.
The C program uses the C Runtime Library which in turn implements printf() by calling a winapi console function, WriteConsole(). This api function is C based but the buck already stopped at printf(), an embedded zero is a string terminator for that function. No surprises here.
The Winforms program uses the .NET RichEditBox class, a managed wrapper for the riched20.dll native Windows control. The underlying mechanism is pinvoke, almost all properties and methods of the class are implemented by pinvoking SendMessage() to send messages like EM_SETTEXTEX, the message that alters the text displayed by the control. This is also a C based api, a zero acts like a string terminator. Unlike the richtx32.ocx wrapper, the .NET RichEditBox wrapper class does not make an effort to properly handle strings with embedded zeros. It simply passes the string as-is and leaves it up to the pinvoke marshaller to convert the .NET string to a C string. Which has no other option than to truncate the string at the zero since C strings don't have a length field.

Related

.NET COM usercontrol does not set font or language properly

I have created a COM VB.NET (v3.5 under VS2013) usercontrol which i have included in an old VB6 project. The control communicates with its VB6 host just fine. It works as expected, opens the DB, reads / writes stuff. Everything is OK except one thing, which i'm not sure what it is. It seems i cannot properly set either its font(?) or its language(?) to Greek in order to be able to type Greek characters in a contained textbox.
This usercontrol contains several other .NET controls. Listboxes, buttons and textboxes. I read stuff from DB, set the text property of all those controls to the contents of the database and Greek are shown properly. If i try to switch the O/S language to Greek and type something in a textbox, strange characters are shown instead of the proper Greek ones (i assume from another codepage). I have programmatically changed its font to "[Font: Name=Arial, Size=9, Units=3, GdiCharSet=161, GdiVerticalFont=False]". GdiCharSet=161 is Greek. It should work. And it does work from within the .NET environment or from a test .NET exe. I can type Greek in the textbox. When i try to use it from within the VB6 program, it seems switching to Greek and typing Greek chars is not possible. Loading Greek from DB and showing them is no problem though.
I have also tried setting GdiCharSet to 0, 1, 2 (yup, it did show Symbols as expected) and to change the culture in the usercontrol constructor but no luck:
System.Threading.Thread.CurrentThread.CurrentCulture = New System.Globalization.CultureInfo("el-GR")
System.Threading.Thread.CurrentThread.CurrentUICulture = New System.Globalization.CultureInfo("el-GR")
Any ideas someone, what to check / try?
Wow... After spending more hours than i could spare on this matter, i have finally found a solution.
Private Sub txtMessage_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtMessage.KeyPress
If InputLanguage.CurrentInputLanguage.Culture.Equals(New Globalization.CultureInfo("el-GR")) Then
FixKeyChar(e)
End If
End Sub
Public Sub FixKeyChar(ByRef e As KeyPressEventArgs)
Dim myUnicodeBytes As Byte() = Encoding.Unicode.GetBytes(e.KeyChar)
Dim myUTF32Bytes As Byte() = Encoding.Convert(Encoding.Default, Encoding.UTF32, myUnicodeBytes)
e.KeyChar = ChrW(myUTF32Bytes(1) * 256 + myUTF32Bytes(0))
End Sub
I hope it proves to be helpful for some other poor soul messing with these things...

Visual Studio 2013 Visual basic create and write text file

I'm new to programming, and I have one small question. I wrote a code to create a xml file with 5 lines and everything works like a charm. Now I have a textbox and I want the input from the box, named INPUT be written in the middle of one line. This is my code:
Private Sub Entry_Click(sender As Object, e As EventArgs) Handles Entry.Click
Dim data As String() = {
"<?xml version=""1.0"" encoding=""utf-8""?>",
"<EntryQue xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">",
"<NumberReq>0</NumberReq>",
"<TypeReq>7</TypeReq>",
"<Amount>", INPUT.Text, "</Amount>",
}
File.WriteAllLines("C:/Prog/xml/DATA.xml", data)
The problem is that the INPUT is written in a new line, between amount and /amount, like this:
Amount
123456
/Amount
How can I put it in the same line...for example Amount123456/Amount ?
Your array of string is delimited by commas, so each comma indicates a new line in the output file. Instead of this:
"<Amount>", INPUT.Text, "</Amount>"
Do this:
"<Amount>" & INPUT.Text & "</Amount>"
For details on the string concatenation operators (there are two), see here. I use the & operator because you are concatenating mixed data type (numeric & string):
https://msdn.microsoft.com/en-us/library/te2585xw.aspx
The + Operator (Visual Basic) has the primary purpose of adding two numbers. However, it can also concatenate numeric operands with string operands. The + operator has a complex set of rules that determine whether to add, concatenate, signal a compiler error, or throw a run-time InvalidCastException exception
The & Operator (Visual Basic) is defined only for String operands, and
it always widens its operands to String, regardless of the setting of
Option Strict. The & operator is recommended for string concatenation
because it is defined exclusively for strings and reduces your chances
of generating an unintended conversion.

Conversion of VB Variable Types

I'm experimenting with learning how conversions work between variable types. Right now, I'm looking at using one conversion inside a Try/Catch (for values that can't convert). Is there a way to have a string representation of a value (obtained from a TextBox), convert it to a test type, and then see how that converts to all the other VB standard types in a loop? Or even better if there is a resource that already does this.
I can do this, but the code is very close to being repetitive and I'm hoping for a loop of some kind to simplify and shorten it.
First of all, there is no such thing as variable type in VB.net. May be you confusing with object variables - but this is not the same thing
Dim o As Object
o = 1 ' integer
The type that is stored in o is still integer. It is boxed.
Dim i As Integer = CInt(o)
You just un-boxed it. It works because object is lowest of types and all other derive from it. So, it can "box" any other type.
In UI we use text boxes to collect data. Text boxes can contain only string. And unless you writing these strings to a file like txt or xml you usually need to convert these strings to a type you use in application.
Dim port as Integer = Convert.ToInt32(txtPort.Text)
This is not really the area where you can determine, what type is in that text box. You really need to know upfront - what are you expecting there? You can test your text for being one type or another by using
Integer.TryParse
Date.TryParse
.....TryParse
.............
But the thing is, some data can successfully pass this test fro multiple types.
Good question. While it is possible to declare variables of type type and use them in a loop, these cannot be used in declarations or DirectCast.
Dim types() As Type = {GetType(Integer), GetType(Double)}
Dim testType As Type = GetType(Double)
The easiest way might be to test each value individually something like this (although you'll probably want a try-catch for each or all the items).
Dim xInteger As Integer
xInteger = TextBox1.Text
s &= "Integer: " & xInteger.ToString & vbcrlf ' or some test
Dim xDouble As Double
xDouble = TextBox1.Text
s &= "Double" & ": " & xDouble.ToString & vbcrlf
...

Accessing an object over class

When reading an old project of mine I found something suspicious where I don't really understand why this part is working:
Public Shared Sub getXMLforProject(QueryString As String)
Dim linkStart As String = "http://example.org"
Dim linkEnd As String = "&tempMax=2000"
Dim target As String = linkStart & QueryString & linkEnd
'replaces parts that need encoding,
'groups(1) is the sign e.g. <= and groups(2) is the text that needs encoding
'groups(0) is the text of the full match (sign and encoding text)
target = rx.Replace(target, Function(m As Match) encodeURLString(m.Groups(1).Value) + encodeURLString(m.Groups(2).Value))
GUI.WebBrowser.Navigate(target)
Return True
End Sub
the respective path that seams suspicious to me is the line
GUI.WebBrowser.Navigate(target)
There is a class called GUI that realises the user interface, but in the file context there is no objects named "GUI" available, so the access must be done by using the class. How is it possible for this to work? Is there an implicit mechanism that redirects the call from the GUI-class to the GUI-object?
You are using VB.NET, it emulates the behavior of the Form class from earlier Visual Basic editions where using the type name was a legal way to refer to an instance of the class. Kinda necessary to give programmers a fighting chance to convert their VB6 projects. Underlying plumbing is the My.Forms object.
So, 99.9% odds are that the GUI class derives from System.Windows.Forms.Form. Especially given that it has a WebBrowser member. The Form is the host window for the browser.

VB seems to lose newlines when called over COM

I have a VB method
Public Sub append_text(ByVal s As String)
f1.TextBox1.AppendText(s)
End Sub
which is called over COM from C++
_bstr_t b(L"test\nnew\nlines\n");
ATLENSURE_SUCCEEDED(t->append_text(b));
But the text box ends up saying
testnewlines
Without the aforementioned new lines.
Why is that then?
For the sake of completeness, posting my comment as an answer (now that I know it's correct...):
Different operating systems consider different character combinations as new lines. The *nixes, for instance, use a single \n, as in your code. Windows, on the other hand, uses the \r\n combination. Therefore, the single \n in your string just isn't enough to be considered a new line marker. Using \r\n will do the trick.
Eran is right.
To fix it on the VB side, try this
Dim s2 As String = s.Replace(vbLf, vbCrLf)
f1.TextBox1.AppendText(s2)
EDIT Sideshow Bob has compiled and tested this.