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
Related
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.)
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)
I am Compiling My string Code(I read My Code from Text File) In vb and it works fine but i have a function that returns nullable double(Double?)
when i use it like this
Dim x As Double? = Myfunc(1000) 'it returns Nothing
my x variable fills with Nothing and it's ok
But When I use it like this
Dim x = Myfunc(1000) 'it returns Nothing
my x value is 0 !!!!
How can i solve this problem
i want my users write codes like first code block
i tested all Option Explicit and Option Strict but it did not gain me anything.
please let me know how can i use Just dim x not Dim x as (type)
thank you for your helps
UPDATE :this is Myfunc Code :
Function Myfunc(parameterId As Long) As Double?
If parameterId = 1000 Then
Return Nothing
Else
Return tot(parameterId) 'it is a dictionary of values
End If
End Function
And this Is my Compile Class :
Private Shared Function Compile(ByVal vbCode As String) As CompilerResults
Dim providerOptions = New Dictionary(Of String, String)
providerOptions.Add("CompilerVersion", "v4.0")
' Create the VB.NET compiler.
Dim vbProv = New VBCodeProvider(providerOptions)
' Create parameters to pass to the compiler.
Dim vbParams = New CompilerParameters()
' Add referenced assemblies.
vbParams.ReferencedAssemblies.Add("mscorlib.dll")
vbParams.ReferencedAssemblies.Add("System.Core.dll")
vbParams.ReferencedAssemblies.Add("System.dll")
vbParams.ReferencedAssemblies.Add("System.Windows.Forms.dll")
vbParams.ReferencedAssemblies.Add("System.Data.dll")
vbParams.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll")
vbParams.ReferencedAssemblies.Add("System.Xml.dll")
vbParams.ReferencedAssemblies.Add("System.Xml.Linq.dll")
vbParams.GenerateExecutable = False
' Ensure we generate an assembly in memory and not as a physical file.
vbParams.GenerateInMemory = True
' Compile the code and get the compiler results (contains errors, etc.)
Return vbProv.CompileAssemblyFromSource(vbParams, vbCode)
End Function
As discussed above, Option Infer On needs to be included to force the compiler to create the variable as the required type - in this case the Double? returned by MyFunc.
I am trying to write a VB.NET program that will call a function in an unmanaged C DLL passing the structure like this:
typedef struct {
unsigned char *msg;
int msglen;
}
What I have not been able to figure out is how to handle the "unsigned char *msg" part. How would you define this in the VB.NET Structure?
<StructLayout(LayoutKind.Sequential)> _
public structure foo
<MarshalAs(UnmanagedType.LPStr)> dim msg as string
dim msgLen as integer
end structure
This depends a lot on how the memory for the msg field is handled. You need to be careful to free any allocated memory which is transfered to managed code.
That being said I think the most straight forward interop type is as follows
Public Structure S1
Public msg as IntPtr
Public msgLen as Integer
End Structure
To get the actual msg value as a String you'll need to use the following code.
Public Function GetString(ByVal s1 as S1) As String
return Marshal.PtrToStringAnsi(s1.msg, s1.msgLen)
End Function
To create an S1 instance based on a String do the following. Note: You will need to free the memory allocated here if the calling function does not take ownership.
Public Function CreateS1(ByVal str As String) As S1
Dim local As New S1
local.msg = Marshal.StringToHGlobalAnsi(str)
local.msgLen = str.Length
return local
End Function
I have written my own function, which in C would be declared like this, using standard Win32 calling conventions:
int Thing( char * command, char * buffer, int * BufSize);
I have the following amount of Visual Basic code figured out, which should import the DLL file and call this function, wrapping it up to make it easy to call Thing("CommandHere",GetDataBackHere).
UPDATE: This code is now a working solution, as shown here:
Imports Microsoft.VisualBasic
Imports System.Runtime.InteropServices
Imports System
Imports System.Text
Namespace dllInvocationSpace
Public Class dllInvoker
' I tried attributes, but I could not make it build:
' <DllImport("thing1.dll", False, CallingConvention.Cdecl, CharSet.Ansi, "Thing", True, True, False, True)>
Declare Ansi Function Thing Lib "thing1.dll" (ByVal Command As String, ByRef Buffer As StringBuilder, ByRef BufferLength As Integer) As Integer
' This part contributed by helpful user:
Shared Function dllCall(ByVal Command As String, ByRef Results As String) As Integer
Dim Buffer As StringBuilder = New StringBuilder(65536)
Dim Length As Integer = Buffer.Capacity
Dim retCode As Integer = Thing(Command, Buffer, Length)
Results = Buffer.ToString()
'Debug.Assert(Results.Length = Length) ' This assertion is not true for me
Return retCode
End Function
End Class
End Namespace
I got the code to build by following the help received here, and then I had forgot the As Return Type (which got me a MarshalDirectiveException PInvokeRestriction). Then I had an assertion failure inside my DLL, which lead to an SEHException. Once fixed, this works BEAUTIFULLY. Thank you folks. There are newsgroups where people are saying this can not be done, that Visual Basic only loads managed DLL assemblies (which I guess is the normal thing most Visual Basic users are used to).
It depends on how you use the buffer argument in your C code. If you only pass a string from your VB.NET code to your C code then declaring it ByVal String is good enough. If however you let the C code return a string in the buffer then you have to declare it ByVal StringBuilder and initialize it properly before the call. For example:
Public Class dllInvoker
Declare Ansi Function Thing Lib "Thing1.dll" (ByVal Command As String, ByVal Buffer As StringBuilder, ByRef BufferLength As Integer) As Integer
Shared Function dllCall(ByVal Command As String, ByRef Results As String) As Integer
Dim Buffer As StringBuilder = New StringBuilder(65536)
Dim Length As Integer = Buffer.Capacity
Dim retCode As Integer = Thing(Command, Buffer, Length)
Results = Buffer.ToString()
Debug.Assert(Results.Length = Length)
Return retCode
End Function
End Class
Note the ambiguity in the returned Length value.
You cannot convert a StringBuilder instance to a string instance, instead, use the 'ToString' method to convert it back to the string type...here's the portion of the code in the dllCall function...
retCode = Thing(Command, Buffer, bufsz)
Results = Buffer.ToString();