Click to See Complete Forum and Search --> : Interfaces
leep
November 28th, 1999, 04:18 PM
I have an ActiveX Control project (CMSSecurity). It contains one UserControl (ICMSPassword) which Implements an ICMSPlugin interface. It includes all the properties/subs/functions from the ICMSPlugin interface, plus several of its own (which make up it's ICMSPlugin interface, right?).
In another application, I have an objPlugin variable of type ICMSPlugin, and an objPass variable of type ICMSPassword. objPlugin holds a reference to the ICMSPlugin interface on a dynamically created instance of the CMSSecurity.ICMSPassword control. Shouldn't I be able to do set objPass = objPlugin
to get a reference to that control's ICMSPassword interface? When I do this I get a Type Mismatch error.
In the project which references the ICMSPassword control, when I go to Project/Componants, it lists CMSSecurity on two lines. One refers to the .VBP and the other refers to the .OCX. Is this a sign that something's wrong or is this normal? I've tried checking both of them (not at the same time) and either way I get the Type Mismatch error. I've tried running RegClean but it didn't help.
-----
Lee Perkins
TigerBase Technologies
czimmerman
November 28th, 1999, 10:57 PM
I think you have to first do the following:
dim ojbPlugin as ICMSPlugin
Then the line set objPass = objPlugin should work.
Charlie Zimmerman
http://www.freevbcode.com
czimmerman
November 28th, 1999, 10:58 PM
I think you have to first do the following:
dim objPlugin as ICMSPlugin
Then the line
set objPass = objPlugin
should work.
Charlie Zimmerman
http://www.freevbcode.com
leep
November 28th, 1999, 11:16 PM
I think what I'm trying to do should work. I think something else is wrong. Take a look at this:
Dim objPlugin as ICMSPlugin
Dim objPass as CMS_Security.ICMSpassword ' Tried just "ICMSpassword" also
Dim objObject as Object
set objPlugin = CreateObject("CMS_Security.ICMSpassword")
set objObject = CreateObject("CMS_Security.ICMSpassword")
set objPass = CreateObject("CMS_Security.ICMSpassword")
The "Set objPlugin =" line works and gets the ICMSPlugin interface.
The "Set objObject =" line works and gets the ICMSpassword interface.
The "Set objPass =" line fails with a Type Mismatch error.
I've unregistered CMS_Security.ocx, removed all references to CMS_Security and ICMSpassword from my registry, ran RegClean, and recompiled CMS_Security and the application that uses it and still get this problem. What in the WORLD am I doing wrong? :)
BTW, I no longer have multiple lines in the Project/Components list for CMS_Security now that I cleaned up the registry.
-----
Lee Perkins
TigerBase Technologies
czimmerman
November 28th, 1999, 11:36 PM
It's a weird situation, because it seems that VB recognizes that ICMSpassword implements ICMSplugin, yet it does not recognize ICMSpassword as a valid object in itself.
Just guessing, but it may be possible that the application is looking for the previous version of ICMSpassword. Try unchecking the reference to ICMSpassword in the references list, closing the references, then opening up the references list and browsing to the correct, newly compiled version of CMS_Security.
leep
November 28th, 1999, 11:58 PM
I unregistered CMS_Security.ocx, deleted all copies of CMS_Security.ocx, removed all references to CMS_Security and ICMSpassword from the registry, removed the component reference to CMS_Security from the application project, quit VB, cleaned up the CMS_Security project directory (removed the .lib, .exp, etc... compile time generated files), restarted VB, opened the project group, recompiled CMS_Security, copied CMS_Security.ocx to another directory, set Binary Compatibility to the copy of the OCX (just to make sure my interfaceID's are changing on me), added the component reference CMS_Security back to the application project, recompiled it, ran it, and sure enough... as soon as it hits the line:
set objPass = objPlugin
it throws up a Type Mismatch error.
Could this have anything to do with the fact the CMS_Security is a ActiveX Control (not an Active DLL)? Is there some reason in VB why you can't get the UserControl's "native" interface through another interface reference on that same object? I know you can't say
Dim objPass as new ICMSPassword
It just won't let you. But you can say
Dim objPass as ICMSPassword
I'm gonna play with this more using a small project and minimal code.
-----
Lee Perkins
TigerBase Technologies
Ravi Kiran
November 29th, 1999, 12:16 AM
hey!, in your first post you said ICMSPassowrd is a user Control!. and how can you do a createObject on a user control, It works only for server classes/objects.
Either you do a "set" to an existing instance of a control or you create a run time instance using Me.Controls.add ( VB 6.0) .
Also you said "The "Set objPlugin =" line works and gets the ICMSPlugin interface."..
this is the reference of which instance of interface? Meaning, an interface has be have an implementation right? So to which class/control is this refering to after that line?
II. Back to yout first post :
ICMSPassword is a class that implemets the ICMSPlugin Interface, which means
you can NEVER say
dim objPass as ICMSPassword
dim objPlugin as ICMSPlugin
...
set objPass = objPlugin. ' IS WRONG
Infact it is the other way:
set objPlugin = objPass
because IMPLEMENTS means "is a" relationship holds. So where ever a ICMSPLugin object is required, you can use an instance of ICMSPassword, but you can never use a ICMSplugin where ICMSpassword is required!!.
ICMSPassowrd : Implements ICMSPlugin.
so if there is a function that takes the class/interface CMSPLugin you can pass a
a reference to CMSPassword, because CMSPLugin is wholely contained in CMSPassword.
Think abt it!
RK
czimmerman
November 29th, 1999, 12:21 AM
I'm a little confused because now you're going back to the code from your first post. In your second post, you presented something slightly different. In the second post, you said set objPass = createObject("ICMSPassword") didn't work, and I was not sure why. But here and in your first post, you are trying to assign an object to an interface variable, and this won't work. Instead, you have to do the opposite -- dim an instance of the interface variable and then assign the interface variable to an instance of the object variable. You can then access the object's implementation of that interface via the interface variable.
Charlie Zimmerman
http://www.freevbcode.com
leep
November 29th, 1999, 12:26 AM
You're thinking strictly VB here. We're dealing with the world of COM. An object has multiple interfaces. From any interface on an object, you can call QueryInterface(...) and get a reference to any other interface on the object. This is one of the rules of COM. VB handles the grunt work of calling QueryInterface for you behind the scenes. All you have to do is assign an interface reference variable to a variable of another interface type and VB will call QueryInterface on the assigned interface to request the new interface. If it fails... Type Mismatch. If it doesn't fail, you have a reference to the other interface on the same object. That's how VB handles COM and multiple interfaces.
As to your other comment, an ActiveX control *IS* a COM server and should therefore be able to be created with CreateObject(<servers ProgID>) with no problem. When you do Me.Controls.Add("<controls ProgID>"), that's essentialy what VB is doing. It's creating an instance of the server dynamically by looking it's ClassID up in the registry via it's ProgID. After all, an .OCX is still an in-proc COM server (ActiveX DLL, whatever you want to call it) it's just renamed to .OCX. The main difference between VB's ActiveX DLL and ActiveX Control project types are what COM interfaces they implement. An ActiveX Control implements a lot of OLE interfaces to all it to be imbedded in a container.
-----
Lee Perkins
TigerBase Technologies
Ravi Kiran
November 29th, 1999, 12:29 AM
"Shouldn't I be able to do
set objPass = objPlugin "
NO. You should not be able to. See my other positng.
----
Regarding 2 instances: Even i have noticed. and what i could decifer is: it is so because their in-process serves are different. For one it is .ocx file while for the other it is the running instance of VB.exe ( This exists as long as you have VB open only). Look into the registry, you will see both.
This is again the typical case of an interface being implemented by multiple objects.
Your .Ocx file implements the interface identified by the ClassID of the control. and the VB.exe also (in debug mode) registers itself as implementing the same interface, and same class id, and hence you see two references and you can choose between them.
RK
leep
November 29th, 1999, 12:45 AM
Ok, maybe I'm a little confused in my understanding of how VB handles COM. In COM, an object can have multiple interfaces. If you have any interface on that object, you can get to any other interface on that object by calling QueryInterface() through the interface pointer (reference) you have. That's a fundamental rule of COM. I was under the impression that in VB, you just assigned an variable of one interface type to a variable of another interface type and VB would take care of calling QueryInterface() behind the scenes for you. Given that assumption, if you have an object that has InterfaceA and InterfaceB, you should be able to assign a variable of type InterfaceA to a varialbe of type InterfaceB, and visa versa.
In a VB ActiveX Control project, there is a UserControl. I assumed (Maybe THAT's what I'm doing too much... :)) that the UserControls name was one interface, and any interfaces it "Implements" were additional interfaces.
Using OleView to view the compiled OCX confuses me a little (a lot!) more. It appears that the ActiveX Control project's name is used as the name of the Type Library. The UserControl's name is used as the coClass *AND* the default interface. I always thought the project's name was used to name the coClass, and the UserControl's name was used to name the default interface. Shows how wrong I've been. :) So when I Dim a variable as CMS_Security.ICMSPassword, I'm specifying the Type Library, and the coClass. The variable should be a reference to the default interface on the coClass. Yet in VB, if I do:
Dim objPass as CMS_Security.ICMSPassword
then when I type objPass. the list that comes up of available properties/methods is WAY more than is in the ICMSPassword interface, it's the VB control itself. Ok, I'm throughly confused now on how VB handles COM.
ARGH!!!!! :( It's late (2am almost) and I'm going insane. Time to go to sleep. :)
-----
Lee Perkins
TigerBase Technologies
czimmerman
November 29th, 1999, 12:53 AM
How VB handles COM is an interesting topic, but if you approach VB coding from a "COM underpinnings" point of view, you will just get confused. The creators of VB purposely hid the details of COM and its implementation from VB developers. Thus, I'd recommend just trying to figure out what you're supposed to do, and not worry about how it relates to COM.
Regarding the other issue, I did not know that you can't use CreateObject on a UserControl, like that other fellow said, because I've never tried it, but I'd assume that's correct, and that's why you are having the trouble you are having.
Good luck, I'm sure you'll have it all working very fast after you wake up tommorrow.
Ravi Kiran
November 29th, 1999, 12:58 AM
It may be the ooly World of com!. but still it has stick together right?
In your example, your ICMSPlugin doesnot implement the interface ICMSPassword!. and hence it fails.. simple.. (infact it is the other way!)
>"You're thinking strictly VB here.".
VB may be doing the CreateObject and other grunt work of Com behind the scenes. I too understand (some of)the intercasies , it may be doing all but and a "little more", which could be causing the touble :
and my simple point is:
If you program in VB, do the VB way!.
VBs way of query interface is 'TypeOf'.
To know if an object implements an interface or not, Use "is typeof ".
RK
leep
November 29th, 1999, 01:02 AM
I think what I'm finding out is that in the case of:
Dim objPlugin as ICMSPlugin
Dim objPass as ICMSPassword
My variable objPlugin is a reference to a COM Interface named ICMSPLugin. My variable objPass is of type UserControl ICMSPassword (the UserControl named that, not the COM Interface named that). CreateObject("CMS_Security.ICMSPassword") returns COM interfaces. So... Set objPass = CreateObject(...) tries to assing the COM Interface ICMSPassword to a variable of type UserControl ICMSPassword. Type Mismatch. If this is the case... I need to find a way to make a variable of the COM Interface ICMSPassword type, not the UserControl ICMSPassword type. I'm afraid VB might not let me do this in which case I have to rethink my strategy. This wouldn't be so bad if I wasn't supposed to start burning CD's with this software on it this week for release to the field and it's had no testing yet. ARGH!!!! :) Bet you're glad you're not me, huh? I wish I wasn't me right now. LOL! :)
-----
Lee Perkins
TigerBase Technologies
leep
November 29th, 1999, 01:05 AM
I think I'm starting to understand what's going on (read my latest reply to czimmerman in this thread). Sorry if I sounded abrupt before, it's just getting late and I'm too close to a dead line to still be sane. :)
-----
Lee Perkins
TigerBase Technologies
czimmerman
November 29th, 1999, 01:15 AM
I don't think your strategy is off base, just your syntax. If you have the user control on the form, you can just do what Ravi suggested, in one of the previous messages: use me.controls.add to dynamically load the control. If it is not on a form, you can either add an invisible form to your project and put the control there, or compile the ICMSPassword object as an Active X dll rather than an Active X control.
leep
November 29th, 1999, 01:30 AM
It's not quite that simple for me. :) I've greatly simplified my actual scenario here to make it easier to concentrate on the problem. In reality, the "Application" I've been refering to is another ActiveX Control (CMS_Reports) which has 3 UserControls (ICSMFranchiseReports, ICMSBookkeeperReports and ICMSTransmiterReports). And there are about 20 other ActiveX Control projects with one or more UserControls each. All these UserControls (including CMS_Security.ICMSPassaword) are "plugins" to a central Standard EXE project which is known genericaly as the "Framework". The framework has a Parent MDI form, and a single child MDI form. The framework creates a new child MDI form and the form dynamically adds one of the controls to itself. A control on a form can request that the framework create another child window and gives the framework the ProgID of the control to place on the window. All the controls implement the ICMSPlugin interface, so the framework returns the ICMSPlugin interface reference to the control that requested the window be created. It's in one of those controls (CMS_Reports.ICMSBookkeeperReports) that I'm requesting the framework create a CMS_Security.ICMSPassword window. The framework gives me back the ICMSPlugin interface reference to the control it just created. Given only that ICMSPlugin reference, I need to acquire a referenc to the control's ICMSPassword interface. That's the frame of mind I was in when I started this thread. I see now that I may have to have the framework return a generic Object to the requesting control (since the framework has no idea what kind of objects it's creating, only that they must implement ICMSPlugin). Either way, I'll work something out tomorrow.
-----
Lee Perkins
TigerBase Technologies
Ravi Kiran
November 29th, 1999, 01:43 AM
*** LOL **.
I think it rather too late to decide if you should gone for active-x control or dll or server (exe). incidentally all are COM!.
It is one of the first design considerations.. well before burning CDs :-)
I think, your understanding is what my understanding too is. CreateObject creates an instance of the class, it is a pointer to the interface and a little more.. that little more (a bit more because it is a control ), you have to live thru.. having decided to use VB:-)
--
To get a simple reference to the COM interface,
drop a user control ICMSPassword on a form. code is the sameas you have been doing:
dim objPLugin as ICMSPlugin
dim objpass as ICMSPassword.
set objPass = Form.ICMSPassword1
' here objPass is both a Usercontrol reference and also the Cominterface
set objPlugin = objPass ' is valid and COREECT also, if you ask me!!
' you dont need a CreateObject for ICMSPlugin, unless you want another instance/reference.
'
Debug.print objpass is Typeof ICMSPlugin
' will print true
if you want more tell me what exactly you want.. i do understand a bit of COM, i may be able to tell the VB way. What exacly you propose to do with the interface pointer of ICMSPassword?
RK
Ravi Kiran
November 29th, 1999, 02:37 AM
This is a beautiful explanation of the requirement.
It depends on how the frame work is returning the interface.
Something like this may still work:
dim objPass as ICMSPassowrd
dim objPlugin as ICMSPlugin
set objPlugin = CreateObject("Library.ICMSPassword")
'' ** NOTICE the Class. it is not PLUGIN
'' and this line is valid because ICMSPassword class created above supports plugin interface.
'' In your case, it may not be a direct CreateObject, but a Me.Controls.Add.. or whatever
''
if typeof objPlugin is ICMSPassword then
set objPass = objPlugin
end if
I just now did a small test and this is the code
private Sub Form_Load()
Dim ttt as ITest1
Dim ttt2 as ITest2 '<-- Implements Itest1 actually
set ttt = CreateObject("InterfaceTests.ITest2")
'' Notice the Class name it is Itest2
If TypeOf ttt is ITest2 then
set ttt2 = ttt
End If
set ttt = nothing
set ttt2 = nothing
set ttt = CreateThruFuncAsObject("InterfaceTests.ITest2")
If TypeOf ttt is ITest2 then
set ttt2 = ttt
End If
set ttt = nothing
set ttt2 = nothing
set ttt = CreateThruFuncAsClass("InterfaceTests.ITest2")
If TypeOf ttt is ITest2 then
set ttt2 = ttt
End If
set ttt = nothing
set ttt2 = nothing
End Sub
private Function CreateThruFuncAsObject(szClsName as string) as Object
set CreateThruFuncAsObject = CreateObject(szClsName)
End Function
private Function CreateThruFuncAsClass(szClsName as string) as InterfaceTests.ITest1
set CreateThruFuncAsClass = CreateObject(szClsName)
End Function
and it goes thru w/o a glitch and works
RK
leep
November 29th, 1999, 07:11 AM
The third example in your code is closest to what I'm doing. I'm calling a function and getting a ICMSPlugin back and I set it into a variable named objPlugin (Dim objPlugin as ICMSPlugin) (that's the interface my control implements). But when I check "TypeOf objPlugin is ICMSPassword" I get False even though the ICMSPlugin is an interface on an instance of a CMS_Security.ICMSPassword control which was created by the MDIChild form in the framework doing something like this (don't have the exact code in front of me but I remember what I was thinking when I wrote it... Sounds dangerous, huh?) :)
[vbcode]Dim objExt as VBControlExtender
Dim objPlugin as ICMSPlugin
Set objExt = me.Controls.add("CMS_Security.ICMSPassword)
Set objPlugin = objExt.Object
... objPlugin is returned to the caller.
I'm off to work this morning so I'll check back in throughout the day. :)
-----
Lee Perkins
TigerBase Technologies
Ravi Kiran
November 30th, 1999, 12:58 AM
unfortunately, i cannot create an example of your case, because i am still using VB 5.0!!
I will still see if i can simulate a case...
RK
Ravi Kiran
December 1st, 1999, 05:58 AM
any progress? or too busy trying ??
RK
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.