Могут ли свойства ActiveX (к которым можно получить доступ из Visual Basic) процедурно генерироваться во время выполнения? - PullRequest
2 голосов
/ 27 февраля 2009

Кто-нибудь знает, возможно ли генерировать свойства ActiveX во время выполнения?

Мне нужно только получить и установить эти свойства из Visual Basic.

Мой элемент управления ActiveX написан на C ++, и я уже знаю, как создавать свойства, реализуя жестко запрограммированные функции C ++ get и put. Однако у меня потенциально большой набор свойств для этого элемента управления ActiveX, и в идеале представленный набор свойств будет меняться в зависимости от внутреннего состояния элемента управления ActiveX.

Я надеюсь, что есть способ генерировать свойства из данных, такие как следующий XML:

<Properties>
    <Property>
        <Name>SomeProperty</Name>
        <Type>Int</Type>
        <DefaultValue>10</DefaultValue>
    </Property>

    ...

<Properties>

Спасибо

Ответы [ 2 ]

1 голос
/ 27 февраля 2009

Это может быть очень просто или несколько сложно в зависимости от синтаксиса, который вам необходим.

Один из способов - создать собственную коллекцию имен / значений в элементе управления ActiveX. Вы можете добавить только два метода:

HRESULT GetPropery([in] BSTR name, [out,retval] VARIANT value);
HRESULT SetPropery([in] BSTR name, [in] VARIANT value);

По сути, у вас будет ОДНО свойство на элементе управления, который будет содержать коллекцию всех остальных. Это самый простой способ.

Вместо этого можно создать свойство com collection (ссылка предполагает ATL, но есть общая информация о com collection) свойства вариантов. Сделайте вызов Item () коллекции, принимающей строки. Доступ к нему будет выглядеть так (коллекция называется «Свойства»):

myValue = myControl.Properties("Name")

Я не уверен, как вы могли бы установить такие значения?

myControl.Properties("Name") = newValue

Для этого может потребоваться, чтобы коллекция возвращала не варианты, а COM-объекты со свойством «default». Я даже не помню многих деталей свойств по умолчанию - но я думаю, что клиенты VB6 хорошо их поддерживают, и все, что вам нужно, это установить некоторые атрибуты в вашем файле IDL / ODL.

Обе идеи требуют, чтобы вызывающие стороны имели небольшую косвенность метода (Get / SetProperty) или использование свойства коллекции (myobject.Properties.XXXX). Если вы ДОЛЖНЫ иметь следующий синтаксис:

x = myControl.MyDynamticProperty

Вам нужно написать собственную реализацию IDispatch GetIDsOfName и Invoke. Я сделал это недавно, это было ужасно. К счастью, все это было удалено, поскольку в этой части приложения мы пошли в другом направлении. Вы должны были бы заставить вызывающих абонентов использовать нежизнеспособный интерфейс IDispatch (и быть с поздним связыванием) - я полагаю, это может быть легко или сложно в зависимости от языка вызова. Мои абоненты всегда были VB script , поэтому это не было проблемой.

0 голосов
/ 27 февраля 2009

Во-первых, это технически возможно, но включает в себя использование памяти и виртуальных таблиц. Не для слабонервных и определенно не для всего, что вы хотите сохранить в долгосрочной перспективе. COM разработан таким образом, что после определения интерфейса он остается неизменным для этой ревизии. Вот почему так важно обновлять номера ревизий при добавлении в интерфейс.

Мы столкнулись с этой же проблемой при создании модуля калькуляции для нашего программного обеспечения для резки металла. Диктонар Microsoft Scripting был слишком негибким, поэтому мы создали похожий набор объектов, называемый свойством. Это позволяет динамически добавлять свойства в наши классы.

Option Explicit

Private priName As String
Private priValue As Variant

Private priProperties As PropertyList

Public Property Get Properties() As PropertyLis
    Set Properties = priProperties
End Property

Public Function Assign(ByVal RHS As Property)
    priName = RHS.Name
    priValue = RHS.Value
    priProperties.Assign RHS.Properties
End Function

Public Function Clone() As Property
    Dim nObject As Property

    Set nObject = New Property

    nObject.Name = priName
    nObject.Value = priValue

    If Not priProperties Is Nothing Then
        nObject.Properties.Assign priProperties
    End If

    Set Clone = nObject

    Set nObject = Nothing
End Function

Public Property Get Name() As String
    Name = priName
End Property

Public Property Let Name(ByVal RHS As String)
    priName = RHS
End Property

Public Property Get Value() As Variant
    Value = priValue
End Property

Public Property Let Value(ByVal RHS As Variant)
    priValue = RHS
End Property

Private Sub Class_Initialize()
    mPropertyType = PropertyTypeEnum.ptVariant
    mPropertyList = New PropertyList
End Sub

PropertyList. Определите Item как свойство по умолчанию, а NewEnum - как свойство перечислителя.

Option Explicit

Private mCol As Collection

Public Sub Assign(nObject As PropertyList)
    Dim I As Long

    Me.Clear
    For I = 1 To nObject.Count
        Me.AddMember nObject(I).Clone
    Next

End Sub

Public Function Clone() As PropertyList
    Dim nObject As PropertyList
    Dim I As Long

    Set nObject = New PropertyList

    For I = 1 To Count
        nObject.AddMember Me(I).Clone
    Next I

    Set Clone = nObject

    Set nObject = Nothing
End Function

Public Sub AddMember(Item As Property)
    mCol.Add Item, Item.Name
End Sub

Public Sub Add(Name As String, Optional Value As Variant)
    Dim Item As Property
    If Not Defined(Name) Then
        Set Item = New Property

        Item.Name = Name

        If Not IsMissing(Value) Then N.Value = Value
        AddMember N
    Else
        If Not IsMissing(Value) Then Me(Name).Value = Value
    End If
End Sub

Private Sub Class_Initialize()
    Set mCol = New Collection
End Sub

Private Sub Class_Terminate()
    Set mCol = Nothing
End Sub

Public Sub Clear()
    Set mCol = New Collection
End Sub

Public Property Get Count()
    Count = mCol.Count
End Property

Public Property Get Defined(Index As Variant) As Boolean
    Dim Item As Property

    On Error Resume Next

    If IsNumeric(Index) Then
        Set Item = mCol(Index)
    Else
        Set Item = mCol(UCase(Index))
    End If

    If Err.Number <> 0 Then
        Defined = False
    Else
        Defined = True
    End If

End Property

Public Property Get Item(Index As Variant) As Property
    If IsNumeric(Index) Then
        Set Item = mCol(Index)
    Else
        Set Item = mCol(UCase(Index))
    End If
End Property

Public Property Get NewEnum() As IUnknown
    Set NewEnum = mCol.[_NewEnum]
End Property

Наша версия более сложна, чем эта, с возможностями сортировки и форматирования, поэтому мы не использовали Microsoft Scripting Dictonary. Это позволяет нам динамически создавать иерархический набор свойств. Что оказалось полезным при внедрении модуля затрат в наше программное обеспечение. Так как мы постоянно добавляем или меняем поля в ответ на отзывы клиентов.

Это должно оказаться полезным при работе с гибкостью полей XML. Вы можете использовать функцию Vartype для получения точного типа варианта. При желании вы можете сохранить строки, так как VB6, как и большинство вариантов BASIC, может свободно преобразовывать числа и строки.

...