What is a public object module in VBA? - oop

I'm trying to get as close to function pointers / abstract classes as I can in VBA.
I have a class called VerificationManager and verifies a bunch of cells in a couple of spreadsheets match up. This will be done in different ways depending on the information and spreadsheets being used with it.
I'd like to be able to make the code reusable by specifying a method to be called in a string using the Application.Run function. So I can rewrite the function that changes.
Now if I was using Java or C# I would be able to extend an abstract class and rewrite the internals to the function. If I was using JavaScript I could store a function in a variable and pass the variable to the class and call it from there.
Inside my class I have a public property called "verificationModule" which I set to the name of the function I want it to call.
Sub VerifyWorkLocations(empLoc As EmployerLocation)
...
For i = 0 To empLoc.numOfEmp
Application.Run verificationModule, empLoc.taxdescmatch, empLoc.employees(i)
Next i
...
End Sub
However, when I try to call Application.Run I receive the following error:
Compile Error:
"Only user-defined types defined in public object modules can be
coerced to or from a variant or passed to late-bound functions"
I already tried placing my User Defined Types in a Class Module but it basically said that a class module was the wrong place for a type.

The error comes from full-fledged VB, where you can create an ActiveX dll project, create a public class there and put a UDT into that class.
In VBA, you use classes instead of UDTs when you need to coerce to or from a variant.
So just declare a class with all the fields you have in your UDT, and delete the UDT.
Alternatively, create a DLL in VB6 that would only contain the declaration of the type, and reference that dll from VBA. Or, if you're comfortable with IDL, just create a TLB file directly.

To add a module to a VBA application, try the following steps (assuming you've already entered the VBA IDE):
From the Project Explorer, right-click on your project.
Click on "Insert..."
Select "Module."
If no modules exist, a new folder within the VBA/Excel project will be created, named "Modules," and a module with a default name of "Module1" will be created.
Double-click the module to open it in the source editor.
This is where you have to place UDT's. I believe this is because of the difference in the way such types are stored internally by VBA relative to the COM-style structure of elements/objects declared/manipulated as Classes...

Related

How to create a global function and pass variables to it in VBA Access?

In my program I am trying to cut down on repetitive code by putting it into global functions.
In my current setup I am calling the function like:
Call [Global variable].Close
(global variable is the name of the class module).
This function is looks like;
Public Function Close()
DoCmd.Close
Cancel = True
End Function
Unfortunately this wont compile properly. What am I doing wrong?? (As an aside I also want to pass variables to and from this function and want to know how this would be done).
Thanks for your help.
If you're using a class module, you need an instance of that module before you can call its members. That requires either creating the class module as pre-declared (which involves exporting the code, editing in Notepad, and re-importing), or creating an instance with the New keyword:
Dim myClassInstance As MyClass
Set myClassInstance = New MyClass
myClassInstance.Close
But, depending on your use-case, you might better off with the function being available in a standard module - then you can just call it from anywhere, including from within a query.

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()

How to specify a code module as the "Object Ref" parameter in VB.Net CallByName?

I am trying to call a public subroutine from a Windows form based on a string variable containing the name of the subroutine. The subroutine is a procedure in a code module and works fine when called by using the procedure name directly.
The VB.net function CallByName should work, but I don't know how to specify the module name as the "Object Ref" parameter.
In the code shown, "ReportLibrary" is a module containing the public sub with the name contained in the string strReportProcedure. This results in the following error helper:
The Help says this about the ObjectRef parameter:
ObjectRef
Type: System.Object
Required. Object. A pointer to the object exposing the property or method.
What am I missing or is it just not possible to call a routine from a module using CallByName?
CallByName will not work for code in VB.Net modules since the first parameter requires an object. You need to move the methods into a class, then create an instance of the class in order to make CallByName work.
Hmmm, I think the problem is somewhere else.
I think you haven't declared a variable like this:
Dim RL as NEW Reportlibrary
And after declaring it, use this:
CallByName(RL, strReportProcedure , CallType.Method , blnPreview)
Probably the problem was in declaration, because (in your case) your class doesn't let you access to your library's subroutines. That's why you need to declare "as New ReportLibrary".
Good Luck !
Dim object As NEW Reportlibrary and then just use that Object.

Check if .dll file exists and load it

What is the easiest want to check if a .dll file exists, then to load it ? ( i don't need to use modules from that dll file, i just want to run it ).
I'd like to have simple example of code.
To check if a file exists use system.io.file.exists(path).
To load the assembly look at Assembly.Load, you can execute code from it by loading it, then calling Activator.CreateInstance on a type from that assembly. Once you have an instance of the type you can call methods on it.
If you don't have an interface defined on the type from the assembly for easy calling you will have to use Reflection to inspect the types and methods on those types. That starts getting more complicated and without a specific example of what you are trying to do I can't give you an example of how to actually do it in code.
updated example
The simplest way to just execute code from a dynamically loaded assembly involves knowing a few things about it in advance.
You should know in advance the name of the Type that contains the code you want to execute, the name of the Method that contains the code, and the parameters it takes. For this example lets say that you always have a class in the assembly called "MyClass", and the code you want to run is in a sub called "Execute" that take no parameters. You can load and execute it like this.
You should Import System.Reflection
Dim asm as Assembly = Assembly.LoadFrom("TheDll.dll") 'Load the assembly
dim t as type = asm.GetType("MyClass") 'Get a reference to the type that contains the code
dim info as MethodInfo = t.GetMethod("Execute") 'Get a reference to the method on the type that we want to call
dim instance as object = Activator.CreateInstance(t) 'Create an instance of the type to call the method on
info.Invoke(obj,nothing) 'Invoke the method with no parameters

Declare Attribute in VB.NET

In my VB 6.0 code, I declare have the following line:
Attribute VB_Name = "MyFile"
However, in VB.NET, I get the error "expecting declaration". Isn't this a declaration statement? Is there a good reference for finding the differences between VB.NET and VB 6.0?
There's no need for the above code at all in VB.NET.
In VB 6, it specifies the name of the file from within code—this is used for things like the window title, as well as allowing you to explicitly qualify references to the members of that class in your code.
In VB.NET, the name used in the declaration of the class already serves that purpose. You no longer need to provide an explicit name with an Attribute. Consider the following mini-class:
Public Class MyFile
Public Sub DoWork()
'do something here
End Sub
End Class
To call the DoWork method of the class you've named MyFile from another place in your code, you would simply write:
MyFile.DoWork()
just as you could after you specified the VB_Name attribute under previous versions of VB.
Also note that the file name that your class/module is saved as can be something completely different; the name you specify in the class declaration is not dependent on the name you've given the file itself, just like previous versions.