UInt32 to Int32 - vb.net

If I have a VB.Net function that returns an Int32, but uses an unsigned int (UInt32) for calculations, etc. How can I convert a variable "MyUintVar32" with a value of say "3392918397 into a standard Int32 in VB.Net?
In c# if I just do a "return (int)(MyUintVar32);", I get -902048899, not an error.
I've tried several different methods. What is the difference in the way c# handles these conversions versus VB.Net?

I realize this is an old post, but the question has not been answered. Other people my want to know:
Dim myUInt32 As UInt32 = 3392918397
Dim myInt32 As Int32 = Convert.ToInt32(myUInt32.ToString("X"), 16)
the reverse operation:
myUInt32 = Convert.ToUInt32(myInt32.ToString("X"), 16)
Also, one can create a union structure to easily convert between Int32 and UInt32:
Imports System.Runtime.InteropServices
<StructLayout(LayoutKind.Explicit)> _
Public Structure UnionInt32
<FieldOffset(0)> _
Public IntValue As Int32
<FieldOffset(0)> _
Public UIntValue As UInt32
End Structure
Dim MyUnionInt32 as UnionInt32
MyUnionInt32.UIntValue = 3392918397
Dim IntVal as Int32 = MyUnionInt32.UIntValue '= -902048899
the reverse operation:
MyUnionInt32.IntValue = -902048000
Dim UIntVal as UInt32 = MyUnionInt32.UIntValue '= 3392919296
Cheers, TENware

3392918397 is too big to fit into a signed 32-bit integer, that's why it is coming out negative, because the most significant bit of 3392918397 is set.
1100 1010 0011 1011 1101 0011 0111 1101
If you want to maintain integers of this proportion inside a signed integer type, you'll need to use the next size up, a 64-bit signed integer.

It's not an optimal solution, but you can use BitConverter to get a byte array from the uint and convert the byte array to int.
Dim myUInt32 As UInt32 = 3392918397
Dim myInt32 As Int32 = BitConverter.ToInt32(BitConverter.GetBytes(myUInt32), 0)

You can't convert 3392918397 into an Int32 since that number is too large to fit in 31 bits. Why not just change the function to return a UInt32?

Or after doing the Uint32 work check it against MAXINT and 0.
If > MAXINT and < 0 then you're ok. If not you "overflowed" and should throw an exception.
I don't remember if MAXINT is defined. You can use: 2^31 - 1 instead.

Related

VB.net Integer and Short conversion, GetMessagePos()

I am trying to use DWORD WINAPI GetMessagePos(void) function in VB.net.
The function returns a DWORD (32 bit) which can be stored in a VB.net integer variable. A quote from the MSDN doc:
The x-coordinate is in the low-order short of the return value; the
y-coordinate is in the high-order short (both represent signed values
because they can take negative values on systems with multiple
monitors)
How can I retrieve x and y coordinates using vb.net?
I am currently trying
<System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling:=True)>
Private Shared Function GetMessagePos() As Integer
End Function
Sub test()
Dim pos As Integer = GetMessagePos()
Try
Dim x As Short = CShort(pos And &HFFFF)
Dim y As Short = CShort(pos >> 16)
MessageBox.Show(x & ", " & y)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
but I am not sure if it is the right way to do it. I am trying to do some tests like
Try
Dim x As Short = -1
Dim y As Short = 1
Dim i As Int32 = (y << 16) Or x
Dim x2 As Short = CShort(i And &HFFFF)
Dim y2 As Short = CShort(i >> 16)
MessageBox.Show(x & ", " & y)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Basically I code x and y coordinates in Short (Int16) variables, put them together in a Int32 and then try to decode.
But it doesn't seem to work since it leads to an overflow.
Any ideas of how to decode the x-y coordinates from the GetMessagePos() WINAPI?
You have to be careful when you extract these values in order to ensure that they work properly on a multiple monitor system. The "standard" way of doing it, in terms of what you would normally use with the GetMessagePos function are the GET_X_LPARAM and GET_Y_LPARAM macros, defined in the Windows SDK headers. These are mentioned specifically in the GetMessagePos documentation, and there should be similar references in all documentation for functions that return packed coordinates. There is also a warning not to use the classic LOWORD or HIWORD macros because they treat the values as unsigned quantities, as you alluded to in the question.
So, the task is essentially to translate the GET_X_LPARAM and GET_Y_LPARAM macros from C to VB.NET. Translating them to C# is relatively simple because you can take advantage of the unchecked keyword:
int GetXValue(UInt32 lParam)
{
return unchecked((short)(long)lParam);
}
int GetYValue(UInt32 lParam)
{
return unchecked((short)((long)lParam >> 16));
}
But VB.NET doesn't have an equivalent for C#'s unchecked keyword, so you have to find some other way to avoid overflow. Personally, I write this kind of interop code in C# and stick it in a library so I can do what I find the most readable.
If you prefer to stick with VB.NET, there are a couple of ways to do it. The simplest conceptually is to manipulate the value as a UInt32 to avoid the overflow. For the x-coordinate in the lower bits, you will need to explicitly mask off the upper bits to avoid an overflow. For the y-coordinate, you'll need to shift and mask. Then you can convert back to a Short:
Public Function GetXValue(lParam As UInt32) As Short
Return CShort(lParam And &HFFFF)
End Function
Public Function GetYValue(lParam As UInt32) As Short
Return CShort((lParam >> 16) And &HFFFF)
End Function
Another alternative is a bit more clever, perhaps too clever, but probably more efficient. It involves declaring the equivalent of a C-style union, which in VB.NET terms is just a Structure whose fields overlap:
<StructLayout(LayoutKind.Explicit)> _
Public Structure CoordUnion
<FieldOffset(0)> Public LParam As UInt32
<FieldOffset(0)> Public XCoord As Short
<FieldOffset(2)> Public YCoord As Short
Public Sub New(lParam As UInt32)
LParam = lParam
End Sub
End Structure
Then you can use it like this:
Dim temp As CoordUnion = New CoordUnion(GetMessagePos())
Dim pt As Point = New Point(temp.XCoord, temp.YCoord)
' ...
Note, also, that I've implicitly changed the P/Invoke signature for GetMessagePos so that it returns a UInt32:
<System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling:=True)>
Private Shared Function GetMessagePos() As UInt32
End Function
You could have just as easily used the IntPtr type throughout all of these helper/conversion functions as the UInt32 type. In fact, that's how you would normally write it, since you usually get these pointer coordinates packed into an lParam value as part of a window message (e.g., when overriding the WndProc method of a control).

Visual Basic.Net Converting a Long to a Ulong

I am having issues using VB.Net trying to convert a Long to a ULong.
I have tried many combinations and keep getting overflow errors.
I have a signed value of -2147483648, I know it will have a Ulong of 2151196588 once converted.
However I want to do this in a programmatic fashion because I am parsing values that can be negative and positive, but when the numbers are negative, they need to have the proper ulong value.
Note: Absolute values wont work, it needs to be a ulong for a true value.
Thank you.
If you mean reinterpret_cast<ulong>(long), then use the same technique:
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Explicit)> _
Public Structure LongULongUnion
<Runtime.InteropServices.FieldOffset(0)> Public l As Long
<Runtime.InteropServices.FieldOffset(0)> Public ul As ULong
End Structure
Sub Main()
Dim u As LongULongUnion
u.l = -2147483648L
Console.WriteLine(u.ul)
Console.ReadLine()
End Sub
But that gives 18446744071562067968 when converted.
You can use the BitConverter class:
Dim a As Int64 = -2147483648
Dim b = BitConverter.ToUInt64(BitConverter.GetBytes(a), 0)
Console.WriteLine(b.ToString) ' outputs: 18446744071562067968
Are you sure your intended value of 2151196588 is correct?
This is the easiest way to convert any Long to ULong:
Dim x As Long = -2147483648
Dim y As ULong = Not (CType((Not x), ULong)) ' = 18446744071562067968
I'm a C# programmer, so please correct me if I converted it to VB.NET incorrectly. My C# code was:
long x = -2147483648;
ulong y = ~((ulong)~x); // = 18446744071562067968
Basically you take the complement of the negative value, which is always a positive value. You can then safely cast it to ULong. Take the complement again and you have the same bit pattern cast to ULong.
Make sure you are converting your value to positive BEFORE you convert it to ulong, negatives are not in a ulong's value scope.
long: -9223372036854775808 to 9223372036854775807
ulong: 0 to 18446744073709551615

VB.Net - Converting multi-byte hex values to decimal

How would I convert the two individual byte values (in hex) to a decimal value representing the concatenated hex values? For example, if I have the
Dim byte1 As Byte = &H99
Dim byte2 As Byte = &H99
' I want the decimal representation of the hex value "9999"
' (byte1.ToString + byte2.ToString) which should be "39321"
Currently I use the following code:
Dim decVal as integer
decVal = Val("&H" + Hex$(byte1).ToString + Hex$(byte2).ToString)
However, when I use this, the value (decVal) comes out to "-26215"
What am I doing wrong in the conversion here?
Try the following:
decVal = byte1 * 256 + byte2
Your problem is when you call Val("&H9999"), if you use CInt("&H9999") or Integer.Parse("9999", System.Globalization.NumberStyles.HexNumber) you would get the correct answer (in this case at least)
If you look at the output from:
decVal = Val("&H9999")
Console.WriteLine(decVal.ToString("X"))
you get FFFF9999
I'm not sure why this is happening, but I would see this as a reason not to use the Val function to parse hexadecimal strings
#Patrick McDonald has a good inline way of doing it and if that's what you're looking for then I recommend using that. But I can't resist not giving you the overly complicated but cross-platform and expanded versions. One thing to note, you are asking to convert bytes in big-endian mode which is a very important topic to understand if you're playing with bytes.
Both functions below take a param array and perform conversions but in two different ways. One handles an arbitrarily large byte array (bound only by platform restrictions) and the other uses the built-in converter class that reads byte arrays.
Once again, let me stress the "overly complicated" part.
Private Shared Function ConvertBytes2(ByVal ParamArray bytes() As Byte) As UInt32
''//Reverse the array order
Dim NewBytes = bytes.Reverse().ToList().ToArray()
''//Our return value
Dim Dec As UInt32 = 0
''//Temporary value for bit shifting
Dim T As UInt32
''//Loop through the bytes from left to right
For I = (NewBytes.Count - 1) To 0 Step -1
''//Grab the byte
T = NewBytes(I)
''//Shift it and add to our return value
Dec += T << (8 * I)
Next
Return Dec
End Function
Private Shared Function ConvertBytes1(ByVal ParamArray bytes() As Byte) As UInt32
''//We want to read the bytes in big-endian order but BitConverter works in little-endian mode on most Windows systems (but not all) so convert if needed
Dim NewBytes() As Byte
If BitConverter.IsLittleEndian Then
NewBytes = bytes.Reverse().ToList().ToArray()
Else
NewBytes = bytes
End If
''//Our return value
Dim Dec As UInt32
''//BitConverter can return UIn16, 32 or 64, we're only supporting 16 and 32 below
If NewBytes.Count = 2 Then
Dec = BitConverter.ToUInt16(NewBytes, 0)
ElseIf NewBytes.Count = 4 Then
Dec = BitConverter.ToUInt32(NewBytes, 0)
Else
''//Invalid number of bytes sent
Throw New ArgumentOutOfRangeException("bytes")
End If
Return Dec
End Function
Dim Byte1 As Byte = &HA
Dim Byte2 As Byte = &H99
''//&h0A99 = 2,713
Trace.WriteLine(ConvertBytes1(Byte1, Byte2))
Trace.WriteLine(ConvertBytes2(Byte1, Byte2))

How to pass integer as unsigned parameter in VB.NET?

I'm using a library call, setInstance(ByVal instance As UInteger), in my VB.NET code. The parameter I need to pass is an Integer. Is there anything I need to do to convert the integer parameter to an unsigned integer? The number is guaranteed to be positive and less than 10.
Like so...
Dim MyInt As Int32 = 10
Dim MyUInt As UInt32 = CUInt(MyInt)
setInstance(MyUInt)
CUInt or CType(x, UInt) allow converting a positive integer.
It throws an exception when x is negative.
To use Int as Uint, you can use some tricks:
dim bb() = System.BitConverter.GetBytes(myInt)
dim MyUint = System.BitConverter.ToUInt32(bb, 0)
Also with System.Buffer.BlockCopy for arrays.
If you configure the compiler to disable Check Integer Overflow (default for C#). Then you can use CUInt with negative values with no check - not exception.
You can call CUint to convert a variable to a UInteger.

bit pack Int16 into a Ushort VB.net

I have to pack and unpack a 16bit Int from/into a Ushort in VB.net
This is how I thought I could do it (doesn't work, gives me overflow exception)
'Pack Int16 into ushort '
Dim usPacked = CType(Data, UShort)
'unpack Int16 from ushort '
Dim unpacked = CType(data,Int16)
Thanks!
You can use the old Union solution
<StructLayout(Runtime.InteropServices.LayoutKind.Explicit)> _
Structure s1
<FieldOffset(0)> Public AsShort As Short
<FieldOffset(0)> Public AsUShort As UShort
End Structure
Dim v1 = GetTheShortValue()
Dim v2 = new s1
v2.AsShort = v1
Dim v3 As UShort = v2.AsUShort
EDIT: Jared's answer is better than this one of mine :(
UShort can store integers from 0 through 65,535.
Short can store integers from -32,768 through 32,767.
Long can store integers from about -2 billion to +2 billion.
You'll get an overflow when you try to put negative numbers into a UShort, or when you try to put numbers over 32,767 into a Short. One solution is to use a Long as an intermediary.
'Pack Int16 into ushort '
Dim usPacked = CType(CLng(nData) + 32768, UShort)
'unpack Int16 from ushort '
Dim unpacked = CType(CLng(usPacked) - 32768, Int16)