Page 1 of 2 12 LastLast
Results 1 to 40 of 61

Thread: Instantiate internal class object with name in string

  1. #1

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Instantiate internal class object with name in string

    Hey,

    Anyone have an idea how to instantiate a class (say Class1) in our project when the name is a string?

    For instance, something like ...

    Code:
    Dim o As Class1
    Set o = InstantiateByName("Class1")
    EDIT1: Much like CallByName but for instantiation instead.

    Thanks,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  2. #2
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Instantiate internal class object with name in string

    Maybe there's some stuff in the vbRunTime-exports which allows that directly (although going
    through these, nothing obvious popped out to me - maybe Anatoli (The Trick) can help there)...

    For Classes in external Dlls, there's of course CreateObject - and besides - for the "typical Dozen"
    of Project-Private Classes one might need this for, a little routine with a 'Select Case' in it could
    be done in minutes, so the efforts to find (and test) something in the undocumented Runtime-Procs
    are probably not worth it..

    What do you need this for?
    Did you consider VBScript (which allows to define and instantiate Classes dynamically)?

    Olaf

  3. #3

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Instantiate internal class object with name in string

    Olaf, thanks for the reply.

    And it's mostly for my own edification, not really needed for any immediate project or problem.

    Basically, I was working on a project to enumerate all the internal classes in a project (any project), along all their public members and their Sub/Function/Property(get/let/set) abilities. I've successfully figured out how to enumerate all the classes and their members, but I haven't figured out how to specify anything about what the members are (Sub/Function/Property(get/let/set)).

    I thought I'd just instantiate each class, and then try CallByName on the members, figuring out what they are.

    However, then I ran into the problem of this thread. The problem is, my enumerated classes are in a string array.

    A "Select Case" approach could work, but it sort of defeats the purposes of what I was trying to do. I'd like to enumerate all of this without necessarily starting out knowing what classes and members are in the project (as just a general purpose routine).

    As I'm sure you know, this is innately available in .NET (and many other languages) with the "reflection" abilities. But apparent, there's no inherent reflection in VB6. What's interesting, is there appear to have also been some reflection abilities on older versions of VB, but they were removed in VB6.

    Anyway, as stated, no immediate need, but it often amazes me how many times these endeavors of curiosity wind up being needed for a production project later on.

    Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  4. #4

  5. #5

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Instantiate internal class object with name in string

    WOW, you've done it again, Trick. You're being true to your name.

    When in the IDE, it's obviously quite trivial. It's all based on the EbExecuteLine function, which could obviously be quite handy for more than just this.

    As a small proof-of-concept, one could start a new project with Form1, and have just a Class1, and do the following:

    Code for Class1:
    Code:
    
    Option Explicit
    
    Private Sub Class_Initialize()
        MsgBox "Initializing Class1"
    End Sub
    
    
    Code for Form1:
    Code:
    
    Option Explicit
    '
    Private Declare Function EbExecuteLine Lib "vba6.dll" (ByVal pStringToExec As Long, ByVal Foo1 As Long, ByVal Foo2 As Long, ByVal fCheckOnly As Long) As Long
    '
    
    Private Sub Form_Load()
        Dim o As IUnknown
        '
        Set o = IdeCreateInstance("Class1")
    End Sub
    
    Private Function IdeCreateInstance(ByVal Class As String) As IUnknown
        ' Only for IDE. 
        '
        EbExecuteLine StrPtr(Me.Name & ".OneCellQueue New " & Class), 0, 0, 0
        '
        Set IdeCreateInstance = OneCellQueue(Nothing)
        If IdeCreateInstance Is Nothing Then
            Err.Raise 8, , "Specified class '" + Class + "' is not defined."
            Exit Function
        End If
    End Function
    
    Private Function OneCellQueue(ByVal refIn As IUnknown) As IUnknown
        ' Returns what was "previously" passed in as refIn, 
        ' and then stores the current refIn for return next time. 
        '
        Static o As IUnknown
        '
        Set OneCellQueue = o
        Set o = refIn
    End Function
    
    And voila, reflection in the VB6 IDE.

    I've also cleaned up how to do it from an executable. I'll post that in the next post.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  6. #6

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Instantiate internal class object with name in string

    If you "think through" the code below, it becomes clear that the secret to instantiating an object with a string in an executable is all wrapped up in the "__vbaNew" call found in the msvbvm60.dll.

    Code:
    
    Private Declare Function ExeNew Lib "msvbvm60" Alias "__vbaNew" (lpObjectInfo As Any) As IUnknown
    
    
    However, this function requires the lpObjectInfo pointer of the class. Interestingly, I just happen to have that lpObjectInfo pointer in my UDT array which contained my list of classes. However, for those who have nothing but the class name in a string, here's the code to dig out the lpObjectInfo pointer, and then instantiate the class.

    I've included the code that was presented as proof-of-concept in post #5 as well. Therefore, calls to the following procedure should work in either the IDE or an executable.

    As a note, for it to work correctly in the IDE, the following code MUST be placed in a standard (BAS) module named NameBasedObjectFactory.

    I'll leave you on your own to build a project to test it. You could just include a Class1 in your project like I suggested in post #5, and then instantiate it with this code. All you need to do is call CreateObjectPrivate with your class name, and it'll return your object.

    Code:
    Option Explicit
    '
    ' This must be a standard (BAS) module and it MUST be named "NameBasedObjectFactory" if things are to work correctly.
    '
    #Const ALSO_USERCONTROLS = False ' Not tested.
    '
    Private Declare Function EbExecuteLine Lib "vba6.dll" (ByVal pStringToExec As Long, ByVal Foo1 As Long, ByVal Foo2 As Long, ByVal fCheckOnly As Long) As Long
    '
    Private Declare Function lstrcmpi Lib "kernel32" Alias "lstrcmpiA" (ByVal s1 As String, ByVal s2 As Long) As Long
    Private Declare Function ExeNew Lib "msvbvm60" Alias "__vbaNew" (lpObjectInfo As Any) As IUnknown
    Private Declare Function AryPtr Lib "msvbvm60" Alias "VarPtr" (ary() As Any) As Long
    Private Declare Sub GetMem4 Lib "msvbvm60" (ByVal lpAddress As Long, dst As Any)
    Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal lpAddress As Long, ByVal nv As Long)
    '
    Private Type EXEPROJECTINFO
        Signature                       As Long
        RuntimeVersion                  As Integer
        BaseLanguageDll(0 To 13)        As Byte
        ExtLanguageDll(0 To 13)         As Byte
        RuntimeRevision                 As Integer
        BaseLangiageDllLCID             As Long
        ExtLanguageDllLCID              As Long
        lpSubMain                       As Long
        lpProjectData                   As Long
        ' < There are other fields, but not declared, not needed. >
    End Type
    '
    Private Type ProjectData
        Version                         As Long
        lpModuleDescriptorsTableHeader  As Long
        ' < There are other fields, but not declared, not needed. >
    End Type
    '
    Private Type MODDESCRTBL_HEADER
        Reserved0                       As Long
        lpProjectObject                 As Long
        lpProjectExtInfo                As Long
        Reserved1                       As Long
        Reserved2                       As Long
        lpProjectData                   As Long
        guid(0 To 15)                   As Byte
        Reserved3                       As Integer
        TotalModuleCount                As Integer
        CompiledModuleCount             As Integer
        UsedModuleCount                 As Integer
        lpFirstDescriptor               As Long
        ' < There are other fields, but not declared, not needed. >
    End Type
    '
    Private Enum MODFLAGS
        mfBasic = 1
        mfNonStatic = 2
        mfUserControl = &H42000
    End Enum
    '
    Private Type MODDESCRTBL_ENTRY
        lpObjectInfo                    As Long
        FullBits                        As Long
        Placeholder0(0 To 15)           As Byte
        lpszName                        As Long
        MethodsCount                    As Long
        lpMethodNamesArray              As Long
        Placeholder1                    As Long
        ModuleType                      As MODFLAGS
        Placeholder2                    As Long
    End Type
    '
    
    Public Function CreateObjectPrivate(ByVal Class As String) As IUnknown
        '
        ' When you work in the compiled form and the different mechanisms will be used by the IDE.
        If InIDE Then
            Set CreateObjectPrivate = IdeCreateInstance(Class)
        Else
            Set CreateObjectPrivate = ExeCreateInstance(Class)
        End If
    End Function
    
    Private Function IdeCreateInstance(ByVal Class As String) As IUnknown
        ' Only for IDE.
        '
        ' IMPORTANT: The module this is in MUST be named NameBasedObjectFactory.
        '
        EbExecuteLine StrPtr("NameBasedObjectFactory.OneCellQueue New " & Class), 0, 0, 0
        '
        Set IdeCreateInstance = OneCellQueue(Nothing)
        If IdeCreateInstance Is Nothing Then
            Err.Raise 8, , "Specified class '" + Class + "' is not defined."
            Exit Function
        End If
    End Function
    
    Private Function OneCellQueue(ByVal refIn As IUnknown) As IUnknown
        ' Returns what was "previously" passed in as refIn,
        ' and then stores the current refIn for return next time.
        '
        Static o As IUnknown
        '
        Set OneCellQueue = o
        Set o = refIn
    End Function
    
    Private Function ExeCreateInstance(ByVal Class As String) As IUnknown
        ' Only for Executable.
        '
        Dim lpObjectInformation As Long
        '
        ' Get the address of a block of information about the class.
        ' And then create an instance of this class.
        ' If a class is not found, generated an error.
        '
        If Not GetOiOfClass(Class, lpObjectInformation) Then
            Err.Raise 8, , "Specified class '" + Class + "' does not defined."
            Exit Function
        End If
        '
        Set ExeCreateInstance = ExeNew(ByVal lpObjectInformation)
    End Function
    
    Private Function GetOiOfClass(ByVal Class As String, ByRef lpObjInfo As Long) As Boolean
        ' Only for Executable.
        '
        ' lpObjInfo is a returned argument.
        ' Function returns true if successful.
        '
        Static Modules()        As NameBasedObjectFactory.MODDESCRTBL_ENTRY
        Static bModulesSet      As Boolean
        Dim i                   As Long
        '
        #If ALSO_USERCONTROLS Then
            Const mfBadFlags As Long = mfUserControl
        #Else
            Const mfBadFlags As Long = 0
        #End If
        '
        If Not bModulesSet Then
            ReDim Modules(0)
            If LoadDescriptorsTable(Modules) Then
                bModulesSet = True
            Else
                Exit Function
            End If
        End If
        '
        ' We are looking for a descriptor corresponding to the specified class.
        For i = LBound(Modules) To UBound(Modules)
            With Modules(i)
            If lstrcmpi(Class, .lpszName) = 0 And CBool(.ModuleType And mfNonStatic) And Not CBool(.ModuleType And mfBadFlags) Then
                    lpObjInfo = .lpObjectInfo
                    GetOiOfClass = True
                    Exit Function
                End If
            End With
        Next i
    End Function
    
    Private Function LoadDescriptorsTable(dt() As MODDESCRTBL_ENTRY) As Boolean
        ' Only for Executable.
        '
        Dim lpEPI               As Long
        Dim EPI(0)              As NameBasedObjectFactory.EXEPROJECTINFO
        Dim ProjectData(0)      As NameBasedObjectFactory.ProjectData
        Dim ModDescrTblHdr(0)   As NameBasedObjectFactory.MODDESCRTBL_HEADER
        '
        ' This procedure is called only once for the project.
        ' Get the address of the EPI.
        '
        If Not FindEpiSimple(lpEPI) Then
            Err.Raise 17, , "Failed to locate EXEPROJECTINFO structure in process module image."
            Exit Function
        End If
        '
        ' From EPI find location PROJECTDATA, from PROJECTDATA obtain location
        ' of Table header tags, the title tags, and obtain the number of address sequence.
        '
        SaMap AryPtr(EPI), lpEPI
        SaMap AryPtr(ProjectData), EPI(0).lpProjectData: SaUnmap AryPtr(EPI)
        SaMap AryPtr(ModDescrTblHdr), ProjectData(0).lpModuleDescriptorsTableHeader: SaUnmap AryPtr(ProjectData)
        SaMap AryPtr(dt), ModDescrTblHdr(0).lpFirstDescriptor, ModDescrTblHdr(0).TotalModuleCount: SaUnmap AryPtr(ModDescrTblHdr)
        '
        LoadDescriptorsTable = True
    End Function
    
    Private Function FindEpiSimple(ByRef lpEPI As Long) As Boolean
        ' Only for Executable.
        '
        Dim DWords()            As Long: ReDim DWords(0)
        Dim PotentionalEPI(0)   As NameBasedObjectFactory.EXEPROJECTINFO
        Dim PotentionalPD(0)    As NameBasedObjectFactory.ProjectData
        Dim i                   As Long
        '
        Const EPI_Signature     As Long = &H21354256 ' "VB5/6!"
        Const PD_Version        As Long = &H1F4
        '
        ' We are trying to get a pointer to a structure EXEPROJECTINFO. The address is not stored anywhere.
        ' Therefore the only way to find the structure - find its signature.
        '
        ' Current research implementation simply disgusting: it is looking for signatures from the
        ' very beginning of the image, including those places where it can not be known. And find out
        ' Behind the border of the image, if you find a signature within the virtual image failed.
        ' This will likely result in AV-exclusion. But its (implementation) is compact.
        '
        SaMap AryPtr(DWords), App.hInstance
        Do
            If DWords(i) = EPI_Signature Then
                SaMap AryPtr(PotentionalEPI), VarPtr(DWords(i))
                SaMap AryPtr(PotentionalPD), PotentionalEPI(0).lpProjectData
                If PotentionalPD(0).Version = PD_Version Then
                    lpEPI = VarPtr(DWords(i))
                    FindEpiSimple = True
                End If
                SaUnmap AryPtr(PotentionalPD)
                SaUnmap AryPtr(PotentionalEPI)
                If FindEpiSimple Then Exit Do
            End If
            i = i + 1
        Loop
        SaUnmap AryPtr(DWords)
    End Function
    
    Private Sub SaMap(ByVal ppSA As Long, ByVal pMemory As Long, Optional ByVal NewSize As Long = -1)
        Dim pSA As Long: GetMem4 ppSA, pSA:
        PutMem4 pSA + 12, ByVal pMemory: PutMem4 pSA + 16, ByVal NewSize
    End Sub
    
    Private Sub SaUnmap(ByVal ppSA As Long)
        Dim pSA As Long: GetMem4 ppSA, pSA
        PutMem4 pSA + 12, ByVal 0: PutMem4 pSA + 16, ByVal 0
    End Sub
    
    Private Function InIDE() As Boolean
        On Error GoTo InTheIDE
        Debug.Print 1 / 0
        Exit Function
    InTheIDE:
        InIDE = True
    End Function

    And Voila, reflection for classes fully implemented in VB6.

    Should I post this in the CodeBank?

    Enjoy,
    Elroy

    EDIT1: It turns out the lpObjectInfo I had wouldn't work because it changes value when things are moved into memory. Therefore, all of these procedure listed above are needed to instantiate an object from one of your internal classes from a string. Also, just FYI, once instantiated, TypeName works as expected.
    Last edited by Elroy; Aug 21st, 2016 at 11:34 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7
    Hyperactive Member
    Join Date
    Jul 2013
    Posts
    400

    Re: Instantiate internal class object with name in string

    Should I post this in the CodeBank?
    Absolutely
    Carlos

  8. #8
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Instantiate internal class object with name in string

    Well - now the only thing remaining is, to come up with a good problem for this solution...

    Olaf

  9. #9

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Instantiate internal class object with name in string

    It was actually this thread by some1uk03 that got me thinking about it. It's not precisely what he was looking for, but it's very close.

    Also, it's been fun, and I just really don't like VB6 having weaknesses (which I know it does), when stood up next to VB.NET and other languages. At least, it no longer has this weakness.

    Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  10. #10
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Instantiate internal class object with name in string

    VB6 supports full reflection over the ITypeInfo-Interfaces already -> for *.dll and *.ocx binaries...
    (and there only for its Public Classes/Interfaces which are "supposed to be exposed")

    Can't *really* think up a good reason, why someone would want that for Private Classes
    (which were defined Private for a reason)...

    Olaf

  11. #11
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Elroy View Post
    Should I post this in the CodeBank?
    You probably should get permission first from firehacker.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  12. #12

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Instantiate internal class object with name in string

    Bonnie,

    Ahhh, I didn't realize that he posted in these threads. Yes, it's definitely highly derivative of his work. I wasn't trying to imply otherwise. I was going to attribute it to Telepathist (which is his handle in the thread where I found it, see post #4 above).

    Yes, now that I know he visits these forums, I'll send him a PM, and see what he thinks.

    Thank You,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  13. #13
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Schmidt View Post
    Can't *really* think up a good reason, why someone would want that for Private Classes
    (which were defined Private for a reason)...

    Olaf
    All classes in a Std-EXE are private -- there is no option here. Otherwise we would gladly mark them as Public so to be able to instantiate them with CreateObject("Project1.Class1") for instance.

    Runtime's CreateObject for sure is augmented version of COM's CoCreateInstance and it's rather unfortunate that private class instantiation from code in the *same* project is not baked in (the way New keyword is enabled). People now have to resort to massive Select Case statements unless using Elroy's module.

    I had to use it recently in a test-harness project of mine where the project's .vbp file was generated dynamicly (random number of classes added to it) and the final executable had to operate on an instance of a class whose name was passed as first parameter to the same executable. I had to generate a Select Case to resolve the whole name to instance trouble or use Elroy's module to simplify this exercise.

    Just sharing my $.02 worth a real-world use-case. . .

    cheers,
    </wqw>

  14. #14

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Elroy View Post
    Should I post this in the CodeBank?

    Enjoy,
    Elroy
    I am happy people find my module (NameBasedObjectFactory) useful, but I found it disgusting that you decided to cut any mention of its original authorship completely prior to redistributing it here and in other places.

    The original code posted on VBStreets forum had quite typical header, containing the name of its author (me), creation and modification history, description (in Russian) and a copyright sign Ā©.
    Code:
    ' ******************************************************************************
    ' *     Fire-Lines Ā© 2011                                                      *
    ' *     Модуль:                                                                *
    ' *         NameBasedObjectFactory                                             *
    ' *     Описание:                                                              *
    ' *         Этот модуль обеспечивает возможность создавать экземпляры классов  *
    ' *         по строковому имени соответствующего класса.                       *
    ' *     Автор:                                                                 *
    ' *         Владислав Петровский (firehacker)                                  *
    ' *     История изменений:                                                     *
    ' *         *   2011-05-21  firehacker  Файл создан.                           *
    ' *     Примечания:                                                            *
    ' *         Переименование модуля вызовет его неработоспосбность!              *
    ' *     Текущая версия: 1.0.0                                                  *
    ' *                                                                            *
    ' ******************************************************************************
    You have stripped all the comments replacing it with english equivalents, but copyright info is completely removed! Isn't that true that as a person who spent quite some time reverse-engineering MSVBVM60.DLL, I deserve to be mentioned in the source code?

    Another modifications that I see is that you have renamed some of my original procedure/variable names. I am not sure whether it was done because original naming scheme was for some reason annoying for you, or just to bring more differences into the source code file.

    NbofRtlSimpleNew was renamed to ExeNew.
    NbofDbgCreateInstance was renamed to IdeCreateInstance.
    NbofRtCreateInstance was renamed to ExeCreateInstance.
    NbofGetOiOfClass was renamed to GetOiOfClass.
    NbofLoadDescriptorsTable was renamed to LoadDescriptorsTable.
    NbofFindEpiSimple was renamed to FindEpiSimple.

    So, you basically hate "Nbof" prefix which stands for NameBasedObjectFactory, which is the name of the module FYI. Luckily you haven't touch Sa in SaMap and SaUnmap, which is prefix for SAFEARRAY. That "Nbof" prefix was not only my naming style/convention, but also a measure against potential name conficts.

    For absolutely unknown reason the conditional-compilation constant DENY_USERCONTROLS was renamed into ALSO_USERCONTROLS. This changed the meaning of its name to almost opposite, but didn't change anything in its behaviour. Normally, one shoudn't use this module to create new instances of UserControl-classes, and DENY_USERCONTROLS was set to True to disallow such attempts.

    You have also changed
    Code:
    ModuleType                      As NameBasedObjectFactory.MODFLAGS
    to
    Code:
    ModuleType                      As MODFLAGS
    I don't understand why you think the last one is better. First, it was a measure against someone's wish to rename this module: this line won't compile after module gets renamed. Secondly, it was also a protection from possible name ambiguity.

    As for comments... You have translated it from Russian to English, but most likely Google-translate was used. Translation is inaccurate in many places. What the heck is "AV-exclusion"? In English it's called "exception", not "exclusion". I would completely rewrite comments in English, there are so many misinterpretations.

    But what is the most frustrating for me (except for the fact of deleting authorship information), is the way you determine whether you work under IDE on in form of compiled binary. For another unexplainable reason you have changed my elegant way of testing for IDE/compiled, that was originally described here, to the uggly method that is based on catching division-by-zero error.

    Why the way you've used is ugly and the one I proposed is elegant?

    Because in my approach everything is resolved at compile time.

    With this code:
    Code:
        Dim IDE_MODE As Boolean: Debug.Assert LetTrue(IDE_MODE)
        If IDE_MODE Then
            Call foo()
            Call foo()
            Call foo()
            Call foo()
            Call foo()
        Else
            Call bar()
            Call bar()
            Call bar()
            Call bar()
            Call bar()
        End If
    ...
    Private Function LetTrue(b As Boolean) As Boolean: b = True: LetTrue = True: End Function
    After you compile you project, you can open it under a disassembler. You'll find that there is no else-branch at all. All calls to the bar() will be eliminated during compilation and will not be placed into compiled EXE file. The implementation of bar() itself will be also eliminated (if it's not called from anywhere else). LetTrue, which is auxillary stub here used as part of IDE/complied determination trick, wont be placed into EXE.

    This works almost like if it were conditional compilation constant for IDE/not IDE determination.

    But in your approach everything is resolved at run-time. Both foo-foo-foo-foo and bar-bar-bar calls will be placed into EXE. Both foo() and bar() implementationы will be compiled and occupy space in EXE-file. Your InIDE function will also become a part of EXE file and will be called each time CreateObjectPrivate is being called. In my approach LetTrue isn't called at all (when project is compiled).

    Let's see two code examples that differ only the way IDE/not-IDE mode is examined. In both cases 100 millions of iteration calling DoSomeJob is done. DoSomeJob contains variative behavior (depending on IDE status):

    My approach:
    Code:
    Sub DoSomeJob(ByRef SomeVar As Long)
        Dim InIde As Boolean: Debug.Assert MakeTrue(InIde)
        If InIde Then
            AnotherRubbish
            AnotherRubbish
            AnotherRubbish
            SomeVar = SomeVar - 1
            AnotherRubbish
            AnotherRubbish
            AnotherRubbish
            AnotherRubbish
        Else
            SomeVar = SomeVar + 1
        End If
    End Sub
    
    Sub AnotherRubbish()
        Beep
        DoEvents
        QBColor 14
    End Sub
    
    Function MakeTrue(ByRef x As Boolean) As Boolean
        x = True: MakeTrue = True
    End Function
    Classic approach (your approach):
    Code:
    Sub DoSomeJob(ByRef SomeVar As Long)
        If InIDE Then
            AnotherRubbish
            AnotherRubbish
            AnotherRubbish
            SomeVar = SomeVar - 1
            AnotherRubbish
            AnotherRubbish
            AnotherRubbish
            AnotherRubbish
        Else
            SomeVar = SomeVar + 1
        End If
    End Sub
    
    Sub AnotherRubbish()
        Beep
        DoEvents
        QBColor 14
    End Sub
    
    Private Function InIDE() As Boolean
        On Error GoTo InTheIDE
        Debug.Print 1 / 0
        Exit Function
    InTheIDE:
        InIDE = True
    End Function
    Both are preceeded by the following code (common part), that measures and reports execution time and issues a loop with 100 millions of iterations:
    Code:
    Option Explicit
    
    Public Declare Sub QueryPerformanceCounter Lib "kernel32" (ByRef pi64Ctr As Currency)
    Public Declare Sub QueryPerformanceFrequency Lib "kernel32" (ByRef pi64Freq As Currency)
    
    Sub Main()
        Dim tsStart As Currency
        Dim tsEnd   As Currency
        Dim Freq    As Currency: QueryPerformanceFrequency Freq
        
        Dim qqq     As Long
        
        QueryPerformanceCounter tsStart
        BigLoop qqq
        QueryPerformanceCounter tsEnd
        
        MsgBox qqq & " - " & Format((tsEnd - tsStart) / Freq, "0.000 seconds")
    End Sub
    
    Sub BigLoop(ByRef jjj As Long)
        Dim i As Long
        For i = 1 To 100000000
            DoSomeJob jjj
        Next i
    End Sub
    Now let's compile and open both binaries under OllyDbg to see disassembly listings of the generated code. For the sake of saving screen space I have enabled "Compile for small code" and "Remove Integer Overflow Checks" options.

    First of all, compare two lists of entities that are included into binary files:

    Pay you attention, that MakeTrue and AnotherRubbish procedures are not included into binary file in case of using my approach at all. Unlike so-called "classic approach", where both InIDE and AnotherRubbish (dead code) became a part of EXE file.

    Not let's see disassembly listing of the procedures:

    Very compact and elegant. Debug.Assert is throwed away together with MakeTrue() invocation at compile time. Boolean variable is eliminated by optimizer. If/Else/EndIf branching is also optimized, the content of Else-branch is throwed away. MakeTrue procedure is eliminated during link time as it is not referenced from anywhere else. No traces of IDE-only code or IDE/not-IDE checks left in the binary .

    This is as effective as #if..#endif preprocessor approach in C/C++ compilers.

    Now let's see what code is generated for your approach:


    Look how much code (totally unnecessay code) is generated and executed each time. Let's compare again side-by-side:


    You can judge by the result of measurements of execution time:


    Your approach is more than ten times slower! An order of magnitude!

    If I simplify this code snippets as much as possible, leaving only those statements that determine current mode of operation and measure time under IDE, you aproach shows bad results again:


    To summarize:
    1. You removed file header block having copyright/author/date/version information. Very disgraceful. You could reformat it, of course, but keeping author's name in credits.
    2. You translated some comments from Russian to English. But the translation looks like it was done by Google Translate rather than by human who understands what he's writing about.
    3. You changed names of procedures a bit, which is a matter of taste and naming conventions.
    4. You replaced elegant IDE-vs.-compiled determination code with a bulky and inefficient one.

  15. #15
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Instantiate internal class object with name in string

    @firehacker: Btw, is VBStreets some kind of private forum/club? I cannot find the registration form.

    If registering is some kind of "apprentice" test I mesirably failed "hacking" it with http://vbstreets.ru/register.php :-))

    cheers,
    </wqw>

  16. #16
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,872

    Re: Instantiate internal class object with name in string

    @firehacker, in post #12 you are mentioned as the original author:
    Bonnie,

    Ahhh, I didn't realize that he posted in these threads. Yes, it's definitely highly derivative of his work. I wasn't trying to imply otherwise. I was going to attribute it to Telepathist (which is his handle in the thread where I found it, see post #4 above).

    Yes, now that I know he visits these forums, I'll send him a PM, and see what he thinks.

    Thank You,
    Elroy

  17. #17

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Instantiate internal class object with name in string

    firehacker,

    I'm not sure what to say. When I read everything, I think I did try to attribute it to you. However, I apologize for any misunderstandings. I tried to go back through my PMs, but they don't go back that far.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  18. #18
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Schmidt View Post
    Can't *really* think up a good reason, why someone would want that for Private Classes
    (which were defined Private for a reason)...
    I used this in a .Net program to write a TCP/IP protocol. The idea was that my client and server components would communicate via messages and these messages were represented by classes. For example, I might have a message called GetFileSizeRequest which would actually be a class that is derived from a base class, something like MessageBase. Long story short, I didn't want to have to write a bunch of boilerplate for every single type of message there was so I put all the protocol classes along with their Winsock wrappers in a library and used reflection to enumerate over all of the different message types. When I wanted to create a new message type, all I had to do was derive it from MessageBase and the library would automatically figure out how to handle it. Reflection made it very easy to implement this type of thing. Via reflection the library was automatically aware of all different message types and was capable of identifying them and all I had to do was inherit from a specific base class. It greatly improved my productivity.

    Although these classes were public, I was toying with the idea of implementing an even higher layer of abstraction and hiding all of this behind Friend classes(basically private classes). For example, I could have a class that just connects and performs a file transfer using very simple methods but internally they would use the different message classes to get it done. All the outside user would see is a simple call to something like TransferFiles. The internal workings would need the ability to enumerate Friend classes to function correctly.

    So yea, there is use for the ability to enumerate private classes.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  19. #19
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Niya View Post
    So yea, there is use for the ability to enumerate private classes.
    In my opinion, there isn't - not in "real world scenarios" - meaning "at Binary-Level"...
    (Private Classes were specifically declared this way, to remain "unreachable" from outside the Binary)

    The only exception is, when one works at "compiler-level" (at the level of Project-Source-Files ...wqweto brought an example for that).
    But when your tool works already at SourceFile-level, then you can of course "inject any Source-Text" directly into those files ...
    (in wqwetos case for example, a specific Sub Main() which contains an instantiation-line for the specific ClassName he then wouldn't have to pass on the CommandLine).

    As for your FileTransfer-"story"- it seems quite a bit "overengineered" to me, when it would require an enumeration of interface-members or -classes.
    (since any File consists of Bytes - and Bytes are what's finally transferred over sockets - so there's only a single, very simple and generically working RPC-function needed).

    Olaf
    Last edited by Schmidt; Jan 29th, 2021 at 03:44 AM.

  20. #20
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Schmidt View Post
    As for your FileTransfer-"story"- it seems quite a bit "overengineered" to me, when it would require an enumeration of interface-members or -classes.
    (since any File consists of Bytes - and Bytes are what's finally transferred over sockets - so there's only a single, very simple and generically working RPC-function needed).
    In my case the problem was matching a specific binary signature received on a socket to a specific message class. The classical way of doing it would have required a very large switch(Select Case in VB) statement, a switch for every binary signature to class match. So for example, if I received, lets say I decided that &HFF01 was meant to be a request for a file size. I would need to match this to a FileSizeRequest class. The classical way, I would have to manually include a check for this in the source code in a Select Case block. By using reflection, I could avoid always having update the Select Case block every time I created a new kind of message.

    Here is an example of such an implementation:-
    Code:
        Public MustInherit Class MessageBase
    
        End Class
    
        <MessageSignature(&HFF01S)>
        Public Class FileSizeRequest
            Inherits MessageBase
        End Class
    
        <MessageSignature(&HFF02S)>
        Public Class ComputerNameRequest
            Inherits MessageBase
        End Class
    
        Public Function IdentifyMessage(ByVal messageSignature As Short) As String
    
            'Get all types derived from MessageBase in the current assembly
            Dim messageTypes As IEnumerable(Of Type) = Assembly.GetExecutingAssembly.GetTypes.Where(Function(t) t.IsSubclassOf(GetType(MessageBase)))
    
            'Search each MessageBase type until a matching signature is found
            For Each mt As Type In messageTypes
    
                'Look for the MessageSignatureAttribute on the current MessageBase derived type
                Dim sigAttr As Attribute = mt.GetCustomAttributes.FirstOrDefault(Function(attr) TypeOf attr Is MessageSignatureAttribute)
    
                'If it doesn't have a MessageSignatureAttribute then throw an exception
                'to alert the developer that he forgot to add one to this specific class
                If sigAttr Is Nothing Then
                    Throw New Exception("MessageBase derived class must be annotated with a MessageSignatureAttribute")
                Else
    
                    'Read the MessageSignatureAttribute to determine if the signature matches the
                    'signature we are looking for
                    If DirectCast(sigAttr, MessageSignatureAttribute).Signature = messageSignature Then
    
                        'Return the name of the class the represents the message
                        Return mt.Name
                    End If
                End If
    
            Next
    
            'No message class matching the signature was found
            Return ""
        End Function
    
    
        <AttributeUsage(AttributeTargets.Class)>
        Public Class MessageSignatureAttribute
            Inherits Attribute
    
            Private _signature As Short
    
            Public Sub New(ByVal signature As Short)
                _signature = signature
            End Sub
    
            Public ReadOnly Property Signature As Short
                Get
                    Return _signature
                End Get
            End Property
        End Class
    The key to making the above work is a combination of reflection and metadata in the form of attributes. All I have to do to create a new type of message is derive from MessageBase and annotate the class with it's signature. If I did this:-
    Code:
    Debug.WriteLine(IdentifyMessage(&HFF01S))
    It would output this:-
    Code:
    FileSizeRequest
    I can tell you from experience that this method is very low maintenance. I can match binary signatures to classes automatically. Without reflection and metadata I would have to use Select Case like this:-
    Code:
        Public Function IdentifyMessageClassic(ByVal messageSignature As Short) As String
    
            Select Case messageSignature
                Case &HFF01S
                    Return "FileSizeRequest"
                Case &HFF02S
                    Return "ComputerNameRequest"
                Case Else
                    Return ""
            End Select
    
        End Function
    In my opinion that's a lot of unnecessary book keeping. You can end up with some very large Select Case blocks when you have a lot of message types and it's a nightmare to maintain when you're always renaming, adding and removing things. You could easily forget to update that Select Case after changing the name of one of the classes or removing one. I would rather have all this done automatically so I can spend my time actually working on the stuff that is important.

    Reflection helps solve a lot of these kinds of problems.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  21. #21
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Niya View Post
    Reflection helps solve a lot of these kinds of problems.
    Not sure, what you're trying to tell me (COM-Dlls support reflection as well).

    And as for your example - I'd associate MessageHandler-Endpoints with Method-Names (not Class-Names)
    (all the different File-related Messages then handled via a bunch of methods which are sitting in a cFileStuff Handler-Class)

    Olaf

  22. #22
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Schmidt View Post
    Not sure, what you're trying to tell me (COM-Dlls support reflection as well).
    Let me clarify. The ability to reflect over private classes can be useful.

    Quote Originally Posted by Schmidt View Post

    And as for your example - I'd associate MessageHandler-Endpoints with Method-Names (not Class-Names)
    (all the different File-related Messages then handled via a bunch of methods which are sitting in a cFileStuff Handler-Class)

    Olaf
    I usually put that at a higher level of abstraction. Inside the cFileStuff I would have all the code that deals with the message classes. At the highest level of abstraction, you do not see these messages. You make calls like cFileStuff.Download to download files. Events or callbacks can be used for notification, for example when a file transfer is complete. The message classes are not supposed to be exposed at this level. It's part of the internals.

    I see what you're saying though and it depends on the complexity of the protocols. For very simple protocols that aren't meant for complex communication, I won't even bother with all this. I'll just use Winsock+byte arrays more or less directly.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  23. #23
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    38,989

    Re: Instantiate internal class object with name in string

    This is a weird thread.

    Elroy said he'd PM firehacker. Firehacker comes back FOUR YEARS LATER. I agree that code should be attributed, though it does look like it was (I didn't look in any code files)...but four years??

    And then it's continuing with a discussion on whether or not it is useful, which isn't entirely off topic, but seems a bit irrelevant.
    My usual boring signature: Nothing

  24. #24
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Elroy View Post
    I tried to go back through my PMs, but they don't go back that far.
    I still have them.








    firehacker, welcome to VBForums! I hope you'll post more often, we'd love to have more VB6 experts here.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  25. #25
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Shaggy Hiker View Post
    This is a weird thread.

    Elroy said he'd PM firehacker.
    He probably didn't (Edit: according to Bonnies post above - I stand corrected...)

    He had "run-ins" with others about that later on - as e.g. with Tanner Helland here:
    https://www.vbforums.com/showthread....=1#post5240533

    I think it was after Tanners "scolding", that he put in the "kinda apologetic" signature we still see today.

    Olaf
    Last edited by Schmidt; Jan 29th, 2021 at 01:32 PM.

  26. #26
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Bonnie West View Post
    I still have them...

    firehacker, welcome to VBForums! I hope you'll post more often, we'd love to have more VB6 experts here.
    Well, if that isn't Bonnie West ... in the flesh...

    BTW, I agree fully with your kind welcome for "firehacker" - and (regarding "posting-presence" here) -
    would very much like, when you'd follow your own suggestion...

    Olaf

  27. #27
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,996

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Schmidt View Post
    Well, if that isn't Bonnie West ... in the flesh...

    BTW, I agree fully with your kind welcome for "firehacker" - and (regarding "posting-presence" here) -
    would very much like, when you'd follow your own suggestion...

    Olaf

  28. #28

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by wqweto View Post
    @firehacker: Btw, is VBStreets some kind of private forum/club? I cannot find the registration form.

    If registering is some kind of "apprentice" test I mesirably failed "hacking" it with http://vbstreets.ru/register.php :-))

    cheers,
    </wqw>
    No, it isn't any kind of apprentice test, it is actually my pain. That's a sad story. Let me explain.

    For years VBStreets was one the popular (if not the most popular) community of VB and VBA developers from Russia and russian-speaking countries (which are most of CIS countries). We have even released our own book (ISBN=9785977500883). However, starting from 2010 popularity of classic VB and our forums started to decay. But the amount of spambots attacking our forums was growing exponentionally. Neither ReCAPTCHA nor customized Q&A-captcha with questions basing on riddles and proverbs helped against them. I suspect all these spam accounts were being created by real humans (likely, working for food) rather than by automated software. So, speaking about new users registration rate, in the end of 2016 it could be described as 1 real human account per 50 spambot accounts. However, we were still rejecting their massive attacks.

    In the very end of 2016, two events took place:
    1. Our virtual server suddenly stopped to respond. The support team of the hosting provider was feeding me with promises for quite a long period of time: at the day of incident they were promising to fix everything in a few hours, then they were talking about few days, and finally, after almost 10 days of their hard work, they said that disk infrastructure has died and they are are not going to revive the cluster of affected servers! I was given a raw dump containing parts of damaged filesystem and a promo-code allowing me to order a new server for free (for several months, and with significant discount afterwards ā€” as a compensation for their fault). On the other hand, after one day of outage independently from their attempts to fix SAN/RAID/or whatever, I've started considering redeployment of the server from the backup. And here is the point when another terrible truth opened: although backups were created regularly, they weren't been tested properly ā€” it turned out that all backups for last 9 months are damaged because of truncation during transfer from one server to another machine.
    2. Exactly at the same time I was infected by varicella aka chickenpox. And I should confirm an opinion that when you got infected this virus for the first time in adult age, the disease shows itself with a way severe symptoms and higher risk of complications. And indeed, in my case it was carrying out very sorely and caused lots of complications. I can just say that after 2017 and up until today my health was never recovered to the level as it was before meeting Varicella-Zoster virus. All these years can be described as an infinite sequence of troubles, illnesses, one changing another.

    So, there was two-week outage caused by server disk subsystem crash, and at the same time I was suffering from very high temperature together with severe pain all over the whole skin surface as if I had burns everywhere. Nevertheless, I managed to rebuild the server (using parts of my own damaged backups, raw dumps of damaged file system (received from hosting support team) and even google cache) and revived VBStreets! We lost only like 5 topics, 10 new users and 50 attachments, which was looking great in the situation when you don't have fresh backups.

    However, VBStreets was not the only project living on the crashed server. Few more sites (which were also my projects) lived there. All of them together with VBStreets were relying on my own emailing subsystem, built using Exim, Dovecot and custom frontend, but highly customized. Whereas VBStreets was back live and running 2 or 3 weeks after the incident, neither rest of my projects nor common emailing infrastructure was fixed at that time.

    And since VBStreets was unable to send notifications and registration confirmations, I decided to temporarily disable registration at all.
    This decision was mostly driven by the enormous pressure of spambots. And I never planned to disable registration permanently. But to my shame, I still have recovered neither common emailing infrastructure, nor the rest of my projects (could you believe that before that last incident all these projects were hosted on Ukrainian Hosting.ua service, and eventually my server was damaged in massive fire in the datacenter as well as hundreds of other servers? Apparently I am a lucky person...). Who might know that my health troubles would be continuous?

    I am still planning to fix email subsystem. It required migration to another server, because our current server policy restricts mass emailing. Yet another complication is that when you rent a server, you may be given with IP address which is in the blacklist of every major email provider. It takes too much time to resolve this situation with abuse teams, so that it's probably easier to reorder server or buy an additional IP until you get not compromised IP.

    BUT!

    Yesterday I enabled registration on VBStreets (without email confirmation)! Only 1 real human have registered so far, and zero(!) spammers. Apparently spammers excluded our forums from their lists. But they can strike back :-)

    So, hurry up! Registration on VBStreets is now opened!
    http://bbs.vbstreets.ru/ucp.php?mode=register

    I can disable it at any moment when spammers get clue that registration is open again. And it will remain disabled until I fix emailing subsystem and apply some modern antispam solution. If you going to register, please also take care to remember your password, since password recovery won't work (except for manual recovery by PMing or emailing me)!

  29. #29

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Arnoutdv View Post
    @firehacker, in post #12 you are mentioned as the original author:
    I know that I was mentioned in that topic, but Elroy edited my original module (which we call "a brick" on VBStreets, because there is collection of a so-called bricks ā€” ready-to-use modules) cutting the header block from it.

    And now my module is being distributed in several places (including GitHub) without any mention of me. Thanks to Elroy.


    When I read everything, I think I did try to attribute it to you.

    Quote Originally Posted by Elroy
    I tried to go back through my PMs, but they don't go back that far.
    But I wasn't visiting VBForums until this month, so haven't seen your PMs.

    Okay, you haven't got an answer from me. For me it seems strange that you treat an absence of an answer from the original author as a permission to take my module, make some minor changes (which bring no improvements, no new features, don't fix bugs, but are nothing more than stylistic changes), removing original copyright/authorship/history header and call it highly derivative.

    You could take the original header:
    Code:
    ' ******************************************************************************
    ' *     Fire-Lines Ā© 2011                                                      *
    ' *     Модуль:                                                                *
    ' *         NameBasedObjectFactory                                             *
    ' *     Описание:                                                              *
    ' *         Этот модуль обеспечивает возможность создавать экземпляры классов  *
    ' *         по строковому имени соответствующего класса.                       *
    ' *     Автор:                                                                 *
    ' *         Владислав Петровский (firehacker)                                  *
    ' *     История изменений:                                                     *
    ' *         *   2011-05-21  firehacker  Файл создан.                           *
    ' *     Примечания:                                                            *
    ' *         Переименование модуля вызовет его неработоспосбность!              *
    ' *     Текущая версия: 1.0.0                                                  *
    ' *                                                                            *
    ' ******************************************************************************
    and improve it to:

    Code:
    ' ******************************************************************************
    ' *     Fire-Lines Ā© 2011                                                      *
    ' *     Module:                                                                *
    ' *         NameBasedObjectFactory                                             *
    ' *     Description:                                                           *
    ' *         This module provides an ability to instantiate objects             *
    ' *         by specifying class name as a string value.                        *
    ' *     Author:                                                                *
    ' *         Vladislav Petrovskiy (firehacker)                                  *
    ' *     Revision history:                                                      *
    ' *         *   2011-05-21  firehacker  File has been created.                 *
    ' *         *   2016-08-22  Elroy       Translated comments, stylistic changes.*
    ' *                                     IDE/EXE determinition logic changed to *
    ' *                                     tradition approach.                    *
    ' *     Remarks:                                                               *
    ' *         Renaming this modules makes it non-functional!                     *
    ' *         Original module and new versions can be found here:                *
    ' *                http://bbs.vbstreets.ru/viewtopic.php?f=28&t=43201          *
    ' *     Current version: 1.0.1                                                 *
    ' *                                                                            *
    ' ******************************************************************************
    And I would be absolutely happy with that. Even your decision to change the way debug mode (IDE presence) is detected, which makes the code little bit worse, would be okay in case o But you preferred to cut this header.

  30. #30

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Shaggy Hiker View Post
    Elroy said he'd PM firehacker. Firehacker comes back FOUR YEARS LATER. I agree that code should be attributed, though it does look like it was (I didn't look in any code files)...but four years??
    It's quite simple. I accidentally found that my module is being redistributed across the Internet, but someone changed authorship info in the head of the module as well as making some other questionable edits. I tried to track down where this modified version comes from, and it turned out that it comes from this particular topic.


    BTW, given the fact this forum's engine supports hierarchical post display (aka Hybrid Mode), should I respond to multiple people in a separate post, or it's preferable to place all answers (addressed to several different persons) into a single big post?

  31. #31
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by firehacker View Post
    So, hurry up! Registration on VBStreets is now opened!
    http://bbs.vbstreets.ru/ucp.php?mode=register
    Took me some time with the secret question in Russian (switching the UI in English makes registration form illegible which didn't help) but finally managed to guess the answer like a bot so you can shut this registration down already, thank you! :-)))

    cheers,
    </wqw>

  32. #32

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Bonnie West View Post
    firehacker, welcome to VBForums! I hope you'll post more often, we'd love to have more VB6 experts here.
    Quote Originally Posted by Schmidt View Post
    BTW, I agree fully with your kind welcome for "firehacker" - and (regarding "posting-presence" here) -
    would very much like, when you'd follow your own suggestion...
    Thank you for your wellcome.

    During last ten years I spend thousands of hours reverse-engineering classic VB. I have so much unique information about its internals revealed during reverse-engineering...

    I am in the middle of starting a new crowd-sourced project: it will be very similar to what ReactOS people are trying to do with Windows NT. It's not just a number of ephemeral wishes of reviving or recreating classic VB. There are some strong ideology, a methodology of work, specially designed toolkit and a toolchain behind my initiative.

    I know there are some initiatives to re-make classic VB: people are starting from scratch and making their own IDEs and compilers utilizing completely different architectures and principles. For me such initiatives look like someone's attempt to create completely new operating system: you'll have no software for your new OS, no drivers, no community. The only reason why ReactOS has a chance to have any decent success is that they claim that software and drivers made for Windows NT will work (or have to work) under ReactOS and vise versa. They claim some degree of binary compatibility.

    Likewise, I am targeted at recreating source files of original classic VB. Having such sources-pack will open a way of making improvements and releasing new versions of classic VB, and it will be higly compatible. All the existing VBP-projects will be compatible with hypothetical new IDE. All the existing binaries will be binary compatible with new recompiled msvbvm60.dll (with a number of improvements).

    When it comes to reverse-engineering and ensuring high degree of compatibility, one would ask you: how can you surely tell that you reverse-engineered some product correctly and compiling your code (results of reverse-engineering) won't break compatibility? How can you guarantee that your half of a million lines of source code will behave exactly the same way as original product is supposed to work? What if you misunderstood some algorithm and your implementation is seems to be similar, but is not strictly identical?

    The key aspect of my initiative is a special methodology that ensures that reverse-engineered source code is 100% equivalent to
    the original source code (which Microsoft will never give us). I am talking about functional equivalence, I don't mean having exactly same name for procedures and variables (however, presence of debug symbols for VB6.EXE and MSVBVM60.DLL allows to achieve partial variable/functions/methods/classes/types match too!).

    It isn't just a methodology: I have developed some unique tools that are used as part of the workflow by this methodology. The key utility is called ANTILEGO, but that requires an additional article on what the LEGO and LEGOfication process is (in a few words: it is a secret build stage that was used inside Microsoft when building all their binaries, it was a predecessor of PGO/LTCG in modern Microsoft's linkers, but it isn't the same as PGO/LTCG).

    You probably heard of TDD as a development methodology. TDD stands for Test-Driven Development. In my case an important part of the declared methodology can be described as TDRE (Test-Driven Reverse Engineering). And, as I said, it's not just an ideology of applying some tests after each commit: I have a number of special utilities which form a toolchain which is a workhorse of the whole TDRE approach. These includes custom disassembling and sophisticated machine code analysis engines which can tell you if the machine code compiled from your recreated source file is functionally or even byte-to-byte equivalent of the original binary, released by Microsoft.

    It is planned that the number of enthusiasts will work in a distributed manner (using Git), reversing the product part-by-part and proposing their results via pull-request mechanism. A special web site is going to be a coordination platform, showing the overall progress, a map of RCE coverage, having tons of documentation and serving as a task-tracker/bug-tracker as well as a hosting for Git repository.

    The repository itself exists for a long period of time, but it isn't hosted anywhere in public repository hosting currently:


    First commits were done 6 years ago (but the whole work started years before than, I just didn't use git):


    Statistics and progress are displayed by local utilities and scripts:

    (This is an old picture, BTW, but it shows how I am planning to display coverage map on the projects main page in the future)

    Lots of functions from MSVBVM60.DLL, VB6.EXE and VBA6.DLL are reversed back to C/C++ code. Here is example of VBACollection::Remove (which is implementation of Remove method of Collection class in VB/VBA):

    It is not just reversed, it is reversed the way that it's not simply functional equivalent of original code, but if you try to compile it with proper version of CL.EXE (Microsoft C/C++ compiler) with a proper set of command like switches, it gives a sequence of machine commands byte-to-byte identical to the sequence command that you can find in the binary released by Microsoft. And lots of functions and members are reverse-engineering this way, and my goal is to cover everything (but that is not a mandatory requirement if you're going to recompile runtime, for example).

    Thousands of "anonymous" functions from VBA6.DLL that are not covered by any debug symbols and whose names and activity were absolutely unknown, are discovered and reverse-engineered, including lots of functions responsible for source code parsing, compilation:

    Many of them are described this way (prototype, multiversionality info, short description, pseudocode):

    (I am showing simplest one, because otherwise it wouldn't fit one screen. Also, it is in Russian, as you can see, but about half of docs are written in English)

    Lots of internal structures are reversed and described:



    Tons of documents describing how various internal components of Visual Basic work and are organized:




    I am going to make all this information publicly available as part of VB-RCE project. However, I don't want to do that until it reaches some critical mass, which, I believe, it still hasn't reached. Not all tools are 100% polished. Not all parts of my TDRE workflow is automated or works as I wish.

    However, over the years of reverse-engineering I made a number of interesting discoveries.
    • Did you know about undocumented keys in VBP-file: C2Switches and LinkSwitches under [VBCompiler] section? You probably did, because I was the first who described it here in November 2011 and now you can google many mentions of VBCompiler section, but back in the days this was unique information.
    • Did you know that one bit separates you from this kind of syntax?

    • Did you know that there is hidden analogue of CallByName but for plain functions/API instead of object methods in VB? As well as a hidden basis for expression evaluation engine?
    • Did you know that that there is undocumented mechanism allowing connecting from external software to VB IDE or to compiled VB project and tracing events (including step-by-step tracing, which, however, works only in IDE mode)?
    • Do you know that a number of attempts to rename any variable (or any entity) is limited to 32K times due to the nature of how code entities are represented internally?


    I have started a series of articles describing my explorations and reverse-engineering results. Unfortunately for English-speaking people, these articles are in Russian. It's called VB Internals and is published on VBStreets.

    Currently there are only two ready articles:


    The first one covers very important topic that Visual Basic is actually a hybrid of two products (Ruby and EB) glued together. It is very important to understand what Ruby and EB are, how they were born and where the boundaries between them lay prior to diving into reverse-engineering or any explorations. It should be considered an introduction article for the whole series.

    The second one tries to evaluate number of C/C++/assembler source files (sources of VB6 itself) and the overall number of lines in these files basing on the information that can be obtained by extraction raw data from DBG/PDB files and consequent sophisticated postprocessing.

    The third is upcoming: it will bring more details on how sources are organized and how various components of IDE/runtime is distributed across source files.

    Here is the preliminary list of topics that I plan to highlight in the series. (Google translate)
    Last edited by firehacker; Feb 7th, 2021 at 12:32 AM.

  33. #33
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,116

    Re: Instantiate internal class object with name in string



    A lot to read there, but very well worth it.

  34. #34

  35. #35

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Instantiate internal class object with name in string

    I just wanted a copy of those images in a post of mine.

    But WOW, hey Bonnie. I hope you've been well. It's AMAZING to see you here. You were always one of my favorite posters. Not sure you heard, but it seems that LaVolpe is moving on from VB6. He gave us a smiling *wave* a few days back. Maybe we'll get you back. *smiles and shrugs*




    Quote Originally Posted by Bonnie West View Post
    I still have them.








    firehacker, welcome to VBForums! I hope you'll post more often, we'd love to have more VB6 experts here.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  36. #36
    Hyperactive Member
    Join Date
    Jun 2016
    Location
    EspaƱa
    Posts
    506

    Re: Instantiate internal class object with name in string

    wauuuuu how much work.
    sure many people join to help.

    I really want to see all those tools, but what if they fall into the wrong hands.

    a greeting
    PS: sorry I use translator

  37. #37
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Instantiate internal class object with name in string

    Quote Originally Posted by Elroy View Post
    I hope you've been well.
    Don't worry, I'm doing OK.

    Quote Originally Posted by Elroy View Post
    Not sure you heard, but it seems that LaVolpe is moving on from VB6. He gave us a smiling *wave* a few days back.
    I know, that's why I was hoping the remaining VB6 experts around the world (like firehacker) will join us here so that we can finally get the proper VB6 successor started (and, judging by this thread and the recent classic VB revival threads, it does seem like it's gonna happen soon ).

    Quote Originally Posted by Elroy View Post
    Maybe we'll get you back. *smiles and shrugs*
    Quote Originally Posted by Schmidt View Post
    ... and (regarding "posting-presence" here) -
    would very much like, when you'd follow your own suggestion...
    Yeah, I would love to return to my coding hobby, but unfortunately, there are many other things I've got to take care of first. I do try to visit the forum from time to time though.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  38. #38
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: Instantiate internal class object with name in string

    oooo Bonnie is back.....
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  39. #39
    PowerPoster
    Join Date
    Jan 2020
    Posts
    3,746

    Re: Instantiate internal class object with name in string

    for best ,you can use english and Russian ,two language

  40. #40
    PowerPoster
    Join Date
    Jan 2020
    Posts
    3,746

    Re: Instantiate internal class object with name in string

    VB6 is a commercial product, VB.NET was subsequently developed, and VB6 was abandoned. Even the earliest developers are required to keep secrets, so no one knows how VB1.0 to VB6 were invented.
    As a Microsoft product, confidentiality is normal.
    Mainly the smallest VB6 IDE, only 10-30M, including some basic controls. Such a small volume has achieved similar functions as DELPHI7.0. Technically speaking, after more than 30 years, it is still very advanced.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width