VB.NET Address Pointer - vb.net

I have a DLL with the following function and is being used in my application
WritetoBuffer(BYTE* pBuffer, DATA_TYPE Type);
This is the code being used in VB 6
Dim pBuffer() as byte
ReDim pBuffer(0 To (300 * 400 * 3 - 1))
Dim ppBuf As Long
ppBuf = VarPtr(pImageBuffer(0))
Dim Rtn As Integer
Rtn = WritetoBuffer(ppBuf, 1)
I am trying to write the equivalent code in VB.NET, but I am facing difficulties in it. Tried using the following function, but it's not working.
Public Function VarPtr(ByVal e As Object) As Intptr
Dim GC As GCHandle = GCHandle.Alloc(e, GCHandleType.Pinned)
Dim GC2 As Intptr = GC.AddrOfPinnedObject.ToInt32
GC.Free()
Return GC2
End Function
I haven't used Marshal Class or similar functions before and I am not sure about the right way to do it. Can someone please advice me on this?

As #Dai commented, .ToInt32 is incorrect here, and you can’t free the handle before you use it.
Dim pBuffer(300 * 400 * 3 - 1) As Byte
Dim pinned = GCHandle.Alloc(pBuffer, GCHandleType.Pinned)
Dim Rtn As Integer = WritetoBuffer(pinned.AddrOfPinnedObject(), 1)
pinned.Free()

Try this. You need GCHandle to stay alive while you make your call. Just returning the address of the pointer is not enough from what I understand. When you're done then free the handle.
Dim Handle As GCHandle = GCHandle.Alloc(pBuffer, GCHandleType.Pinned)
Dim ppbuf As IntPtr = Handle.AddrOfPinnedObject.ToInt32
Dim Rtn As Integer
Rtn = WritetoBuffer(ppbuf, 1)
Handle.Free()

In cases such as this you shouldn't need to get a pointer of your byte array. Due to the fact that since BYTE* pBuffer is used as an array, that is all you need it to be in VB.NET as well.
Thus you could declare your P/Invoke like this:
<DllImport("yourfile.dll")> _
Public Shared Function WritetoBuffer(ByVal pBuffer As Byte(), ByVal Type As Integer) As Integer
End Function
...and then use it like this:
Dim pBuffer() as byte
ReDim pBuffer(0 To (300 * 400 * 3 - 1))
Dim Rtn As Integer = WritetoBuffer(pBuffer, 1)

Related

Assign a string to a byte array in a VBA user-defined type

I work with a relay module that I normaly connect via USB. That all works perfectly. Now I would like to connect it via the network. All manufacturer's VB.NET code works in vba except for accessing this module over the network.
Public Declare PtrSafe Function DapiOpenModuleEx Lib "DELIB64" (ByVal moduleID As Long, ByVal nr As Long, ByRef exbuffer As DAPI_OPENMODULEEX_STRUCT, ByVal open_options As Long) As Long
' Definitions for DapiOpenEx
Public Type DAPI_OPENMODULEEX_STRUCT
address(255) As Byte
timeout As Long
portno As Long
encryption_type As Long
encryption_password(31) As Byte
End Type
'Open ETH-Module with parameter
Dim handle as Ulong
Dim MyModuleID As UInt32
MyModuleID = 42
Dim open_buffer As New DELib64.DAPI_OPENMODULEEX_STRUCT
open_buffer.address = System.String.Copy(192.168.1.1 As String) As String
open_buffer.portno = 0
handle = DELib.DapiOpenModuleEx(MyModuleID, 0, open_buffer)
I am getting an error "open_buffer.address = System.String.Copy(192.168.1.1 As String) As String "
Can someone help me with what i need to change here?
Dim handle as LongLong
Dim MyModuleID As Long
MyModuleID = 42
Dim open_buffer As Delib64.DAPI_OPENMODULEEX_STRUCT
open_buffer.address = system.String.Copy("192.168.1.1" AS String) As String
open_buffer.portno = 0
handle1 = DapiOpenModuleEx(MyModuleID, 0, open_buffer, 0)
According to your comment, the original line of code is
strcpy((char*) open_buffer.address, "192.168.1.10");
So you need to copy the ASCII (single-byte) string "192.168.1.10" into a VBA byte array. This is surprisingly hard, since the obvious approach of open_buffer.address = StrConv("192.168.1.10", vbFromUnicode) won't work (you can't assign to a fixed-size array that's part of a type).
One obvious solution would be to make a Windows API call to CopyMemory, but if we want a VBA-only solution, a simple loop should suffice:
Dim i As Long
Dim b() As Byte
b = StrConv("192.168.1.10", vbFromUnicode)
For i = 0 To UBound(b)
open_buffer.address(i) = b(i)
Next
open_buffer.address(UBound(b) + 1) = 0 ' C-strings need to be 0-terminated
(I do have the feeling that this should be easier, so I'll gladly upvote competing, simpler answers.)

Is there a VB function to convert 32 bit float to little endian hex

As shown here: https://gregstoll.com/~gregstoll/floattohex/
I need to convert a 32 bit float to a little endian hex (click the swap endiness button before converting). I've managed to do this in python by converting to big endian then reordering, but I have no idea how to approach this issue in VB as I'm entirely new to the language. Using the Hex inbuilt function returns 19a, which i assume means its not correctly evaluating my input as a single.
I've found a recommended solution here but cant get it working:
https://www.tek-tips.com/faqs.cfm?fid=6404
Any suggestions would be great, thanks in advance.
There are a number of ways you could do this - the most obvious being the Copy Memory API. Some time ago, a pretty neat solution was published here: Extracting bits from a float in vba which avoided the need for the API
Basically, you'd just need a couple of short functions:
Option Explicit
Type SingleType
Value As Single
End Type
Type FourBytesType
Value(3) As Byte
End Type
Private Function SingleToBytes(f As Single) As Variant
Dim sngType As SingleType
Dim bytesType As FourBytesType
sngType.Value = f
LSet bytesType = sngType
SingleToBytes = bytesType.Value
End Function
Private Function BytesToHex(bytes As Variant) As String
Dim result As String
Dim i As Long
For i = LBound(bytes) To UBound(bytes)
result = result & IIf(bytes(i) < 16, "0", "") & Hex(bytes(i))
Next
BytesToHex = result
End Function
If you wanted to test Endianness and reverse the array, then something like the following, which kind of uses a Byte Order Mark, could be added. I haven't tested it on a big-endian processor but I think it'd work:
Private Function IsLittleEndianProcessor() As Boolean
Const BOM As Single = 1
Const MSB As Byte = 63
Dim bytes() As Byte
Dim n As Long
bytes = SingleToBytes(BOM)
n = UBound(bytes)
IsLittleEndianProcessor = (bytes(n) = MSB)
End Function
Private Function ChangeEndianness(bytes As Variant) As Variant
Dim result() As Byte
Dim n As Long, m As Long
ReDim result(UBound(bytes))
m = UBound(bytes)
For n = LBound(bytes) To UBound(bytes)
result(m) = bytes(n)
m = m - 1
Next
ChangeEndianness = result
End Function
I'm not actually sure how you want the hex string displayed but you could step backwards through the array to write the hex if needed. Sample test would be:
Public Sub TestMe()
Dim bytes As Variant
Dim output As String
bytes = SingleToBytes(3.1415)
If Not IsLittleEndianProcessor Then
bytes = ChangeEndianness(bytes)
End If
output = BytesToHex(bytes)
Debug.Print output
End Sub

VB NET - ZLIB - Uncompress a stream

I have a little class that can uncompress a byte array with zlib. Here it is :
<Runtime.InteropServices.DllImport("zlib1.DLL", CallingConvention:=Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint:="compress2", charset:=Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function CompressByteArray2(ByVal dest As Byte(), ByRef destLen As Integer, ByVal src As Byte(), ByVal srcLen As Integer, ByVal level As Integer) As Integer
End Function
Public Shared Function DeCompressBytes(ByVal Bytes() As Byte) As Byte()
Dim OrigSize As Integer = BitConverter.ToUInt32(Bytes, 0)
Dim Data(Bytes.Length - 5) As Byte
Array.Copy(Bytes, 4, Data, 0, Bytes.Length - 4)
Dim DLLfunctionResult As Integer
Dim bResult(CInt(OrigSize + (OrigSize * 0.01) + 12)) As Byte
DLLfunctionResult = UncompressByteArray(bResult, OrigSize, Data, Data.Length)
If DLLfunctionResult = 0 Then
ReDim Preserve bResult(OrigSize - 1)
Return bResult
Else
Return Bytes
End If
End Function
It Works, no problem.
I would like to know if it's possible to uncompress from a stream instead of a byte array. Because right now, I have to read the stream and put it in a variable, then uncompress it and put the new result in a variable. The purpose is to accelerate the process. Maybe it will not do that, but I would still like to know about
(French here, sorry for my english)

VB.NET - GetWindowText() returns ZERO for "edit" class

I am trying to retreive text from another application by app's control handle. I have no problem if control is "static" but my code seems not working for "edit" control. As MSDN says, GetWindowText cannot retreive text from EDIT control but maybe you know another way of achieving this?
My current code is here:
Dim newHwnd As IntPtr = Handler.GetClassByPosition(ParentHwnd, cls, classPosition)
Dim length As Integer = Handler.GetWindowTextLength(newHwnd)
Dim sb As New String(" ".Chars(0), length + 1)
If cls = "edit" Then
Handler.GetWindowText(newHwnd, sb, sb.Length)
End If
where GetClassByPosition returns control's handle by specifying parent handle, class name (static,edit or button) and classPosition (used in loop - not important for now)
As I said, it works great with STATIC (labels etc) but it returns 0 if I'm retreiving text from EDIT (textbox) control of that external application.
UPDATE:
I have tried the following solution which success in returning data if data is integer but if it contains any letter, result is 0:
Dim tmpstr As IntPtr = Marshal.AllocHGlobal(100)
Dim NumText = API.SendMessage(Hwnd, API.WM_GETTEXT, 200, tmpstr )
NumText = Marshal.PtrToStringAnsi(tmpstr )
Return NumText
Thanks in advance,
Nikola
try this:
Private Function GetText(ByVal hWnd As IntPtr) As String
Dim ReturnValue As String = Nothing
If hWnd.ToInt32 > 0 Then
Dim Length As Integer = GetWindowTextLength(hWnd)
If Length > 0 Then
Dim sb As New System.Text.StringBuilder("", Length + 1)
GetWindowText(hWnd, sb, sb.Capacity)
ReturnValue = sb.ToString
sb = Nothing
End If
End If
Return ReturnValue
End Function

Name 'VarPtr' is not declared.In old vb code

I have a old code in VB.Now I convert it into vb.net.There is a line in a code
Dim pCParameters As Integer
pCParameters = VarPtr(Parameters)
When I execute code the error occure that
Name 'VarPtr' is not declared.
VarPtr not supported in vb.net.So how I replace it.
This is not as straight forward because your variables in .NET are managed. To do exactly what you are asking you need to look at GCHandle.Alloc and pin the variable so it cannot be moved. Then you can get its memory address.
Something like this (from memory):
GCHandle handle = GCHandle.Alloc(pCParameters , Pinned )
IntPtr ptr = handle.AddressOfPinnedObject
Yes I found the answer.The new VarPtr function is
Public Function VarPtr(ByVal e As Object) As Integer
Dim GC As GCHandle = GCHandle.Alloc(e, GCHandleType.Pinned)
Dim GC2 As Integer = GC.AddrOfPinnedObject.ToInt32
GC.Free()
Return GC2