tags:

views:

225

answers:

2

Note: This is probably a shot in the dark, and its purely out of curiosity that I'm asking.

When using the ImageList control from the Microsoft Common Control lib (mscomctl.ocx) I have found that VB6 generates FRM code that doesn't resolve to real property/method names and I am curious as to how the resolution is made. An example of the generated FRM code is given below with an ImageList containing 3 images:

   Begin MSComctlLib.ImageList ImageList1 
      BackColor       =   -2147483643
      ImageWidth      =   100
      ImageHeight     =   45
      MaskColor       =   12632256
      BeginProperty Images {2C247F25-8591-11D1-B16A-00C0F0283628} 
         NumListImages   =   3
         BeginProperty ListImage1 {2C247F27-8591-11D1-B16A-00C0F0283628} 
            Picture         =   "Form1.frx":0054
            Key             =   ""
         EndProperty
         BeginProperty ListImage2 {2C247F27-8591-11D1-B16A-00C0F0283628} 
            Picture         =   "Form1.frx":3562
            Key             =   ""
         EndProperty
         BeginProperty ListImage3 {2C247F27-8591-11D1-B16A-00C0F0283628} 
            Picture         =   "Form1.frx":6A70
            Key             =   ""
         EndProperty
      EndProperty
   End

From my experience, a BeginProperty tag typically means a compound property (an object) is being assigned to, such as the Font object of most controls, for example:

Begin VB.Form Form1 
   Caption         =   "Form1"
   ClientHeight    =   10950
   ClientLeft      =   60
   ClientTop       =   450
   ClientWidth     =   7215
   BeginProperty Font 
      Name            =   "MS Serif"
      Size            =   8.25
      Charset         =   0
      Weight          =   400
      Underline       =   0   'False
      Italic          =   -1  'True
      Strikethrough   =   0   'False
   EndProperty
End

Which can be easily seen to resolve to VB.Form.Font.<Property Name>.

With ImageList, there is no property called Images. The GUID associated with property Images indicates type ListImages which implements interface IImages. This type makes sense, as the ImageList control has a property called ListImages which is of type IImages. Secondly, properties ListImage1, ListImage2 and ListImage3 don't exist on type IImages, but the GUID associated with these properties indicates type ListImage which implements interface IImage. This type also makes sense, as IImages is in fact a collection of IImage.

What doesn't make sense to me is how VB6 makes these associations. How does VB6 know to make the association between the name Images -> ListImages purely because of an associated type (provided by the GUID) - perhaps because it's the only property of that type? Secondly, how does it resolve ListImage1, ListImage2 and ListImage3 into additions to the collection IImages, and does it use the Add method? Or perhaps the ControlDefault property?

Perhaps VB6 has specific knowledge of this control and no logical resolution exists?

A: 

I am guessing that the GUID ({2C247F25-8591-11D1-B16A-00C0F0283628}) points to the associated ImageList control and ListImage1, ListImage2, etc... is just there to enumerate all the images.

It's kind of like an early version of WPF associated controls (e.g. a TextBox can reference its enclosing grid for placement).

AngryHacker
+2  A: 

You can see what's going on with this fairly contrived example. Start with an ActiveX project and add Class1 and mark it as Persistable = 1

' Class1
Option Explicit

Private m_sText As String

Property Get Text() As String
    Text = m_sText
End Property

Property Let Text(sValue As String)
    m_sText = sValue
End Property

Private Sub Class_ReadProperties(PropBag As PropertyBag)
    With PropBag
        m_sText = .ReadProperty("txt", "")
    End With
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)
    With PropBag
        .WriteProperty "txt", m_sText, ""
    End With
End Sub

Add UserControl1

' UserControl1
Option Explicit

Private m_oData As Class1

Property Get Data() As Class1
    Set Data = m_oData
End Property

Private Sub UserControl_Initialize()
    Set m_oData = New Class1
    m_oData.Text = "this is a test"
End Sub

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    With PropBag
        Set m_oData = .ReadProperty("rs", Nothing)
    End With
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    With PropBag
        .WriteProperty "rs", m_oData, Nothing
    End With
End Sub

Add Form1 and place a UserControl1 on it as save it. You might wan to add Module1 for Sub Main

' Module1
Sub Main()
    With New Form1
        .Show
    End With
End Sub

Here is my Form1.frm file

VERSION 5.00
Begin VB.Form Form1 
   Caption         =   "Form1"
   ClientHeight    =   2400
   ClientLeft      =   48
   ClientTop       =   432
   ClientWidth     =   3744
   LinkTopic       =   "Form1"
   ScaleHeight     =   2400
   ScaleWidth      =   3744
   StartUpPosition =   3  'Windows Default
   Begin Project1.UserControl1 UserControl11 
      Height          =   516
      Left            =   924
      TabIndex        =   0
      Top             =   588
      Width           =   1020
      _ExtentX        =   1799
      _ExtentY        =   910
      BeginProperty rs {326250A4-CA0D-4F88-8F20-DAA391CF8E79} 
         txt             =   "this is a test"
      EndProperty
   End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit

So UserControl1 determines that object m_oData is persisted as property rs in its WriteProperty overload. Class1 determines that its m_sText member variable (or Text public property) is persisted as txt member in the IPropertyBag the frm is passing. There is nothing that requires public property names to match internal property bag names. I would personally use shorted IDs just to minimize bloat (if possible with VB6 at all).

wqw
+1. It is all documented in the VB6 manual section about authoring your own controls. It suggests you "should use the name of the property in the property bag, as it will appear in the frm text file and may be seen by the user of the control" but you are not forced to do so. Same principles apply to COM controls authored in other programming languages. http://msdn.microsoft.com/en-us/library/aa261321(v=VS.60).aspx
MarkJ
@MarkJ: perfect, thanks for the extra info
DAC