Solved How to re-declare a public variable? (1 Viewer)

KitaYama

Active member
Local time
Tomorrow, 01:51
Joined
Jan 6, 2022
Messages
454
I have the following public variable declared in a module:
Code:
Option Explicit
Public OrdersRibbon As IRibbonUI

Then I have a function that runs from AutoExec and creates a xml statement and sets it as the default ribbon for the database:
Code:
Public Function LoadRibbons()
    .....
    ' create the xml
    .....
    Application.LoadCustomUI "OrdersRibbon", strXML
    .....
End Function

Then every now and then I use the following to re-assign the ribbon, hide/show/enable/disable buttons & controls:
Code:
OrderRibbon.Invalidate
OrderRibbon.InvalidateControl (MyControlID)

This is working, not even a single problem.

But if an unhandled error occurs, the public variable is destroyed (if it's the correct terminology) and the next time the code tries to invalidate the ribbon, it returns the following error:
Object variable or With block variable not set

Now my question:
  1. Is there any other way than a public variable to use in above case? I mostly use tempVars. But I've never set an object to a tempVar nd I'm not sure how to use it in above case.
  2. Is there any way to re assign a public variable once it's been destroyed? (at present we have to close and re-open the database)

Any kind of insight is much appreciated.
 
Last edited:
Solution
You can also save the memory address of the ribbon, and if it breaks, re-reference it from that address, because obviously the ribbon is not destroyed, just the variable that points to it. Consider...
Code:
Private ui_ As IRibbonUI

Function RibbonLoad(ui As IRibbonUI)
'   callback function from ribbon when it loads
    Set ui_ = ui               ' save to local variable
    TempVars!ui = ObjPtr(ui)   ' save address to temp var as backup
End Function

Property Get MainRibbon() As IRibbonUI
'   global property that automatically rebuilds
'   the ribbon if the ui_ variable is Nothing
    If ui_ Is Nothing And Not IsNull(TempVars!ui) Then Set ui_ = GetObjectFromPointer(TempVars!ui)
    Set MainRibbon = ui_
End Property

And the...

KitaYama

Active member
Local time
Tomorrow, 01:51
Joined
Jan 6, 2022
Messages
454
Did you accidentally upload the wrong file? Your sample file does not include any code to reset the ribbon variable.
I just wanted to show how the error occurs and what my main problem is. @Makks suggestion is not included in my sample.
As I explained above, if I add his code I receive a compile error on ZEROPOINTER.

I'll check @arnelgp 's file to see how he's done it.

Thank you for your time.
 

KitaYama

Active member
Local time
Tomorrow, 01:51
Joined
Jan 6, 2022
Messages
454
I just tested @markks solution.
It seems that it works.
I'll implement it on our main database and will repor tback.

I really appreciate your help.
thank you
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Tomorrow, 00:51
Joined
May 7, 2009
Messages
16,504
As for your example, you are correct. ui_ is not Nothing after the error because you handled that error using "On Error Resume Next", so the variables are not reset.
i change the code to:

On Error Goto ErrHandler

still ui_ is Intact (not set to Nothing)

Code:
Private Sub cmdClickMe_Click()
Dim i As Integer

On Error GoTo errHandler

ResumeHere:
    [TempVars]![OpenFormCount] = 1
    MainRibbon.Invalidate
    
    Exit Sub
    
errHandler:
    Resume ResumeHere

End Sub

and the pointer of ui_ is destroyed, so you need to "force" assign it:

Code:
Property Get MainRibbon() As IRibbonUI
'   global property that automatically rebuilds
'   the ribbon if the ui_ variable is Nothing
    
    
    'If ui_ Is Nothing And Not IsNull(TempVars!ui) Then Set ui_ = GetObjectFromPointer(TempVars!ui)
    
    'arnelgp
    'actually ui_ is not set to Nothing when an error occurs
    'force to use saved variable
    Set ui_ = GetObjectFromPointer(TempVars!ui)
    Set MainRibbon = ui_
End Property
 

KitaYama

Active member
Local time
Tomorrow, 01:51
Joined
Jan 6, 2022
Messages
454
@MarkK @sonic8 @arnelgp
I was able to use @MarkK's solution to invalidate the ribbon after an unhandled error.
A sample file that shows the situation is attached. simply click the button.

You'll notice even after the error and when the public variable is out of scope (destroyed) I hide/show the button on the ribbon.

I really appreciate you and all others who participated and shared their experience. Also special thanks to @The_Doc_Man for his perfect explanation on errors.

Million thanks to all of you
 

Attachments

  • testRibbon.accdb
    780 KB · Views: 26
Last edited:

theDBguy

I’m here to help
Staff member
Local time
Today, 09:51
Joined
Oct 29, 2018
Messages
19,019
@MarkK @sonic8 @arnelgp
I was able to use @MarkK's solution to invalidate the ribbon after an unhandled error.
A sample file that shows the situation is attached. simply click the button.

You'll notice even after the error and when the public variable is out of scope (destroyed) I hide/show the button on the ribbon.

I really appreciate you and all others who participated and shared their experience. Also special thanks to @The_Doc_Man for his perfect explanation on errors.
I know a simple thank you is not enough, but it's all I can offer.
Million thanks to all of you
Hi. Glad to hear you got it sorted out. Sorry I couldn't find my old database, but that's exactly what I remembered doing (copy the memory pointer and restore it after the error). Good luck with your project.
 

KitaYama

Active member
Local time
Tomorrow, 01:51
Joined
Jan 6, 2022
Messages
454
I noticed @MarkK's code saves the memory address of the ribbon and when the public variable fails, it uses the address and use it.
So after an error occures I have to use the address to invalidate the ribbon.
Well, If I have the memory address, then I can assign it to my public variable again.

I deleted Property Get and used a procedure (resetVariable) :

Code:
    On Error GoTo ErrorTrap
     
    OrdersRibbon.Invalidate
    Exit Sub
   
ErrorTrap:
    Select Case Err.Number
        Case 91
            resetVariable
            OrdersRibbon.Invalidate
            On Error GoTo 0
            Resume Next
    End Select

And this is resetVariable

Code:
Public Sub resetVariable()
    Set ui_ = GetObjectFromPointer(TempVars!ui)
    Set OrdersRibbon = ui_
End Function

It's a huge step because after a reset, I have access not only the ribbon variable, but any other public variable.
 

Attachments

  • testRibbon_3.accdb
    780 KB · Views: 14

KitaYama

Active member
Local time
Tomorrow, 01:51
Joined
Jan 6, 2022
Messages
454
Is there any other way than a public variable to use in above case? I mostly use tempVars. But I've never set an object to a tempVar nd I'm not sure how to use it in above case.
It may be of interest for @The_Doc_Man & @theDBguy

In response to above question, I was told tempVars can not be used. Actually Microsoft documents says that only strings and numbers can be saved in a tempVar.

I played a little with @MarkK 's code. Well, if he can save the memory address of the ribbon to tempVars, I don't need a public variable at all.
I mean if I have access to the memory address, why should I use a public variable? I can use the address any time I need to invalidate the ribbon.
So I deleted the public variable and did as following :

1- When constructing my ribbon, I call a procedure and save the address:
Code:
Public Sub OnRibbonLoad(ribbon As IRibbonUI)
     RibbonLoad ribbon
End Sub

Code:
Sub RibbonLoad(ui As IRibbonUI)
    Set ui_ = ui               ' save to local variable
    TempVars!ui = ObjPtr(ui)   ' save address to temp var as backup
End Sub

Now anytime I want to invalidate the ribbon, instead of MyRibbon.Invalidate I use the following:
Code:
MainRibbon.Invalidate

MainRibbon is exactly what @MarkK gave me:
Code:
Property Get MainRibbon() As IRibbonUI
    Set ui_ = GetObjectFromPointer(TempVars!ui)
    Set MainRibbon = ui_
End Property

In this way I don't have any public variable at all, no errors, not even after an unhandled error.
A sample file is attached.
@MarkK, I really appreciate your talent. I had imagined I may find a solution when I first posted my question, but never expected a solution as perfect as this.
Million thanks.
 

Attachments

  • testRibbon_4.accdb
    780 KB · Views: 20

arnelgp

..forever waiting... waiting for jellybean!
Local time
Tomorrow, 00:51
Joined
May 7, 2009
Messages
16,504
this is the source:
 

Users who are viewing this thread

Top Bottom