I have (once again) a problem with MS Access. Access has the somewhat peculiar habit to loose object references if errors in the vba code occur for example. I found a pretty neat solution adressing this problem which seems to work most of the time but sometimes causes Access to crash.
Public CurrentUser As CUser 'CUser is a class containing Userinformation
Private Const C_USER_STORAGENAME As String = "CURRENTUSER_HANDLEID"
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (destination As Any, source As Any, ByVal length As LongPtr)
Private Const rbHandleProp = C_USER_STORAGENAME
Public Function InitUser() As Integer
Dim lngUserPtr As LongPtr
Set CurrentUser = New CUser 'Cache a copy
CurrentUser.InitializeUser
lngUserPtr = ObjPtr(CurrentUser) 'HandleID
WriteProjProperty rbHandleProp, lngUserPtr 'Write HandleID
End Function
Private Sub WriteProjProperty(key As String, Value As Variant)
On Error Resume Next
CurrentProject.Properties(key).Value = Value
If err.Number = 2455 Then 'No Key!
CurrentProject.Properties.Add key, Value
End If
End Sub
Private Function GetCurrentUser(lngUserPtr As LongPtr) As Object
Dim objUser As Object
CopyMemory objUser, lngUserPtr, 4 'CRASHES HERE SOMETIMES
Set GetCurrentUser = objUser
Set objUser = Nothing
End Function
Public Function ReadProjProperty(key As String) As Variant
On Error Resume Next
ReadProjProperty = CurrentProject.Properties(key).Value
End Function
Property Get msCurrentUser() As CUser
If CurrentUser Is Nothing Then
Set CurrentUser = GetCurrentUser(CLng(ReadProjProperty(rbHandleProp)))
End If
Set msCurrentUser = CurrentUser
End Property
The User-Object is initialized once on startup and the handle is saved. The user-information can be aquired through the Property msCurrentUser. As I said this works most of the time but there seems to be certain cases in which CopyMemory fails. Any help would be appreciated.
Thanks in advance
Jon
Seriously, don't do that - it's a pain, but you'll just have to recreate the object as required. At present you're caching an object reference, i.e. a pointer to a specific location in memory (*). When an unhandled error causes the object to be destroyed, the operating system (or Access' internal memory manager) is unlikely to reuse the memory previously occupied by the object immediately (i.e., the memory pointed to by the reference), which is why your code appears to work sometimes. Even when it does 'work' however, in reality you're deferencing a stale pointer.
(*) There's actually more than one level of indirection given an Access object reference is a COM/IUnknown pointer under the bonnet, but simplifying in terms of one is enough to make the point.