将UserControl作为参数传递给VB6时出现问题

时间:2009-05-14 12:27:59

标签: com vb6 controls parameters

我有一个COM-visible方法,如下所示:

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

其他组件会调用此方法(即通过COM)并传入类型为SpecificControl的控件。

我的问题是,当通过调试器运行时,参数化控件似乎不是正确的类型,即它在'cast'失败之后退出子例程,而我预期它不会。

使用TypeOf我已经验证参数化对象是Control类型(如上所述)但我无法弄清楚为什么它被传入 - 显然 - 不正确。在调试器外部运行时似乎行为正常 - 但我不能确定(因此这个问题)。

任何人都可以对此有所了解吗?在拳击拆箱过程中,控件是否已经 - 某种程度上 - 被破坏了?有没有更好的方法呢?

编辑:我使用了Kris Erickson建议的TypeName并获得了一些有趣的结果:

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

我明白了:

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

我想我唯一能做的就是避免将UserControl作为参数传递。

2 个答案:

答案 0 :(得分:3)

我使用VBControlExtender作为参数类型

Public Sub SomeMethod(someControl as VBControlExtender)

然后我得到像这样的引用

Dim someSpecificControl as SpecificControl
Dim someSpecificControlExt as VBControlExtender

Set someSpecificControl = someControl.object
Set someSpecificControlExt = someControl

然后使用someSpecificControlExt访问LeftTabIndexTabStopNameMove等扩展程序的属性和{ {1}}访问我的用户控件的特定方法/属性。

仅供参考,代码的行为取决于用户控件是在当前项目中实现还是在ocx中引用。我也在使用Matt Curlands direct user control access hack,这允许我这样做

Dim someSpecificControl as DirectSpecificControl

以便早期访问someSpecificControl道具/方法。

这就是我从控件中获取someSpecificControl(扩展器)的方法:

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

这就是我获取VB6用户控件的内部someSpecificControlExt的方法:

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

引用UserControl返回有一个非常奇怪的GetUserControl实现 - 似乎QueryInterface接口专门针对UserControl

答案 1 :(得分:1)

我不知道为什么会这样,但我知道UserControl在VB6中是半魔术。如果你通过它的实际类型将UserControl传递给一个函数,它会丢失它的所有UserControl基类(我知道,VB6没有继承,但是在创建UserControl时你需要某些特性)。

所以,如果你

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

一旦控件离开你的子程序,它将表现为一个Control,而不是UserControl(你将无法访问UserControl属性,并且尝试访问它们将导致错误)。 VB6中的一个非常奇怪的错误,一个引起大量拉动头发的问题。

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

一切都很好。我的猜测是你是正确的,UserControls是盒装的,没有装箱,因为Control不是UserControls。类型检查的唯一解决方案是使用

TypeName()

知道它是什么类型,因为它不会被破坏。