UtterAccess.com
X   Site Message
(Message will auto close in 2 seconds)

Welcome to UtterAccess! Please ( Login   or   Register )

Custom Search
 
   Reply to this topicStart new topic
> Mousepointer Code For 64, Access 2016    
 
   
RLG
post Feb 13 2020, 07:14 PM
Post#1



Posts: 56
Joined: 9-March 10



I have been trying in vain to convert the venerable MousePointer module to work in 2016 running x64.

I have tried to follow the instructions for converting the Declarations using PtrSafe and LongPtr etc, but still can't get it to work. The problem is that my application, now under construction for 11 years and counting, uses this Function in hundreds of places!

Please has anyone got any revised code, so that the original calls still work?

Richard
Go to the top of the page
 
GroverParkGeorge
post Feb 13 2020, 07:21 PM
Post#2


UA Admin
Posts: 36,753
Joined: 20-June 02
From: Newcastle, WA


This might be easier if we could actually see your code. Obviously, not everyone has your "... venerable MousePointer module..." handy.

--------------------
My Real Name Is George. Grover Park Consulting is where I did business for 20 years.
How to Ask a Good Question
Beginning SQL Server
Go to the top of the page
 
RLG
post Feb 13 2020, 07:27 PM
Post#3



Posts: 56
Joined: 9-March 10



Thanks. Here is my code, with attempted alterations:

Option Compare Database
Option Explicit

Declare PtrSafe Function SetClassLong Lib "user32" Alias "SetClassLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
'=======================================================================
' Globals for cursor handling
Global Const GCL_HCURSOR = (-12)
Global hSwapCursor As Long
Global hAniCursor As Long
'=======================================================================
Public Const IDC_ARROW = 32512&
Public Const IDC_IBEAM = 32513&
Public Const IDC_WAIT = 32514&
Public Const IDC_CROSS = 32515&
Public Const IDC_UPARROW = 32516&
Public Const IDC_ICON = 32641&
Public Const IDC_SIZENWSE = 32642&
Public Const IDC_SIZENESW = 32643&
Public Const IDC_SIZEWE = 32644&
Public Const IDC_SIZENS = 32645&
Public Const IDC_SIZEALL = 32646&
Public Const IDC_NO = 32648&
Public Const IDC_HAND = 32649&
Public Const IDC_APPSTARTING = 32650&
Declare PtrSafe Function LoadCursorBynum Lib "user32" Alias "LoadCursorA" _
(ByVal hInstance As Long, ByVal lpCursorName As Long) As Long
Declare PtrSafe Function LoadCursorFromFile Lib "user32" Alias "LoadCursorFromFileA" (ByVal lpFileName As String) As LongPtr
Declare PtrSafe Function SetCursor Lib "user32" (ByVal hCursor As LongPtr) As LongPtr
'
Public Function Arrow_Pointer()
Screen.MousePointer = 1
End Function
Function ChangeCursor(strPathToCursor As String)
On Error GoTo Error_On_ChangeCursor
' Example :
' ChangeCursor ("C:\Program Files\Microsoft Office\Office\Hand.cur")
If Dir(strPathToCursor) <> "" Then
Dim lngRet As Long
lngRet = LoadCursorFromFile(strPathToCursor)
lngRet = SetCursor(lngRet)
End If

Exit_ChangeCursor:
Exit Function

Error_On_ChangeCursor:

Resume Exit_ChangeCursor

End Function
Public Function Default_Pointer()
Screen.MousePointer = 0
End Function
Public Function IBeam_Pointer()
Screen.MousePointer = 3
End Function
Function MouseCursor(CursorType As Long)
' Example: =MouseCursor(32512) ' using Public Constants from above
Dim lngRet As Long
lngRet = LoadCursorBynum(0&, CursorType)
lngRet = SetCursor(lngRet)
End Function
Public Function Replace_Cursor(PathToFile As String)
' Return handle from animated cursor

' Original - hAniCursor = LoadCursorFromFile("C:\WINDOWS\CURSORS\GLOBE.ANI")

hAniCursor = LoadCursorFromFile(PathToFile)
' Swap current mouse pointer with new animated cursor :
hSwapCursor = SetClassLong(Screen.ActiveForm.hwnd, GCL_HCURSOR, hAniCursor)


End Function
Public Function Restore_Cursor()
' Remove animated cursorand replace with saved index :

hSwapCursor = SetClassLong(Screen.ActiveForm.hwnd, GCL_HCURSOR, hSwapCursor)

End Function
Go to the top of the page
 
RLG
post Feb 13 2020, 07:38 PM
Post#4



Posts: 56
Joined: 9-March 10



I should have said that I am getting a Type Mismatch error at the following line:

Function MouseCursor(CursorType As Long)
' Example: =MouseCursor(32512) ' using Public Constants from above
Dim lngRet As Long
lngRet = LoadCursorBynum(0&, CursorType) ' <------ here
lngRet = SetCursor(lngRet)
End Function

Thanks

Richard
Go to the top of the page
 
BentBrain
post Feb 13 2020, 08:17 PM
Post#5



Posts: 520
Joined: 10-February 03
From: Thailand


Hi RLG
with x64 you need to change long to longPtr.


Try this in your function

#If Win64 Then
Function MouseCursor(CursorType As LongPtr)
Dim Lng Ret as LongPtr
lngRet = LoadCursorBynum(0&, CursorType) ' <------ here
lngRet = SetCursor(lngRet)
End Function
#Else
Function MouseCursor(CursorType As Long)
Dim lngRet As Long
lngRet = LoadCursorBynum(0&, CursorType) ' <------ here
lngRet = SetCursor(lngRet)
End Function
#End If

Regards
BentBrain
This post has been edited by BentBrain: Feb 13 2020, 08:21 PM

--------------------
"There is no excellent beauty that hath not some strangeness in the proportion" Francis Bacon
Go to the top of the page
 
RLG
post Feb 13 2020, 08:47 PM
Post#6



Posts: 56
Joined: 9-March 10



Thank you so much. Worked immediately.

I shall surely find other cproblems - I hope I can consult again if I am stumped.

Richard
Go to the top of the page
 
BentBrain
post Feb 13 2020, 09:08 PM
Post#7



Posts: 520
Joined: 10-February 03
From: Thailand


Glad to help.

No problem. ask any questions. someone will always offer some help.

Regards
BB

--------------------
"There is no excellent beauty that hath not some strangeness in the proportion" Francis Bacon
Go to the top of the page
 
BruceM
post Feb 14 2020, 08:45 AM
Post#8


UtterAccess VIP
Posts: 8,026
Joined: 24-May 10
From: Downeast Maine


While it will often work to use the Win64 declaration, in most cases there is no need. The Win64 declaration is a little deceptive in that it has to do with the Access version (that is to say, 32 or 64 bit), not the Windows version. But the real consideration is the VBA environment. VBA 7 was introduced with Office 2010. Earlier versions did not support 64 bit applications. There is a good summary description here.

First, I don't see the value to setting lngRet at all. It is declared at the procedure level, which is to say its value is available only within the function. Once it's set, the MouseCursor function ignores it, and never sets the MouseCursor value at all. Since the return type for MouseCursor is not specified it is a variant by default. Since its value is never set, and Variant is the only variable that can be null, the function return value will always be null. Further, no other function uses the MouseCursor value, from what I can see, although maybe it is used in code you didn't post. If so, try stepping through that code to see what MouseCursor value is being passed.

Back to the question of declarations, declaring a PtrSafe function means it's "safe" to run in a 64 bit environment, but that depends on properly declaring the arguments, and maybe the return value. I haven't found much in the way of documentation for the functions you are using, but in general, arguments such as hInstance As Long (with the "h" prefix) are memory locations (pointers) rather than defined values. My guess is that the "lp" prefix also indicates a pointer. With PtrSafe, in a 32 bit environment the memory location is 32 bits wide, and 64 bits wide in a 64 bit environment. In most cases the value being passed is 32 bits, but VBA assigns the memory location properly in the PtrSafe environment. Just as a bit, byte, or integer value can be passed where a Long is expected, a Long (32 bit value) can be passed where a 64 bit value can be accepted.

This function declaration is puzzling:

Declare PtrSafe Function LoadCursorBynum Lib "user32" Alias "LoadCursorA" _
(ByVal hInstance As Long, ByVal lpCursorName As Long) As Long

It declares the function as PtrSafe, but then declares hInstance as Long. When the function is called, most likely it's OK to pass a Long for the hInstance argument, provided the function is told to handle it as a LongPtr value, which is to say assign it to whatever size memory location is indicated by the Access version. In other words, the value passed is not what is important, it is how the function handles the value. Compare the SetClassLong declaration.

I'm not going to get too far into the weeds on this topic, partly because my own understanding is not as technical as it would need to be for me to break down all the details. The main thing, IMHO, is to consider the environment in which the program is to run. If it includes Access 2007 or earlier (VBA 6 or earlier), the conditional VBA7 declaration is needed, since earlier versions of VBA do not recognize PtrSafe or LngPtr. This is described in the link above, and also in this article, which is among the better references I have seen on the subject. If all Access versions are 2010 or later, just declare all functions as PtrSafe. Again, 32 bit Access knows what to do with PtrSafe and LongPtr in Access 2010 or later. It is quite rare that a Win64 conditional declaration is needed.

To summarize a little, while it may work in many cases to declare every Long as LongPtr, there is no guarantee it will always produce the correct results. A defined value should be handled as such, not as a memory location of flexible size.

One other thing: the documentation for SetClassLongA includes the advisory "This function has been superseded by the SetClassLongPtr function. To write code that is compatible with both 32-bit and 64-bit versions of Windows, use SetClassLongPtr". It is often best to review old code to assure it has not been superseded. Perhaps more to the point, it may be useful to try commenting out some of the code such as MouseCursor, to find out if it is used at all. Some code that is generously made available may be capable of doing more than a user needs. Sometimes troublesome code isn't needed at all.
Go to the top of the page
 


Custom Search


RSSSearch   Top   Lo-Fi    18th February 2020 - 01:25 PM