Results 1 to 13 of 13

Thread: How to call a Procedure by Name.

  1. #1

    Thread Starter
    PowerPoster cafeenman's Avatar
    Join Date
    Mar 2002
    Location
    Florida
    Posts
    2,819

    How to call a Procedure by Name.

    I'm sure there's a way to do it and I even think I've done it in the past but I can't find it and an internet search gave me AddressOf and CallByName.

    I use callbyname to recolor my forms at run-time per user preferences.

    So this is what I'm trying to do.

    I'm writing a thing that chooses a random thing to do. Let's say there's 20 choices of random things.

    So I have this:

    Sub Random00
    End Sub

    Sub Random01
    End Sub

    and so on.

    To call it I do this:

    Code:
    Sub DoARandomThing
    Dim nRnd as long
    
    nRnd=int(rnd * 19)
    
    Select Case nRnd
    
        Case 0
    
            Random00
    
        Case 1
    
         Random01
    
    etc.
    What I'd like to do is this:

    Code:
    Sub DoARandomThing
    Dim nRnd as long
    
    nRnd = int(rnd * 19)
    
    CallSubroutineByName "Random" & format(nrnd, "00")
    Last edited by cafeenman; Apr 9th, 2024 at 01:06 AM.

  2. #2
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,644

    Post Re: How to call a Procedure by Name.

    Only public methods of classes can be called by their name. All other names are lost after compilation (they become memory addresses).

  3. #3

    Thread Starter
    PowerPoster cafeenman's Avatar
    Join Date
    Mar 2002
    Location
    Florida
    Posts
    2,819

    Re: How to call a Procedure by Name.

    OK, so I have a create a cRandomThings Class?

    That will make this sticky because at least some of the random things are with controls so I'd have to pass those subs the controls.

    I'm not sure it's worth it to just get out of doing a long select case thing.

  4. #4

    Thread Starter
    PowerPoster cafeenman's Avatar
    Join Date
    Mar 2002
    Location
    Florida
    Posts
    2,819

    Re: How to call a Procedure by Name.

    Does anyone know how to make the actual call?

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

    Re: How to call a Procedure by Name.

    Quote Originally Posted by VanGoghGaming View Post
    Only public methods of classes can be called by their name. All other names are lost after compilation (they become memory addresses).
    This sounds logical but VB6 leaves some internal VBProject structures in final binary which allow traversing modules/procedures and finding offset/address is current process. Another thing is that friend/private methods of classes do end up in runtime VTable albeit not used by codegen to make actual calls from callsites but the addresses in current process are present.

  6. #6
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: How to call a Procedure by Name.

    Quote Originally Posted by cafeenman View Post
    Does anyone know how to make the actual call?
    If your 20 procedures are defined in the Form itself, then just make them Public there.

    Then calling (also from within the Form):

    CallByName Me, "Random" & Format(Int(Rnd * 20), "00"), vbMethod

    ...should do it (also note the 20 instead of your 19 above).

    Olaf

  7. #7

    Thread Starter
    PowerPoster cafeenman's Avatar
    Join Date
    Mar 2002
    Location
    Florida
    Posts
    2,819

    Re: How to call a Procedure by Name.

    Thanks. I do know how rnd works. (add 1 if you want 1-based). Otherwise zero-based.

    so all my six-sided die rolls are actually 0 to 5 just so I'm not swapping back and forth all the time between number bases. Just make it all base 0.

    E.g Int(Rnd * 6) returns 0 to 5.

    Thanks again.

    Edit: OK, I see why you specified the 20. The 19 in my OP which was wrong.
    Last edited by cafeenman; Apr 9th, 2024 at 04:12 AM.

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

    Re: How to call a Procedure by Name.

    Quote Originally Posted by cafeenman View Post
    I do know how rnd works. (add 1 if you want 1-based).
    Otherwise zero-based.
    No - just play that through for a "zerobased" Coin-Toss... (a 50:50 distribution between result 0 or 1).

    For that case - your proposed Int(Rnd * 1) will produce a 100:0 distribution
    (always producing a 0 - and never the 1)...

    For a zerobased coin-toss, the right Formula is Int(Rnd * 2)

    Olaf

  9. #9
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,192

    Re: How to call a Procedure by Name.

    Also note that Int in Int(Rnd * 20) is important. Using CLng or leaving it without explicit conversion (i.e. simple Format(Rnd * 20, "00")) will result in bias in final distribution with both end values having half the probability of the rest of outcomes.

    cheers,
    </wqw>

  10. #10

    Thread Starter
    PowerPoster cafeenman's Avatar
    Join Date
    Mar 2002
    Location
    Florida
    Posts
    2,819

    Re: How to call a Procedure by Name.

    Quote Originally Posted by Schmidt View Post
    No - just play that through for a "zerobased" Coin-Toss... (a 50:50 distribution between result 0 or 1).

    For that case - your proposed Int(Rnd * 1) will produce a 100:0 distribution
    (always producing a 0 - and never the 1)...

    For a zerobased coin-toss, the right Formula is Int(Rnd * 2)

    Olaf
    PS: The code below is kind of cool. You just need a VScroll1 and HScroll1 with both of them having the same min and max. That part is important.

    Mine are set to min=0 and max=25
    I've got that thing all over this code.

    Code:
    Private Sub Anger()
    Dim n As Long
    Dim nrnd As Long
    Dim nMid As Long
    Dim nMax As Long
    Dim nOffset As Long
    
    ' AddToText vbCrLf & vbTab & "You have Angered the Ghost!!" & vbCrLf
    
    'Sleep 100
    
    With HScroll1
    
      nMid = .Max / 2
      nMax = .Max / 3
    
      For n = 0 To 49
    
        nrnd = Int(Rnd * nMax)
    
        .Value = nMid + nrnd
    
        .Value = nMid - nrnd
    
      Next n
    
    End With
    
    With HScroll1
    
      nrnd = Int(Rnd * 2)
    
      nOffset = .Max / 3
    
      If nrnd = 0 Then
    
        .Value = nMid + nOffset
    
      Else
    
        .Value = nMid - nOffset
    
      End If
      
    End With
    
    End Sub
    
    Private Sub HScroll1_Change()
    
    With HScroll1
    
      If Not .Enabled Then Exit Sub
    
      VScroll1.Value = .Max - .Value
    
    End With
    
    'lblCount.Caption = Format(HScroll1.Value, PLAY_FORMAT)
    
    'DoARandomThing
    
    End Sub
    Private Sub HScroll1_Scroll()
    
    HScroll1_Change
    
    End Sub
    Private Sub VScroll1_Change()
    
    With VScroll1
    
      HScroll1.Value = .Max - .Value
    
    End With
    
    End Sub
    Private Sub VScroll1_Scroll()
    
    VScroll1_Change
    
    End Sub
    Last edited by cafeenman; Apr 9th, 2024 at 08:56 AM.

  11. #11
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: How to call a Procedure by Name.

    Quote Originally Posted by cafeenman View Post
    PS: The code below is kind of cool.
    You just need a VScroll1 and HScroll1 with both of them having the same min and max. That part is important.
    Not sure, what you want to express with the "Anger-part" of your snippet -
    but it could have been written more efficiently this way:

    Code:
    Option Explicit
    
    Private WithEvents H As VB.HScrollBar, WithEvents V As VB.VScrollBar
    
    Private Sub Form_Load()
      Set V = Controls.Add("VB.VScrollBar", "V"): V.Visible = True
      Set H = Controls.Add("VB.HScrollBar", "H"): H.Visible = True
    
      H = H.Max / 2 + H.Max / 3 * IIf(Int(Rnd * 2), 1, -1) ' Anger
    End Sub
    
    Private Sub H_Change()
      V = H.Max - H
    End Sub
    Private Sub H_Scroll()
      H_Change
    End Sub
    
    Private Sub V_Change()
      H = V.Max - V
    End Sub
    Private Sub V_Scroll()
      V_Change
    End Sub
    Olaf

  12. #12

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

    Re: How to call a Procedure by Name.

    Quote Originally Posted by The trick View Post
    Only Friend methods, private ones is called using VTable.
    Weird! For private methods it does codegen VTable calls.

    This class:

    Code:
    Option Explicit
    
    Public Function Init() As Long
        Test1
        Test2
        Test3
    End Function
    
    Public Function Test1() As Long
        Test1 = 42
    End Function
    
    Private Function Test2() As Long
        Test2 = 43
    End Function
    
    Friend Function Test3() As Long
        Test3 = Test1 + Test2
    End Function
    ... decompiles to this:

    Code:
    Public Function Init() As Long
    00401DA9 8D 45 E4             lea         eax,[unnamed_var1]  
    00401DAC 50                   push        eax  
    00401DAD 8B 45 08             mov         eax,dword ptr [Me]  
    00401DB0 8B 00                mov         eax,dword ptr [eax]  
    00401DB2 FF 75 08             push        dword ptr [Me]  
    00401DB5 FF 50 20             call        dword ptr [eax+20h]  
    00401DB8 89 45 E0             mov         dword ptr [unnamed_var1],eax  
    00401DBB 83 7D E0 00          cmp         dword ptr [unnamed_var1],0  
    00401DBF 7D 17                jge         Class1::Init+6Fh (401DD8h)  
    00401DC1 6A 20                push        20h  
    00401DC3 68 10 1A 40 00       push        offset ___vba@08C12B20 (401A10h)  
    00401DC8 FF 75 08             push        dword ptr [Me]  
    00401DCB FF 75 E0             push        dword ptr [unnamed_var1]  
    00401DCE E8 AF F3 FF FF       call        ___vbaHresultCheckObj (401182h)  
    00401DD3 89 45 D4             mov         dword ptr [ebp-2Ch],eax  
    00401DD6 EB 04                jmp         Class1::Init+73h (401DDCh)  
    00401DD8 83 65 D4 00          and         dword ptr [ebp-2Ch],0  
        Test1()
    00401DDC 8D 45 E4             lea         eax,[unnamed_var1]  
    00401DDF 50                   push        eax  
    00401DE0 8B 45 08             mov         eax,dword ptr [Me]  
    00401DE3 8B 00                mov         eax,dword ptr [eax]  
    00401DE5 FF 75 08             push        dword ptr [Me]  
    00401DE8 FF 50 24             call        dword ptr [eax+24h]  
        Test2()
    00401DEB 8D 45 E4             lea         eax,[unnamed_var1]  
    00401DEE 50                   push        eax  
    00401DEF FF 75 08             push        dword ptr [Me]  
    00401DF2 E8 B5 00 00 00       call        Class1::Test3 (401EACh)  
        Test3()
    00401DF7 8B 45 08             mov         eax,dword ptr [Me]  
    00401DFA 8B 00                mov         eax,dword ptr [eax]  
    00401DFC FF 75 08             push        dword ptr [Me]  
    00401DFF FF 50 08             call        dword ptr [eax+8]  
    00401E02 8B 45 0C             mov         eax,dword ptr [Init]  
    00401E05 8B 4D E8             mov         ecx,dword ptr [Init]  
    00401E08 89 08                mov         dword ptr [eax],ecx  
    00401E0A 8B 45 FC             mov         eax,dword ptr [ebp-4]  
    00401E0D 8B 4D EC             mov         ecx,dword ptr [ebp-14h]  
    00401E10 64 89 0D 00 00 00 00 mov         dword ptr fs:[0],ecx  
    00401E17 5F                   pop         edi  
    00401E18 5E                   pop         esi  
    00401E19 5B                   pop         ebx  
    00401E1A C9                   leave  
    00401E1B C2 08 00             ret         8  
    End Function
    So private Test2 method indeed uses call dword ptr [eax+24h] indirect call through VTable but lacks HResult check.

    Friend Test3 method uses call Class1::Test3 (401EACh) direct call and again no HResult check which seems to be fastest approach.

    Nothing comes to mind what could possible require VTable indirect calls for private methods.

    cheers,
    </wqw>

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