02-16-2004, 09:00 AM
I have a class built as an ActiveX DLL, multiuse type 5, so it runs in the client process.
When a client program creates an instance of my object, I'd like to be able to enumerate the client's Forms collection, but I can't.
MSDN says the Forms collection is a "global object" in the application, so I guess that means it's an object that belongs to the base module instance of the client application.
When the class references Forms, it shows a count of zero, because my DLL has not created any Forms.
Is it at all possible for my server to get a reference to my CLIENT's Forms collection? :confused:
02-16-2004, 09:20 AM
You may get away with some late-binding to do this.
In the DLL, provide an interface that can be called from the "client" app that sets an Object variable equal to the Forms collection object.
Private mobjClientForms As Object
Public Property Set ClientForms(ByVal FormsCollection As Object)
Set mobjClientForms = FormsCollection
Private Function EnumChildForms()
Dim frmInstance As Form
For Each frmInstance in mobjClientForms
Set frmInstance = Nothing
I haven't tested this across "client" and "server" boundaries, so am not completely sure that it will work.
02-16-2004, 10:00 AM
That sort of thing would work fine, I'm sure!
But ... I'd really, really like to do it without requiring
the client to make special calls to me - I need to be transparent!
02-16-2004, 10:12 AM
I'm not sure how you would do it transparently. My gut would tell that you couldn't because it is the Client that references the Server through its ProgID's/CLSID's and the Server doesn't generally reference the Client.
Although the Forms collection is Global to the application, the scope is still within the project and not visible outside the project (much the same way that Global/Public members of a BAS are global within a project).
02-16-2004, 03:50 PM
Agree with that 100% - anything "Global" is global to an instance of a module. It's all owned by the same process and it's simply a side-effect of the dynamic linking mechanism that prevents global items from being automatically visible (as against a linking-based compile system where you control all scope, imports and exports).
There is no reason why another module can't use the object but it needs to know the address - and that can only be made known explicitly by the owner module.
I'll try the client-driven approach by simple passing ObjPtr(Forms) to the server and see how good the late bindng really is! Transparency looks a non-goer, pity, it could have provided a workaround to this rotten XP/VB image list bug.
02-17-2004, 06:55 AM
For general interest's sake, here's how an ActiveX DLL can access all client application's Global objects (Forms, App, Printer etc), so long as the client makes a reference available.
Here's a sample class method that does the job - the LogMessage routine used in the text is just a routine to write messges to a log file.
Function ClientControls(cGlobal As IUnknown) As Long
' Client invokes with: Obj.ClientControls [Global]
' original code by Francesco Balena, devx.com,
' date unknown
Dim i As Integer, j As Integer
Dim k As Integer, msg As String
Dim appGlobal As VB.Global
Set appGlobal = cGlobal ' make it usable
For i = 0 To appGlobal.Forms.Count - 1
msg = "hWnd = " & .hWnd & ", "
LogMessage " " & msg & "Form = " & .Name
k = k + 1
For j = 0 To .Controls.Count - 1
msg = "hWnd = " & .Controls(j).hWnd & ", "
LogMessage " " & msg & .Controls(j).Name & " = " & _
k = k + 1
ClientControls = k ' return count of total controls identified
The unusual syntax and use of the IUnknown parameter type is necessary because the Global object is not an Automation object, it's a private class within VB itself, and has no IDispatch interface, only IUnknown.
A test client:
Private Sub Form_Load()
Set obj = CreateObject("MyThing.Test")
10:17:57 [Client] Begin New Test
10:18:25 [Client] Created test object
10:18:25 [Client] Calling object.ClientControls()
10:18:25 [Class ] ClientControls - locating host app Forms collection
10:18:25 [Class ] Host process has 1 form
10:18:25 [Class ] hWnd = 853240, Form = TargetForm
10:18:25 [Class ] hWnd = 3998962, TargetText = TextBox
10:18:25 [Class ] hWnd = 3998962, ImageL = ImageList
10:18:25 [Class ] hWnd = 590862, pb = PictureBox
10:18:25 [Class ] hWnd = 2491458, pb = PictureBox
10:18:25 [Class ] hWnd = 1836220, pb = PictureBox
10:18:25 [Class ] hWnd = 2098420, pb = PictureBox
10:18:25 [Class ] hWnd = 1901584, TargetButton = CommandButton
10:18:25 [Class ] hWnd = 1246874, TargetListView = ListView
10:18:25 [Class ] hWnd = 1246874, ImageS = ImageList
10:18:25 [Class ] hWnd = 1246874, mView = Menu
10:18:25 [Client] Result = 11
10:19:35 [Class ] Terminate