Calling ActiveX dlls 'on-the-fly'

How would i call ActiveX dlls 'on-the-fly' via code?

I do not mind having to restart the program, i am attempting to call all dlls within a folder and call functions within them (they all have the same function names and project names)

Its basically for a plugin system, my program needs to loop though each dll and call function x() in each one.
LVL 1
Nightma12Asked:
Who is Participating?
 
steveberzinsCommented:
I went ahead and created a simple sample on another PC that has VB6 on it.

It is three projects, one for the interface dll, one for a plugin dll that implements the interface, and a form that shows it all in use together.

Project 1, Active X dll project, named NRPluginInterfaces, I created an IEvents class, and put some functions and methods in it.

code:
Option Explicit

Public Function Function1(ByVal value1 As String) As String

End Function

Public Function Function2(ByVal strValue As String) As String

End Function

Public Sub Method1(ByVal strValue As String)

End Sub
-------------------
Project 2, Active X dll project, named NRPlugin1, created a class called CEvents, and implemented IEvents in it.

code:
Option Explicit

Implements NRPluginInterfaces.IEvents

Private Function IEvents_Function1(ByVal strValue As String) As String
    IEvents_Function1 = "Function1 was supplied a strValue of : " & strValue
End Function

Private Function IEvents_Function2(ByVal strValue As String) As String
    IEvents_Function2 = "Function1 was supplied a strValue of : " & strValue
End Function

Private Sub IEvents_Method1(ByVal strValue As String)
    Debug.Print "Method1 was supplied a strValue of : " & strValue
End Sub
-----------------------
Project 3, simple exe project, one button on a form, (the classic vb test project :), with this code in the click event:

code:
Option Explicit

Private Sub Command1_Click()
   
    Dim x As NRPluginInterfaces.IEvents
    Set x = CreateObject("NRPlugin1.CEvents")
   
    Debug.Print x.Function1("some value")
    Debug.Print x.Function2("Some other value")
   
    Call x.Method1("Yet another value")
   
End Sub

Both Project 2, and Project 3 must reference the NRPluginInterfaces project/dll, but should not reference each other in any other way, the only thing they should know about, is the interface they agree upon sharing, the NRPluginInterfaces.IEvents interface.

create AND BUILD each project, ONE AT A TIME, in this order, and it should all work, if you named all the projects the same as I did, if not, you'll need to change the names to match.
0
 
steveberzinsCommented:
are they registered?
is there any naming convention to the class names that you can follow?

like dlls are named
DoSomething1.dll
DoSomething2.dll

and the class and method in each are always the same?

so you could use something like:
Set x = CreateObject("DoSomething1.ProcessorClass")
x.Execute()
Set x = CreateObject("DoSomething1.ProcessorClass")
x.Execute()

so, you could use the FileSystemObject, loop the dlls in the directory, use the name of the dll to figure out the progid, create it, call the method you know will exist, etc. etc.

0
 
steveberzinsCommented:
oops, cut and paste malfunction... :)
Set x = CreateObject("DoSomething1.ProcessorClass")
x.Execute()
Set x = CreateObject("DoSomething2.ProcessorClass")
x.Execute()

0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
Nightma12Author Commented:
Isnt the format of CreateObject, CreateObject("Projectname.Classname") ? so all the project names will be the same?

and yes, although they are not registered, i can easily make my program register any dlls =]
0
 
Nightma12Author Commented:
The format and methods of each dll will all be the same, would compatability be an issue? Because at the moment i have a single dll that gets overwritten and i have to put Binary compatability on it to work.
0
 
steveberzinsCommented:
not sure I'm understanding...must be missing something, can you show by example what you're trying to do?
0
 
Nightma12Author Commented:
I currently have a dll in my application directory with loads of blank events in there that allow the user to create 'plugins' - however they can only overwrite that one dll and it wont call any others.

I was planning to make the program open and call the events within any dll file in the /Plugin/ directory - as every dll will have the same class name project name and events.

I was under the impression that when you used to CreateObject() method, it wanted the dll in the format: CreateObject(Projecname.Classname) rather than dllname.Classname

At the moment, i set a reference to the single NRPlugin.dll and then do set NRplugin = NEW NRPlugin.Events and then i call them from there. When a user overwrites a dll, they MUST set Binary Compatability onto the old dll otherwise my program will crash with an 'Automation Error'. Would this need to be done if i used CreateObject()?
0
 
steveberzinsCommented:
you're right...

Since you said ActiveX, I assumed COM, and I assumed you'd have all objects registered, that is the 'usual way' of doing it.

so, I'd assumed that the progid, which is what CreateObject works with, would be unique for each of the these objects, and that you'd be using some naming convention for the .dll files, that would allow you to create the objects from the name of the dll, or something like that... guess I was off track in that assumption.

but, to me, this just screams of something that could use an interface, the interface would be implemented by any dll you want to 'plug in'.

Does this sound like something you could use?

-------------------

or, if you really want to do it where the object is going to have the exact same progid, you probably need to look at not registering the dlls at all, and using something like the LoadLibrary api, and GetProcAddress etc.

here is a sample I found, where you can call into a dll without referencing it explicitly:

Create a new project and add this code to Form1
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Any, ByVal wParam As Any, ByVal lParam As Any) As Long
Private Sub Form_Load()
    On Error Resume Next
    'KPD-Team 1999
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net
    'We're going to call an API-function, without declaring it!
    Dim lb As Long, pa As Long
    'map 'user32' into the address space of the calling process.
    lb = LoadLibrary("user32")
    'retrieve the address of 'SetWindowTextA'
    pa = GetProcAddress(lb, "SetWindowTextA")
    'Call the SetWindowTextA-function
    CallWindowProc pa, Me.hWnd, "Hello !", ByVal 0&, ByVal 0&
    'unmap the library's address
    FreeLibrary lb
End Sub
0
 
Nightma12Author Commented:
That could work... does that work with ActiveX dlls created in Visual Basic though? user32.dll is called differently than the dll's i am useing i believe.
0
 
steveberzinsCommented:
never done it myself, I think it will work, but I don't even have vb6 on my development machine anymore, so I can't easily test the theory out by making a test project to do it in.

but...

please consider the interface thing, it just screams to me to be a better solution, and will be much easier for all involved I'd think.

You already have it defined, in vb, sounds like to me, the interface is usually just that, a class with a bunch of empty methods for others to actually 'implement'.

People who want to actually 'implement' the interface, put code into the methods in any class they want to, with a reference to your class, and just put the 'Implements InterfaceClassName' at the top.

if it were me, I'd really look into letting them implement your methods in any dll they want, and not forcing the projectname/classname on them, and using a dll naming convention that you can determine the progid from, to use with createobject, just seems like it could fit, and is likely to be easier in the end, but the dlls would have to be registered for createobject to work, whether when they are added, or programmatically before they are called.

0
 
Nightma12Author Commented:
So what your saying is i should get them to rename the project name to the same name as the dll file itself?

Registering the dll files is not a problem as i already have a script that loops though the dlls files and registers them via regsvr32.

If i had the dllnames the same as the project name, then i would be able to loop though every dll in /Plugins/ and use CreateObject(dllname.classname) to call them? Would that work?
0
 
steveberzinsCommented:
Yep, that is what I'm saying.

By default, isn't that the way it works?
The dll will be named using the project name unless told not to in the project properties right?

So, just to follow more accepted conventions, since your dll is really just an interface definition, the classname for it should start with an 'I'. for example, instead of CNightPlugin as it might be if it were a normal class, in our example name should be something like  INightPlugin.

You just have to tell anyone who wants to write a plugin, to create a project, add a class, name it x (we'll use CNightPlugin for our example), and use Implements YourProjectName.INightPlugin and put code in methods they want to implement.

then in your code, you just define the variable as the interface type,
for each dll in /plugins/ parse out file name without dll extension

  Dim plugin As YourProjectName.INightPlugin
  Set plugin = CreateObject(dllnamewithoutdllextension & ".CNightPlugin")

  do puginy stuff with it... :)

next

and it'll all work fine.

you will want to set binary compatibility on it as well, so the progid - guid and all that fun don't change over time once the thing is out in the wild.
0
 
Nightma12Author Commented:
I tried useing this code as a test and it gets me 'Object variable or with block variable not set' on the line that ive surrounded in >><<

==============================================================================
Option Explicit

Private x As Object

Private Sub Command1_Click()
>>>>>>x = CreateObject("NRPlugin.events")<<<<<<
MsgBox x.GETRecRanks(6)
End Sub
==============================================================================

The dll is already registered

I think the problem is that i need to define x as the project name.. however as far as im aware i am unable to declare variables programmatically and include variables in the Type.... as i wont know what the project name is before running the application.

Hopefully that makes sence.
0
 
steveberzinsCommented:
no, As object should work, it'll just be late bound, the problem I would guess, is that the prog id is not actually "NRPlugin.events", if you use the interface thing, you know that any valid object, that implements the interface, will be compatible with that type, so it is kinda the best of both worlds.

so....

you want me to gin up a real simple sample, that you might get the idea of what I'm trying to get at, or you wanna post the code you're using, like your class with empty methods, and we can make that work?
0
 
Nightma12Author Commented:
Wow, it works! =]

Thanks! =D
0
 
steveberzinsCommented:
glad to help, finally... :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.