Pass .net Form as parameter to dll - vb.net

This is the vb6 dll function code which is built and added as com reference to vb.net exe
Public Function Access1(ByVal txt As String, ByRef res As Object)
MsgBox (TypeName(res))
MsgBox (res.Text)
End Function
Using below .net code I was able to pass component as parameter to vb6 dll.
Dim s As New dllname.class
s.Access1("abc", Textbox1)
The above code worked and msgbox display "Textbox" for typename(res).
But if I try to pass form instead of Textbox , while executing the .net code gives "Specified cast is not valid" error.
How to pass form object to dll function?

Unfortunately, it is not possible to pass a Form back from a COM object.
In order to do this you would need to create an ActiveX containing your form and then you can embed it in your current application.
Alternatively, If you create your form in your COM component, you can show it and then return whatever values you need to your calling code.

Related

Marshalling a .Net function that returns Double() to consume in VBA

Here is my function in .Net:
<Runtime.InteropServices.ComVisibleAttribute(True)>
Public Function Unhex(hex As String) As Double()
Dim GetArr As Double() = HexStringToDoubleArray(hex)
Return GetArr
End Function
Here is how I would like to use it in VBA:
Dim ret() As Double
ret = LinkToComLib.Unhex("EDC531...")
There are hundreds of examples of how to pass arrays into .Net (eg), but the only one I found showing the opposite is this MS page, and it doesn't show it being used on the VBA (or even COM) side. Perhaps I am using the wrong search terms. In any event:
Can I use the MarshalAs to export the Double() from .Net, or will I need to use Marshal.Copy or similar (as I suspect, as it is managed)?
If I do have to Copy, is the proper return type then IntPtr?
Am I correct in thinking that Dim ret() As Double is a pointer to a malloc'ed array or perhaps SAFEARRAY? Is that the proper type to use in VBA in this case?
Would creating the array with the proper size (it's always 492!) in VBA and then passing that to the function help in any way? Deallocing perhaps?
If anyone has a pointer to an example of this - a double (or int) array being passed out of .Net along with the corresponding VBA code, I can likely take it from there. But if someone has answers for the above, VB.Net or C# as they like, I'd appreciate it.
You need to decorate the return with <MarshalAs(UnmanagedType.SafeArray)> attribute.
VB.Net Example:
Imports System.Runtime.InteropServices
<ComClass(ArrayExample.ClassId, ArrayExample.InterfaceId)> _
Public Class ArrayExample
' These GUIDs provide the COM identity for this class and its COM interfaces.
Public Const ClassId As String = "e510d899-dad1-412b-94ea-6c726fe9f9da"
Public Const InterfaceId As String = "ef3498f0-22b4-4c2a-aeb1-22936c9757eb"
Public Function Unhex(hex As String) As <MarshalAs(UnmanagedType.SafeArray)> Double()
Dim GetArr As Double() = {2.0R, 5.0R}
Return GetArr
End Function
End Class
VBA Usage:
Sub t()
Dim c As ExampleComArrayReturn.ArrayExample
Set c = New ExampleComArrayReturn.ArrayExample
Dim arr() As Double
arr = c.Unhex("AABB")
End Sub
Edit: Forgot to mention that this uses the ComClassAttribute Class to have the compiler generate the interfaces for your class.
Edit 2 in response to follow-up question.
To debug your COM library project, go to the Debug tab of project properties. Select "Start External Program" and set it to run Excel. You can also specify the Workbook to open in the "Command line Arguments". Now when you click on the "Start" button, Excel will be launched and break points in your code will be triggered.
Edit 3:
To address the issue of targeting .Net 3.5, you can use a slightly less convenient method of attaching the debugger to the Excel process. If you are using VS2008, the method described above will work. New VS versions will need to attach to the process. There may be a way to specify this info in the vproj.user file, but I have not found the magic property type to allow direct launching using a specific framework version.
Depending on your VS version the "Attach To Process" item will either be under the Tools (VS2013) or the Debug (VS2017) menu or you can use the shortcut cntrl-alt-p.
Obviously start Excel and load your Workbook. Then in VS launch the Attach to Process dialog. Click the "Select" button and then click on the "Debug these type" radiobutton. Select the "Managed (v3.5, v3.0, v2.0) code" type and click the "OK" button. Then select the Excel process and click "Attach".

How to access this variable?

I'm new to VB and I'm currently migrating a vb6 app I did not write to .net and I'm struggling with this error,
If TypeOf Application.OpenForms.Item(i) Is frmAddChangeDelete Then
'UPGRADE_ISSUE: Control ctrlAddChangeDelete1 could not be resolved because it was within the generic namespace Form. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="084D22AD-ECB1-400F-B4C7-418ECEC5E36E"'
If **Application.OpenForms.Item(i).ctrlAddChangeDelete1.ParentFormNumber = intFormNumber** Then
If Application.OpenForms.Item(i).Text = "Add Proofed Expense Items" Then
boolAddProofed = True
Exit For
ctrlAddChangeDelete1 is supposedly calling the friend class ctrlAddChangeDelete from a separate VB file, so I'm not sure why it's saying that
"'ctrlAddChangeDelete1' is not a member of 'System.Windows.Forms.Form'."
Any help is appreciated, thank you !
Application.OpenForms is a collection not strongly typed.
When you reference elements there you get back a generic Form.
In a generic Form there is no control named ctrlAddChangeDelete1
If you have a form derived class named frmAddChangeDelete and this class has a control named ctrlAddChangeDelete1 then you need to cast the reference stored in the OpenForms collection to your specific form class before trying to reference that control.
Moreover, to access that control from external code, you should also have the Modifiers property set to Public instead of the default Internal. Otherwise you will not be able to access the control from any code external to the class.
To retrieve correctly your form you can write
Dim delForm = Application.OpenForms.
OfType(Of frmAddChangeDelete)
FirstOrDefault()
If delForm Is Nothing Then
' No form of type frmAddChangeDelete is present in the collection
' write here your message and exit ?
Else
' Now you can use delForm without searching again in the collection
......
The code above uses the IEnumerable.OfType extension and this requires the Imports System.Linq.
If you don't want to use this then you can always use the TryCast operator to get the reference to the correct class
' Still you need a for loop up ^^^^ before these lines
Dim delForm = TryCast(Application.OpenForms(i), frmAddChangeDelete)
if delForm Is Nothing then
....
else
....

Cannot retrieve a VB.ListBox object passed from a VB6 EXE to a VB6 DLL when debugging DLL

I'm maintaining a DLL with logging feature. I wanted to add a ListBox parameter to a method of this DLL to allow on display logging.
Basically this dll could be described this way :
' Class loggingDll.loggingObject
Public Function processIt([...], aLogBox As Object)
' Simple test code lines...
Dim l As VB.ListBox
Set l = aLogBox
' [...]
End Function
The EXE comes with a GUI, a VB.ListBox included. This ListBox (let's call it LogBox) is passed to the DLL in a way looking like this :
' Exe DllCaller.Exe
Private Sub Form_Load()
Dim aLoggingObject as loggingDll.loggingObject
Set aLoggingObject = New loggingDll.loggingObject
aLoggingObject.processIt(LogBox)
End Sub
This works perfectly fine when I run the EXE. But when running the DLL in debug mode whith this EXE (Project->Properties->Debugging tab option "Start program" with the path to the EXE), I get an ugly "Type Mismatch" at Set l = aLogBox.
I added a spy on the aLogBox variable. TypeName(aLogBox) returns "ListBox", but the content of aLogBox is empty (although a VB.ListBox object is full of properties).
What's happening ? Why debug mode has not the same behaviour ?

Visual Basic Member Already Exists in an object module

I am brand new to visual basic today and I was writing my program but I get a compile error
Member already exists in an object module from which this object module derives
My function prototype is
Function calculate(count As Integer) As String
I was wondering why this is giving me this error
It would appear that you are designing a form, and have an object on that form (such as a text box or command button) which is also named calculate, disregarding case, since VBA is generally not case sensitive.
It is because your function has same name as the system's reserve function name, such as AfterInsert()

Adding Excel Object Library conflicts between Excel.TextBox & Forms.TextBox in Office Development

I have implemented several basic Excel functions in my vb.net application (opening an xls workbook & accessing worksheet). However, it appears that when I add the Reference "Microsoft Excel 14.0 Object Library" the application is getting confused with the standard System.Windows.Forms objects and has the following error: InvalidCastException occured: Unable to cast object of type 'System.Windows.Forms.TextBox' to type 'Microsoft.Office.Interop.Excel.TextBox'. The Invalid Cast error is happening when calling a subroutine & passing the application form controls (check boxes, GridView, TextBox, etc) from my main "Form1" class into a UtilityFunction module. UtilityFunction has a reusable Windows Registry sub routine which retrieves/saves values at application startup/closing. This worked in the past, but now is crashing at the subroutine call in the Form1 class. The exception occurs during application runtime, not during the compile/build.
Also, I deleted the text controls from the form and created them manually, but I'm still getting the same exception error.
When you have a Namespace conflict you need to fully qualify the object you want.
Dim excelTb As New Microsoft.Office.Interop.Excel.TextBox
Dim formTb As New System.Windows.Forms.TextBox
I solved this problem by using the following code:
Imports X = Microsoft.Office.Interop.Excel
Dim xlApp As X.Application = New X.Application