cristianbuse / VBA-UserForm-MouseScroll

Use the Mouse Scroll Wheel to scroll VBA UserForms and Controls
MIT License
74 stars 15 forks source link

Unexpected error 35010 #27

Closed joeyda closed 1 year ago

joeyda commented 1 year ago

I'm trying to use the mousescroll with Autodesk Inventor VBA. Everything works well at first but I get the unexpected error popping up randomly. It seems to fail at SetWindowsHookEx.

Only modification is I had to change all references of "Application" to "ThisApplication" to get it to work with Inventor.

VBA info shows it is version 7.1.1096

cristianbuse commented 1 year ago

Thanks @joeyda ,

I would like to retrieve the Application object via late binding so that it works regardless of host application.

Could you please test if ActiveWindow.Parent.Parent.Name returns the name of the application? I do not have access to Inventor. Thanks!

joeyda commented 1 year ago

I tried that in a userform, it seems like Inventor doesn't implement ActiveWindow, I always get Object variable or with block variable not set

image

joeyda commented 1 year ago

I tested in excel vba and it returned "Microsoft Excel"

cristianbuse commented 1 year ago

Thank you @joeyda !

It seems I need to figure out another way.

cristianbuse commented 1 year ago

Hi again @joeyda ,

It just occurred to me that maybe you are getting the error because the Parent property is not set. Could you please test if ActiveWindow.Application.Name works. Thanks!

I tried a lot of things but I cannot find a common object to use among all apps. For example Global implementing [_Global] which is missing from Outlook but available in Excel, Word and PowerPoint. I also don't have Inventor to test.

The only reliable way would be to remove the Option Explicit directive which would then remove any compilation error and then one of Application or ThisApplication would turn into an Empty Variant and would be easy to test against using IsEmpty. However, this could introduce bugs in future versions so I would rather avoid it if possible.

joeyda commented 1 year ago

ActiveWindow is also not set to anything. If I declare a variable and set it = ActiveWindow, it shows up as Nothing.

Closest thing to that I can see Inventor implementing is ThisApplication.ActiveViewFrame.Application.Caption

image

Here is Inventor's Application object ( I believe ActiveWindow is a subobject of Application?)

image

joeyda commented 1 year ago

I split up the enablemousescroll function to help debug and it seems to be more stable, I haven't gotten the unexpected error in a while

Public Function EnableMouseScroll(ByVal uForm As MSForms.UserForm , Optional ByVal passScrollToParentAtMargins As Boolean = True ) As Boolean Dim testBool As Boolean Debug.Print ("One") testBool = One(uForm)

If testBool = False Then Exit Function

Debug.Print ("Two")
Call Two

Debug.Print ("Three")
testBool = Three
If testBool = False Then Exit Function
'

Debug.Print ("Adding userform")
AddForm uForm, passScrollToParentAtMargins
Debug.Print ("ResetLast")
ResetLast

EnableMouseScroll = True

End Function

Private Function One(uForm As MSForms.UserForm) As Boolean Debug.Print ("running function one") If uForm Is Nothing Then One = False Else One = True End If End Function

Private Sub Two() Debug.Print ("testing addressof (function two)") Dim test As LongPtr test = getAddressOfCallback(AddressOf MouseProc)

    Debug.Print ("AddressOf MouseProc: " & test)
    Debug.Print ("CurrentThreadId: " & GetCurrentThreadId())

End Sub

Private Function Three() As Boolean Debug.Print ("running hookmouse function") If Not HookMouse Then Three = False Else Three = True End If End Function

cristianbuse commented 1 year ago

Hi,

I don't think that the split itself is needed. VBE debugger's edit-and-continue feature can corrupt the internal storage streams and so usually the fix is to export the module, remove it and then import it back. This forces the code to recompile correctly.

Forgot to reply to your previous comment. Thanks for posting the Inventor Application object's methods. It seems that removing Option Explicit would be the only way to bypass the compilation error but I think I won't do that as it's not too hard to do a Find & Replace from Application to ThisApplication.

kaz4ikeda commented 6 months ago

Hi, @cristianbuse

Sorry for late question after completion of this thread, but I'm very eager to know the mechanism that you mentioned about Option Explicit.

Why does the compilation error cease when Option Explicit is commented out? Is it related to the ordinary explanation of Option Explicit that it detects missing variable declaration, or is it related to something more profound function of Option Explicit under the hood? I can't understand the former case because 35010 error is not the "Variable not defined" error. If the latter is the case, please explain what is your intention about the error stopping mechanism, especially the relation to AddressOf function.

cristianbuse commented 6 months ago

Hi @kaz4ikeda ,

Why does the compilation error cease when Option Explicit is commented out? Is it related to the ordinary explanation of Option Explicit that it detects missing variable declaration

Yes, the first ordinary explanation. Because VBA will stop checking if Application or ThisApplication actually exist (at compile-time), we can write code like this:

Function GetCorrectApplication() As Application
    On Error Resume Next
    Set GetCorrectApplication = Application
    If Err.Number <> 0 Then Set GetCorrectApplication = ThisApplication
    On Error GoTo 0
End Function

In the above example, if Option Explicit exists then we get a compile time error (Variable not defined) either on Application or ThisApplication depending what the host app is.

However, if Option Explicit is removed, then the code compiles and calling GetCorrectApplication returns the correct app in both applications because any error raised will be a runtime error and will be supressed by error handling.

cristianbuse commented 6 months ago

Forgot to mention that this is not a problem anymore as the newer version of this repo doesn't use Application

kaz4ikeda commented 6 months ago

Thank you, @cristianbuse , I understand the role of Option Explicit here.

What do you think why the error was not "Variable not defined" but "Unexpected error 35010" in Inventor? I'm using the MouseScroll code with my SOLIDWORKS macro in my office, and sometimes (not so often) 35010 error appears. (Maybe my macro is responsible to that error as in the case of Inventor.)

cristianbuse commented 6 months ago

@kaz4ikeda

I have no idea why the error number is different. I guess some Applcations deviate from the standard error code.

Please note that the latest version of this repository has removed the need for using the Application object. Around September, I introduced Modeless form support and Debugging support. Option Explicit should always be on now

kaz4ikeda commented 6 months ago

Thank you for reply, @cristianbuse . I'm using the latest version of the MouseScroll software. The 35010 error is not serious for me, so I will just take a look for a while. Thank you again.

cristianbuse commented 6 months ago

@kaz4ikeda

Can you please open a separate issue and provide me with more details like when the error occurs and any other info you consider relevant? I will look into it

joeyda commented 6 months ago

Two things helped me with that error: I turned off compile on demand option in the VBA editor, this reduced the frequency of the error significantly. Then I added a call to disablemousescroll every time the user form is hidden or unloaded and my forms have been very stable. Our form is never open for more than a minute at a time then we close it out.

Some things I have noticed about this specific error:

kaz4ikeda commented 6 months ago

Thank you @joeyda for informing your Inventor case.

The symptom seems to be slightly different from my SOLIDWORKS case. SW never crashes relating to the error 35010.

I opened a separate issue as a SW case.

cristianbuse commented 6 months ago

Thanks @joeyda ,

Could you please add one line to the GetCallbackPtr method and then test without using your workarounds? Simply change this:

Private Function GetCallbackPtr() As LongPtr
    Dim ptr As LongPtr: ptr = VBA.Int(AddressOf MouseProc)

to this:

Private Function GetCallbackPtr() As LongPtr
    Sin 1 'Dummy call to force compiler to 'see' the correct address
    Dim ptr As LongPtr: ptr = VBA.Int(AddressOf MouseProc)
joeyda commented 6 months ago

I will test that and see

also, my VBA version if it helps image

joeyda commented 5 months ago

I used mouse scroll last week with that line added and it was pretty much perfect. One crash after launching my mousescroll form but that was after I had a crash elsewhere so probably unrelated.

cristianbuse commented 5 months ago

Thank you @joeyda for letting me know!

I will push a commit to make a dummy call.