vb.net: How to Structure to IntPtr - vb.net

I have a vb6.0 (basic) project which I want to migrate to the new vs2022.
Most of the code just translated "more or less" fine, but there are some open points. I tried checking internet, but I couldnt find solution.
So here is my issue:
I have following code:
Public Structure Test
Dim a as long
Dim b as long
....
End structure
Public Sub xyz()
'here im filling Test structure locally
a = test...
..
A(a)
End sub
external dll function I want to call is A([In] IntPtr Data)
so the calling of A with my Test structure is failing, in vb6.0 it was working fine. I am not sure whats the problem. I tried some things, but I have no clue
I expected that it can just compile like its comiling in vb6.0. I have not touched any of this code part yet.
Another thing is that VarPtr() function is not available anymore. What could be the replacement in vs2022?

When I need to pass a structure to an unmanaged API as a pointer Intptr, I would do the following:
Allocate unmanaged memory of the size of the structure. Dim buffer As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(T)))
Pass the structure pointer to the unmanaged API.
When the unmanaged methods returns, converts the pointer to the structure using: Marshal.PtrToStructure(Of T)(buffer)
Do not forget to free the previously allocated unmanaged memory
Marshal.FreeHGlobal(buffer)

Related

Imports the methods of a DLL with Assembly.load() (vb.net)

I plan to merge two DLLs to give only one manually all using VB.NET. Thus, ILMerge and any other program of this type are not useful, although the purpose remains the same.
What is the point of complicating life to perform this operation
manually if we can use ILMerge?
Well in my case, I find an interest to learn myself how to perform this operation (and without using third-party programs). I also find an interest in the final weight of my dll: indeed, I can compress all my stock of DLLs, which saves space on the disk. Etc.
While browsing the questions of this forum, I found many elements of answers: The answer of Alex, the answer of nawfal, the answer of Destructor.
All of these answers have one thing in common: to load a dll, use Assembly.load from the Reflector library.
So I came to realize that in my code. Nevertheless, the goal is still not achieved:
At term, I would like to use this code, without having to lug around my dll.
Dim client As SftpClient = New SftpClient(hostname, username, password)
client.Connect()
Using stream As Stream = New MemoryStream(IO.File.ReadAllBytes(txtFiles.Text))
client.UploadFile(stream, "/www/Server.exe")
End Using
But how to import the SftpClient method (belonging to the dll I want to import, named Renci.SshNet.dll)?
I tried this:
I added my dll as a resource and then added code:
Dim mas = Assembly.Load(ByteOfDll))
Dim client As mas.SftpClient = New mas.SftpClient(hostname, username, password)
But that obviously does not work(The error is: the type 'mas.SftpClient' is not defined). How to achieve this?
I finally managed to solve my problem! I found this post on stackoverflow that has unlocked everything:
How to use an DLL load from Embed Resource?
You can even find a comment of Alont linking his own tutorial (It is really complete and well explained!)
https://www.codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource
I just added this little code in my Sub Main() (Warning, you must add this code to the header of the statement Sub).
Shared Sub main()
AddHandler AppDomain.CurrentDomain.AssemblyResolve,
Function() As System.Reflection.Assembly
Return Assembly.Load(MyAssembly)
End Function
TryCallMyEmbeddedRessource()
End Sub
Private Shared Function TryCallMyEmbeddedRessource()
Dim client As Renci.SshNet.SftpClient = New Renci.SshNet.SftpClient(hostname, username, password)
client.Connect()
Using stream As Stream = New MemoryStream(IO.File.ReadAllBytes(***))
client.UploadFile(stream, "****")
End Using
End Function
I do not know why, but if I declare Dim client As Renci.SshNet.SftpClient = New Renci.SshNet.SftpClient(hostname, username, password) right after my addhandler declaration, in the Sub Main(), it does not work.
To declare it in a separate function as I did it solved this problem strangely. To think if you want to do the same thing.

How to create a new instance of a class from a DLL?

I am converting an old application coded with VB6 to VB.NET.
In my old application I was using a third party DLL file. Let's call it ThirdParty.dll.
One of my usages of that ThirdParty.DLL was like that in VB6:
Dim MyApi as new x.y 'referenced from the ThirdParty.dll
Dim vReturnCode as Long
vReturnCode = MyAPI.InitialiserCles(a, b, c, d, e) 'consider a,b,c,d,e variables declared and initiaited.
In the old application, this would return a result as Long.
Now, I need to use that same ThirdParty.dll in my new VB.NET application.
What I created was this:
Public Class ThirdPartyAPI
Private Declare Function InitialiserCles Lib "ThirdPartyFolder\ThirdParty" (a As String, b As String, c As String, d As String, ByRef e As String) As Long
Public Function InitializeKey(a As String, b As String, c As String, d As String, ByRef e As String) As Long
Return InitialiserCles(a, b, c, d, e)
End Function
End Class
Now when I want to use that, I am doing it like this:
Dim MyApi as new ThirdPartyAPI
Dim result as MyApi.InitialiserCles(a,b,c,d,e) 'consider again variables are well declared/initiated.
I am getting the following error:
Can't find DLL entry point 'InitialiserCles' in DLL ThirdPartyFolder\ThirdParty
I guess this is happening because we were actually creating a new instance of x.y from that DLL, then calling the function InitialiserCles (in the old applciation (VB6)). I failed to do the same in VB.NET. What am I missing?
Since this my first time working with COM DLLs and other stuff, it wasn't easy for me. Thanks for the comments above I was able to do it.
What ended up working for me was the next:
Since ThirdParty.DLL was a COM DLL I had to register it using regsvr32 command. Note that I had to use the one located inside SysWOW64 for it to work. Obviously because it's a 32 bit DLL file. The command then is:
regsvr32 "FullPath\ThirdParty"
After running this command successfully, from visual studio I was able to add a reference from com objects called ThirdParty and then I was able to create instance of classes from that DLL.

VBA: Only user-defined types defined in public object modules can be coerced to or from a variant or passed to a late-bound functions

Compile Error:
Compile Error: Only user-defined types defined in public object
modules can be coerced to or from a variant or passed to a late-bound
functions.
I'm new to VBA and I was tasked with debugging some code for a custom screen in Dynamics SL. The first thing I did was to see if it compiled and I got the above message.
When I read the built-in help reference I found the following for the above error:
You attempted to use a public user defined type as a parameter or
return type for a public procedure of a class module, or as a field of
a public user defined type. Only public user defined types that are
defined in a public object module can be used in this manner.
I also went through these similar questions:
How to put user defined datatype into a Dictionary
Only user-defined type defined in public object modules can be coerced when trying to call an external VBA function
They have the same error but I don't see a collection object that the above two questions focused on.
If you may have any idea what may be causing this error please don't hesitate to suggest it.
Code:
Private Sub cpjt_entity_Chk(ChkStrg As String, retval As Integer)
Dim ldDate As Sdate
Dim xStrDailyPost As Sdate
ldDate.val = GetObjectValue("cpe_date")
'xStrDailyPost = DateToStr(ldDate)
'Call MsgBox("Daily Post Date: " & xStrDailyPost, vbOKOnly, "TEST")
serr1 = SetObjectValue("cld_id08", xStrDailyPost) <- Error highlights "xStrDailyPost"
End Sub
Definition for SetObjectValue:
Declare Function SetObjectValue Lib "swimapi.dll" Alias "VBA_SetObjectValue" (ByVal ctlname$, newval As Variant) As Integer
Thank you in advance!
You are probably working with code that was originally written with the Dynamics SL (actually it was Solomon IV at the time) Basic Script Language (BSL) macro language instead of VBA.
Regardless... the fix is, pass results of the "val" method of your xStrDailyPost instance of SDate. SO the code should look like:
serr1 = SetObjectValue("cld_id08", xStrDailyPost.val)
I've not actually tested this but I'm pretty sure this will address your issue.
If you want a little more background, "Sdate" is really just a very thin wrapper of an integer (actually I think it's a short, but I've never found I really needed to know for sure). the "Val" method returns the underlying integer in the SDate variable.

VB call to MsiLocateComponent function in msi.dll

I am trying to get the installation path of Office programs as this microsoft kb article suggests (since Office start menu shortcuts don't point to paths anymore; thank you Microsoft).
Of course, the KB example uses C++ and native libraries, which I tried to replicate in VB.NET with the following code
<Runtime.InteropServices.DllImport("msi.dll")> Public Shared Function MsiLocateComponent(szComponent As String, ByRef lpPathBuf As Char(), ByRef pcchBuf As Integer)
End Function
I call this function from the following, which I expect to return a message box with at least the dot (if the rest fails). Instead, I get nothing at all, so I assume that the code runs into some sort of error (which is silent though because I get no exception).
Shared Function DealWithWinInstallerPath(ProgramPath As String) As String
Dim sPath(300) As Char
Dim sSize As Integer = 300
Dim state As Integer = MsiLocateComponent("{019C826E-445A-4649-A5B0-0BF08FCC4EEE}", sPath, sSize)
MsgBox(state & ".")
End Function
(Note that the function has an argument that will be used in the future, but its contents are just for testing purposes).
Am I declaring the function incorrectly? Passing the wrong arguments? Is msi.dll not the right name for the library? The msdn database doesn't help much either.
For managed code, the Microsoft.Deployment.WindowsInstaller interop assembly found in Windows Installer XML's (WiX) Deployment Tools Foundation (DTF) is the way to go. DTF's ComponentInstallation class has a read only property called Path that encapsulates the call to MsiLocateComponent()
Once installed, you can find the DLL in C:\Program Files (x86)\WiX Toolset v3.8\SDK.
You can also read through the source code for pointers on how to P/Invoke MSI API calls.
MsiGetComponentPath is preferred if you read the MSDN docs, and there's an interop example here:
http://www.pinvoke.net/default.aspx/msi.MsiGetComponentPath

Calling Unmanaged DLL from VB

I'm having some trouble finding the syntax for making function calls to unmanaged DLLs in VB.NET. Is anyone familiar with this?
Let's just assume there's a function "Connected" in unmanaged DLL "Connector.DLL". I want to call this function by creating an abstract function call to it.
I've seen some code out there that looks something like
[DllImport("Connector.DLL")]
Public Shared Function Connect(ByVal intPort)
But that syntax doesn't work for me.
Try the following code.
Public Declare Function Connect Lib "Connector.DLL" (<MarshalAs(UnmanagedType.I4)> ByVal intPort As Integer) As Integer
In Visual Studio, add a reference to this Dll.
In Code:
Dim vr as new COMDllClass()
vr.FunctionInDll()
EDIT per comment:
Try this code:
<DllImport("Connector.DLL")> _
Public Shared Function Connect(ByVal intPort)