Search code examples
c++excelvb6activexpropertybag

VB and C++ ActiveX control persist its information in different way, how can I implement C++ ActiveX control to replace VB ActiveX?


Background

There was an old ActiveX control created by VB. I added this ActiveX control to my Excel workbook and set some properties. These properties were saved when the book was saved. Specifically, they were saved in UserControl_WriteProperties function using PropertyBag in VB code. So these properties persisted in the workbook until now.

My Task

I have to create a new ActiveX control using C++ to be backward compatible with the old one. I need ALL information persisted in the ActiveX control which is in my old Excel workbook. So, I implement IPersistPropertyBag to my ActiveX control.

My expectation is, when I open my old Excel workbook, all information must be retrieved correctly via PropertyBag.

Problem

I've found that the information persisted in my Excel workbook is in Stream format. I can implement IPersistStreamInit to my new ActiveX control but I don't understand the format in the Stream persisted in my Excel workbook. So, I can't retrieve the information persisted in my Excel workbook.

I wonder why the information was saved in Stream format even though they were saved via Propertybag in VB code.

Question

Is there a way to get all information persisted in the ActiveX control in this scenario? I've been finding it for two days but I can't find a way.


Solution

  • I've done this task by creating a VB6 COM dll to handle this task.

    Option Explicit
    Dim objMyPropertyBag As PropertyBag
    
    Public Sub Contents(a_content As Variant)
        objMyPropertyBag.Contents = a_content
    End Sub
    
    Public Function Read(key As String) As String
    On Error GoTo Error_Handler
        Read = objMyPropertyBag.ReadProperty(key)
    Error_Handler:
        MsgBox Err.Source & Err.Number
    End Function
    
    Private Sub Class_Initialize()
        Set objMyPropertyBag = New PropertyBag
    End Sub
    

    When I open the my old Excel workbook which contains an old ActiveX object. I do the following steps:

    1. It will come to IPersistStreamInit::Load function which give me an IStream.
    2. I read this stream and parse to VARIANT of SAFEARRAY of VT_UI1 (equal to array of BYTE) called "content".
    3. I create an instance of VB6 COM dll, called "contentReader".
    4. I call contentReader->Contents(content) (pass the SAFEARRAY I've created to it).

    Now I can read any key in the PropertyBag via contentReader->Read([in] key, [out] value).