How to create a new instance of a class from a DLL? - vb.net

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.

Related

vb.net: How to Structure to IntPtr

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)

Access .dll library MODULE function in Excel (VBA)

I have a library called PIT_math_tools (written in vb.net) containing math functions which is split up into different modules.
In this case, the function I want to access is located in a Module called geometry_ellipsen_module:
Namespace geometry_ellipsen
Public Module geometry_ellipsen_module
...
Public Function calc_distanz_ellipse_kreis(...) As Double
Now I want to access the Function calc_distanz_ellipse_kreis() in VBA.
I used the following declare statement to accomplish this:
Private Declare PtrSafe Function calc_distanz_ellipse_kreis Lib "C:\Users\path...\PIT_math_tools.dll" (...) As Double
So far, everything looks fine.
When trying to call that function, however, I get runtime error '453'
"DLL-Entry Point calc_distanz_ellipse_kreis in 'PathToLibrary' not found."
When using the function in other .Net code, it could be found either by using the prefix
PIT_math_tools.geometry_ellipsen.geometry_ellipsen_module.calc_distanz_ellipse_kreis()
or an import statement identical to the prefix above.
Based on that, I tried extending the Function name in the Declare Statement by the same prefix:
Private Declare PtrSafe Function geometry_ellipsen.geometry_ellipsen_module.calc_distanz_ellipse_kreis Lib ...
However, this results in a compiler error "Expected: Lib".
How do I get the vba code to find the function inside the library module?
Thanks in advance.
The VBA syntax...
Private Declare Function SomeMethod() Lib "Some.dll"
... is used to prototype standard Win32 DLLs, e.g. Win32 API. Which .NET DLLs (aka "Assemblies") are not.
What you need to do in VB.NET is to make that assembly COM-visible. VB.NET creates a typelib (*.tlb) for the assembly.
In VBA you then add a COM reference (point to that typelib) to your project like you would do with other COM DLLs (ADODB, MSXML etc.). And then you do your standard
Dim myObject As Namespace.ClassName
Set myObject = New Namespace.ClassName
With myObject
.ThisProperty = 123
Dim lRet As Long
lRet = .ThisMethod("abc")
End With

"Set" and explicit "Variant" statement Deprecation?

I am relatively new to programming in VB, so please be patient with my frustration.
I am trying to declare a class using VB in Visual Studio 2010 Ultimate, and I'm following along with a tutorial, but Intellisense keeps messing with my code. Here's something along the lines of what I'm trying to write:
Import HYSYS
Dim myVar As Variant
...
Public Class MyClassVB1
Dim hyContainer As Object
Public Function Initialize(ByVal Container As Object, ByVal IsRecalling As Boolean) As Long
Set hyContainer = Container
End Function
However, Visual Studio turns my code into this:
Import HYSYS
Dim myVar As VariantType
...
Public Class MyClassVB1
Dim hyContainer As Object
Public Function Initialize(ByVal Container As Object, ByVal IsRecalling As Boolean) As Long
SetAttr() hyContainer = Container
End Function
After arguing with Visual Studio for a while, I finally have the message Let and Set assignment statements are no longer supported.
Is there a replacement that I'm supposed to use, or does Visual Studio just assume that I mean Variant if I don't explicitly specify a type?
Likewise, do I need to use a keyword or function for variable assignment, or can I treat it like I would in c++ and just write hyContainer = Container?
Set, as you're using it, is left over from the vb6/vbscript days.
It no longer works like that in VB.Net. You never ever use it for assignment.
You may be following an obsolete tutorial. In VB.Net, Set is only used as part of a LINQ query.
Variant is similar. It is no longer part of the VB language at all, and has not been for more than 10 years.

Visual C++ managed app: Unable to find an entry point named 'Add'

I have followed the tutorial on the following page to create a c++ DLL and I have put it in the System32 folder: http://msdn.microsoft.com/en-us/library/ms235636%28v=vs.80%29.aspx. I am able to run the .exe from anywhere on the PC. Now I want to be able to call Add from a VB.NET application, so I have added the following code:
Imports System.Runtime.InteropServices
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
Dim Test As Integer
Test = Add(1, 1)
MsgBox(Test)
Catch ex As Exception
End Try
End Sub
<DllImport("MathFuncsDll.dll", EntryPoint:="Add", SetLastError:=True, CharSet:=CharSet.Ansi)> _
Private Shared Function Add(ByVal a As Double, ByVal B As Double) As Double
End Function
End Class
I get the following error: Unable to find an entry point named 'Add' in DLL 'MathFuncsDll.dll. I believe this is because of the namespace. I have researched this and some web pages say namespaces are not allowed with Platform Invoke and some web pages say they are allowed. What is the problem?
The entry point is not named "Add". From the Visual Studio Command Prompt, run dumpbin /exports MathFuncsDll.dll to see the exported names. To get this declaration:
<DllImport("MathFuncsDll.dll", EntryPoint:="?Add#MyMathFuncs#MathFuncs##SANNN#Z", _
CallingConvention:=CallingConvention.Cdecl)> _
Private Shared Function Add(ByVal a As Double, ByVal B As Double) As Double
End Function
The strange looking name is produced by the C++ compiler, a feature called "name decoration". It supports function overloading. You can put extern "C" in front of the function declaration to suppress it. It is actually better if you don't. Also note that SetLastError wasn't correct, the code doesn't actually call SetLastError() to report errors. And CharSet wasn't appropriate, these functions don't take strings.
You'll also need to do something about the Divide function, throwing a C++ exception won't come to a good end in an interop scenario, only C++ code can catch the exception.
Namespaces are not allowed. PInvoke works like plain C client. Don't forget also to declare MathFuncsDll as extern "C" to prevent C++ name mangling. Use Dependency Walker or dumpbin to see list of functions exported from MathFuncsDll.

Excel UDF 'not a valid addin' error

I am trying to create a custom vb.net Excel 2007 function (UDF) using VS 2010 and have gotten to this stage (borrowing heavily from Eric Carter's example at http://blogs.msdn.com/b/eric_carter/archive/2004/12/01/273127.aspx):
Namespace AutomationAddin
<Guid("1aeeb1b5-e099-4f7f-aeb0-3e9f19b64f62")>
<ClassInterface(ClassInterfaceType.AutoDual)>
<ComVisible(True)>
Public Class MyFunctions
Public MyFunctions()
Public Function MultiplyNTimes(ByVal number1 As Double, ByVal number2 As Double, ByVal timesToMultiply As Double) As Double
Dim result As Double = number1
For i As Integer = 0 To timesToMultiply - 1
result = result * number2
Next
Return result
End Function
<ComRegisterFunctionAttribute()>
Public Shared Sub RegisterFunction(ByVal type As Type)
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"))
Dim key As RegistryKey = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), True)
key.SetValue("", (System.Environment.SystemDirectory + "\mscoree.dll"), RegistryValueKind.String)
End Sub
<ComUnregisterFunctionAttribute()>
Public Shared Sub UnregisterFunction(ByVal type As Type)
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), False)
End Sub
Private Shared Function GetSubKeyName(ByVal type As Type, ByVal subKeyName As String) As String
Dim s As System.Text.StringBuilder = New System.Text.StringBuilder
s.Append("CLSID\{")
s.Append(type.GUID.ToString.ToUpper)
s.Append("}\")
s.Append(subKeyName)
Return s.ToString
End Function
End Class
End Namespace
However, when I build it using VS 2010 and try to load it in Excel 2007 using the Addin Manager>Automation I find it listed as AutomationAddin.AutomationAddin.MyFunctions and click OK only to get the error "AutomationAddin.AutomationAddin.MyFunctions is not a valid add-in." I have set the Build settings to Register for COM interop.
I've had a look online and tried following this article How to get COM Server for Excel written in VB.NET installed and registered in Automation Servers list? but to no avail. I checked my registry (after I built my project) and under CLSID/{myGuid}/InprocServer32/Default the data is set to C:\WINDOWS\system32\mscoree.dll and CLSID/{myGuid}/Programmable already exists.
I am not quite sure what I am doing wrong and would appreciate any guidance or suggestions on the topic.
Cheers,
Ben
You might want to check out this article (Build and Deploy a .NET COM Assembly) which might be helpful in your case.
I don't know if this is relevant to the question (especially after all this time) but I originally started with a COM add-in (created using Visual Studio 2010's Excel 2010 add-in project builder). I then added an automation add-in (for UDFs) by hand in the same project using the Eric Carter blog and other examples. The two worked fine independently. It was only after combining the two in the same namespace (for some obsessively tidy reason) that I started getting the "... is not a valid add-in" error. Spent a day tearing my hair out and then separated the namespaces again - problem went away.