Tutorial :Problems passing in a UserControl as a parameter in VB6



Question:

I have a COM-visible method which looks something like the following:

Public Sub SomeMethod(someControl as Object)  On Error Goto ErrHandler        Dim someSpecificControl as SpecificControl       MsgBox TypeOf someControl is Control     MsgBox TypeOf someControl is SpecificControl       On Error Resume Next     Set someSpecificControl = someControl     On Error Goto ErrHandler     if someSpecificControl is Nothing then        Exit Sub     end if       ' do stuff to the control    End Sub  

Other components would call this method (i.e. via COM) and pass in a control of type SpecificControl.

My problem is that when run via the debugger, the parameterized control doesn't appear to be of the right type i.e. it exits the sub-routine after the 'cast' fails when I would have expected it not to.

Using TypeOf I have verified that the parameterized object is of type Control (as above) but I cannot work out why it was passed in - apparently - incorrectly. It seems to be behaving correctly when run outside the debugger - but I can't be sure (hence this question).

Can anyone shed any light on this? Could the control have been - somehow - corrupted in the boxing-unboxing process? Is there a better way of doing this?

Edit: I used TypeName as suggested by Kris Erickson and got some interesting results:

MsgBox TypeName(someControl)   MsgBox "someControl is of type SpecificControl: " & TypeOf someControl is SpecificControl  MsgBox "someControl is of type UserControl: " & TypeOf someControl is UserControl  MsgBox "someControl is of type Control: " & TypeOf someControl is Control  

I get:

SpecificControl  someControl is of type SpecificControl: False  someControl is of type UserControl: False  someControl is of type Control: True  

I guess the only way I have around this is to avoid passing in a UserControl as a parameter.


Solution:1

I don't know why this happens, but I do know that UserControl's are semi magic in VB6. If you pass a UserControl into a function by its actual type, it loses all of its UserControl base class (I know, VB6 doesn't have inheritance but when creating a UserControl you expect certain features).

So if you

Private Sub AdjustControlProperties(oControl as MyUserControl)  ...  End Sub  

Once the control leaves your your subroutine, it will behave as a Control, not as a UserControl (you will have no access to UserControl properties anymore, and attempts to access them will cause an error). Very strange bug in VB6, and one that caused much pulling of hair to work it out.

Private Sub AdjustControlProperties(oControl as Object)  ...  End Sub  

And everything is fine. My guess is that you are correct, and UserControls are boxed, unboxed as Control's not UserControls. The only solution to type checking, is to use

TypeName()  

to know what type it is, as that does not get corrupted.


Solution:2

I'm using VBControlExtender as parameter type

Public Sub SomeMethod(someControl as VBControlExtender)

then I get the references like this

Dim someSpecificControl as SpecificControl  Dim someSpecificControlExt as VBControlExtender    Set someSpecificControl = someControl.object  Set someSpecificControlExt = someControl

Then use someSpecificControlExt to access Left, TabIndex, TabStop, Name, Move, etc. properties of the extender and someSpecificControl to access specific methods/properties of my user control.

FYI, the behaviour of your code depends on whether the user control is implemented in the current project or referenced in an ocx. I'm using Matt Curlands direct user control access hack too, which allows me to do this

Dim someSpecificControl as DirectSpecificControl

so that someSpecificControl props/methods are accessed early-bound.

This is how I get someSpecificControlExt (the extender) from the control:

Public Function GetExtendedControl(oCtl As IUnknown) As VBControlExtender      Dim pOleObject      As IOleObject      Dim pOleControlSite As IOleControlSite        On Error Resume Next      Set pOleObject = oCtl      Set pOleControlSite = pOleObject.GetClientSite      Set GetExtendedControl = pOleControlSite.GetExtendedControl      On Error GoTo 0  End Function

This is how I get the internal UserControl of the VB6 user control:

Public Function GetUserControl(oObj As Object) As UserControl      Dim pControl        As UserControl        Call CopyMemory(pControl, ObjPtr(oObj), 4)      Set GetUserControl = pControl      Call CopyMemory(pControl, 0&, 4)  End Function

The reference GetUserControl returns has a very weird implementaion of QueryInterface -- it seems UserControl interface is specifically dummied to E_NOTIMPLEMENTED.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »