The Win 64 BIT

Hankwembo Christopher,FCCA,FZICA,CIA,MAAT,B.A.Sc
Hankwembo Christopher,FCCA,FZICA,CIA,MAAT,B.A.Sc used Ask the Experts™
on
Hi

I have just come back from one of our depot with bad news the code below is block other code from working , we  are currently using Ms access 2016 stored as 32 BIT running on windows 64 BIT

#IF Win64 THEN
  Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal _
   lpBuffer As String, nSize As Long) As LongPtr
#Else
  Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal _
   lpBuffer As String, nSize As Long) As Long
#End If

For example we cannot up date depot details any more.

Any solution to this will be highly appreciated.

Regards

Chris
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Fabrice LambertConsulting
Distinguished Expert 2017

Commented:
Hi,

What do you need ?
The current user logged in windows (login name) ?

If so, rather than using troublesome APIs, you have some alternatives available:
1) Using environment variables:
Dim user As String
user = environ("USERNAME")

Open in new window


2) Using Wscript.Network object:
Dim wshNet As Object
Set wshNet = CreateObject("WScript.Network")

Dim user As String
user = wshNet.UserName
Set wshNet = Nothing

Open in new window

What I need is to store the captured detail in login table then use the captured details on the queries so that the following can appear on the reports:

(1) The person who created the voucher
(2) The person who approved the voucher


On the code below it worked very well but for some reasons it has stopped and start blocking other code , I believe there is just one more declaration missing here:


#IF Win64 THEN
  Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal _
   lpBuffer As String, nSize As Long) As LongPtr
#Else
  Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal _
   lpBuffer As String, nSize As Long) As Long
#End If
Public Function GetUser() As String

   Dim strBuffer As String
   Dim lngSize As Long, lngRetVal As Long
   
   lngSize = 199
   strBuffer = String$(200, 0)
   
   lngRetVal = GetUserName(strBuffer, lngSize)
   
   GetUser = Left$(strBuffer, lngSize - 1)

End Function


Public Function GetFullName()

    Const MESSAGETEXT = "The current user is not recorded in the Users table."
    Dim strCriteria As String
    Dim varFullName As Variant
   
    strCriteria = "LoginName = """ & GetUser & """"

    varFullName = DLookup("FullName", "Users", strCriteria)
   
    If Not IsNull(varFullName) Then
        GetFullName = varFullName
    Else
        MsgBox MESSAGETEXT, vbExclamation, "Warning"
    End If
       
End Function

Public Function AddNewUser()

    Dim strCriteria As String
    Dim strLoginName As String
    Dim strFullName As String
    Dim strSQL As String
   
    strLoginName = GetUser()
    strCriteria = "LoginName = """ & strLoginName & """"
   
    If IsNull(DLookup("LoginName", "Users", strCriteria)) Then
        strFullName = InputBox("Enter new user's full name:")
        strSQL = "INSERT INTO Users(LoginName,FullName) " & _
            "VALUES(""" & strLoginName & """,""" & strFullName & """)"
   
        CurrentDb.Execute strSQL, dbFailOnError
    End If

End Function
Fabrice LambertConsulting
Distinguished Expert 2017

Commented:
Scratch these APIs and use one of the alternative I posted.
Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Bill PrewTest your restores, not your backups...
Top Expert 2016

Commented:
If you did want to stay with the existing APIs (and I agree for getting the user ID I would use a pure VBA approach rather than the older Windows API approach), this change should get you going:

   lngRetVal = CLng(GetUserName(strBuffer, lngSize))

Open in new window


»bp
Bill PrewTest your restores, not your backups...
Top Expert 2016

Commented:
So you could replace all of this:

#IF Win64 THEN
  Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal _
   lpBuffer As String, nSize As Long) As LongPtr
#Else
  Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal _
   lpBuffer As String, nSize As Long) As Long
#End If
Public Function GetUser() As String

   Dim strBuffer As String
   Dim lngSize As Long, lngRetVal As Long
   
   lngSize = 199
   strBuffer = String$(200, 0)
   
   lngRetVal = GetUserName(strBuffer, lngSize)
   
   GetUser = Left$(strBuffer, lngSize - 1)

End Function

Open in new window

With:

Public Function GetUser() As String
    GetUser = Environ("USERNAME")
End Function

Open in new window


»bp
Jim Dettman (EE MVE)President / Owner
Most Valuable Expert 2017
Most Valuable Expert 2012

Commented:
Couple things:

1. Using an Environ variable, your opening up a security hole.   Any user that can get to the command line would then be able to circumvent security.   The API is a better approach as you are then getting a username based on authenticated credentials.

2. On this:

"#IF Win64 THEN"

   What's critical in your code is the "bitness" of Office  that is installed, not Windows.   The WIN64 constant is used to tell if your running in 64 or 32 bit VBA.    The constant VBA7 tells you if your running in VBA from Access 2010 and up, or prior.

For help with 32 vs 64 bit Access code, see the links in this comment:

https://www.experts-exchange.com/questions/27190589/GetUserName-fails-on-64bit-Access.html#a36167741

 also, you don't say what's wrong with your code, but the call for that was not modified for 64 bit..  You should be able to do:

Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

 and be fine in A2010 and up with 32 or 64 bit Access.

Jim.
I have tried this in the past , this is not even reliable, it works if one is using the same computer but the moment you move your database to  another computer with runtime environment it stops working!

That is the reason why I'm not using it. For example according to your code , I was using it like like below , please follow me:

(1) Create a module:

Public Function GetUser() As String
    GetUser = Environ("USERNAME")
End Function

(2) At form level

I will create a control which I want to be inserted with the window login details

Then I will use this

Before insert event

Me. txtCreatedby = GetUser()

End sub

Please check and confirm  if I'm  I was not doing the right thing!

On the approval side

I will use  form current event

with Me.txtauthorized by = GetUser()

Regards

Chris
also, you don't say what's wrong with your code, but the call for that was not modified for 64 bit..  You should be able to do:

Now what about doing it like below:

#If VBA7 And Win64 Then
    'x64 Declarations
    Private Declare PtrSafe Function apiGetUserName Lib "advapi32.dll" Alias _
            "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
#Else
    'x32 Declaration
    Private Declare Function apiGetUserName Lib "advapi32.dll" Alias _
            "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
#End If

Regards

Chris
President / Owner
Most Valuable Expert 2017
Most Valuable Expert 2012
Commented:
It would be this:

#If VBA7 Then
    ' A2010 and up.  Works in 32 or 64 bit Office
    Declare PtrSafe Function apiGetUserName Lib "advapi32.dll" Alias  "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
#Else
    ' A2010 and prior.
     Declare Function apiGetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
#End If

 In that link I posted earlier was this:

Compatibility Between the 32-bit and 64-bit Versions of Office 2010
http://msdn.microsoft.com/en-us/library/ee691831(office.14).aspx

Read the section "Introducing the VBA 7 Code Base", which describes the use of VBA7 and WIN64 constants.  Very confusing at first, but what you want is:

1. Use VBA7 for code in A2010 and up vs prior versions of Access where you want to do 32 and 64 bit.  (allows you to use PtrSafe).

2. WIN64 for when the API call being made is different between 32 and 64 bit Access code.

 In this case, the call is the same call in both 32 and 64 bit.  So all you need is a statement that checks if your in A2010 and up code.  If so, then you can use PtrSafe.     PtrSafe is not required in 32 bit, but it is for 64 bit.    but if you use it in 32 bit code with A2010 and up, then it is just ignored.

Now let's say the call was different between 32 and 64 bit.   That would look like this:

#If VBA7 then
 ' Running in A2010 and up
 ' Are we running 64 bit?   Differnet call for lib if in 64 bit - needs LongLong data type.
  #if Win64 then
     Declare PtrSafe Function MyMathFunc Lib "User32" (ByVal N As LongLong) As LongLong
  #else
     ' Running 32 bit.  Using PtrSafe, but it is not really needed as it is ignored.
     Declare PtrSafe Function MyMathFunc Lib "User32" (ByVal N As Long) As Long
  #end if
#else
  ' Running in something prior to A2010
  ' Can't use PtrSafe
   Declare Function MyMathFunc Lib "User32" (ByVal N As Long) As Long
#end if
Jim Dettman (EE MVE)President / Owner
Most Valuable Expert 2017
Most Valuable Expert 2012

Commented:
Chris,

  Also note that you had "Private" in the front of your declares.   I dropped that so they work throughout the app.   not sure how you had things setup, but that might have been part of your problem.

Jim.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial