Link to home
Start Free TrialLog in
Avatar of Gazza110
Gazza110

asked on

Password Mask for MS Access Inputbox

Hi,

I know that this has been asked before but I want some code to create an inputbox in MS Access that has a password character *  in it rather than displaying the text.

I know this is possible in MS Excel by creating a customer Inputbox in module code, however the Excel code does not work in MS Access.

Here is a sample of the Excel Code :

#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~

(basAddrOf) - Module


Option Explicit
'// My thanks to:
'// Ken Getz and Michael Kaplan
'// For their brilliant work with
'// Using Callbacks with Office 97
'// KNG Consulting, Inc.
'// Copyright © 1998
'// Ken Getz & Michael Kaplan
'// All rights reserved.
'-------------------------------------------------------------------------------------------------------------------
'   Declarations
'
'   These function names were puzzled out by using DUMPBIN /exports
'   with VBA332.DLL and then puzzling out parameter names and types
'   through a lot of trial and error and over 100 IPFs in MSACCESS.EXE
'   and VBA332.DLL.
'
'   These parameters may not be named properly but seem to be correct in
'   light of the function names and what each parameter does.
'
'   EbGetExecutingProj: Gives you a handle to the current VBA project
'   TipGetFunctionId: Gives you a function ID given a function name
'   TipGetLpfnOfFunctionId: Gives you a pointer a function given its function ID
'
'-------------------------------------------------------------------------------------------------------------------
Private Declare Function GetCurrentVbaProject _
    Lib "vba332.dll" _
    Alias "EbGetExecutingProj" ( _
    hProject As Long) _
As Long

Private Declare Function GetFuncID _
    Lib "vba332.dll" _
    Alias "TipGetFunctionId" ( _
    ByVal hProject As Long, _
    ByVal strFunctionName As String, _
    ByRef strFunctionId As String) _
As Long

Private Declare Function GetAddr _
    Lib "vba332.dll" _
    Alias "TipGetLpfnOfFunctionId" ( _
    ByVal hProject As Long, _
    ByVal strFunctionId As String, _
    ByRef lpfn As Long) _
As Long

'-------------------------------------------------------------------------------------------------------------------
'   AddrOf
'
'   Returns a function pointer of a VBA public function given its name. This function
'   gives similar functionality to VBA as VB5 has with the AddressOf param type.
'
'   NOTE: This function only seems to work if the proc you are trying to get a pointer
'       to is in the current project. This makes sense, since we are using a function
'       named EbGetExecutingProj.
'-------------------------------------------------------------------------------------------------------------------
Public Function AddrOf(strFuncName As String) As Long
    Dim hProject As Long
    Dim lngResult As Long
    Dim strID As String
    Dim lpfn As Long
    Dim strFuncNameUnicode As String
   
    Const NO_ERROR = 0
   
    ' The function name must be in Unicode, so convert it.
    strFuncNameUnicode = StrConv(strFuncName, vbUnicode)
   
    ' Get the current VBA project
    ' The results of GetCurrentVBAProject seemed inconsistent, in our tests,
    ' so now we just check the project handle when the function returns.
    Call GetCurrentVbaProject(hProject)
   
    ' Make sure we got a project handle... we always should, but you never know!
    If hProject <> 0 Then
        ' Get the VBA function ID (whatever that is!)
        lngResult = GetFuncID( _
         hProject, strFuncNameUnicode, strID)
       
        ' We have to check this because we GPF if we try to get a function pointer
        ' of a non-existent function.
        If lngResult = NO_ERROR Then
            ' Get the function pointer.
            lngResult = GetAddr(hProject, strID, lpfn)
           
            If lngResult = NO_ERROR Then
                AddrOf = lpfn
            End If
        End If
    End If
End Function


#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~

(ModInput)  -  Module



Option Explicit

'////////////////////////////////////////////////////////////////////
'Password masked inputbox
'Allows you to hide characters entered in a VBA Inputbox.
'
'Code written by Daniel Klann
'http://www.danielklann.com/
'March 2003

'// Kindly permitted to be amended
'// Amended by Ivan F Moala
'// http://www.xcelfiles.com
'// April 2003
'// Amended for XL97
'////////////////////////////////////////////////////////////////////


'API functions to be used
Private Declare Function CallNextHookEx _
    Lib "user32" ( _
    ByVal hHook As Long, _
    ByVal ncode As Long, _
    ByVal wParam As Long, _
    lParam As Any) _
As Long

Private Declare Function GetModuleHandle _
    Lib "kernel32" _
    Alias "GetModuleHandleA" ( _
    ByVal lpModuleName As String) _
As Long

Private Declare Function SetWindowsHookEx _
    Lib "user32" _
    Alias "SetWindowsHookExA" ( _
    ByVal idHook As Long, _
    ByVal lpfn As Long, _
    ByVal hmod As Long, _
    ByVal dwThreadId As Long) _
As Long

Private Declare Function UnhookWindowsHookEx _
    Lib "user32" ( _
    ByVal hHook As Long) _
As Long

Private Declare Function SendDlgItemMessage _
    Lib "user32" Alias "SendDlgItemMessageA" ( _
    ByVal hDlg As Long, _
    ByVal nIDDlgItem As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) _
As Long

Private Declare Function GetClassName _
    Lib "user32" _
    Alias "GetClassNameA" ( _
    ByVal hwnd As Long, _
    ByVal lpClassName As String, _
    ByVal nMaxCount As Long) _
As Long

Private Declare Function GetCurrentThreadId _
    Lib "kernel32" () _
As Long

'Constants to be used in our API functions
Private Const EM_SETPASSWORDCHAR = &HCC
Private Const WH_CBT = 5
Private Const HCBT_ACTIVATE = 5
Private Const HC_ACTION = 0

Private hHook As Long

Public Function NewProc(ByVal lngCode As Long, _
                        ByVal wParam As Long, _
                        ByVal lParam As Long) As Long

Dim RetVal
Dim strClassName As String, lngBuffer As Long

If lngCode < HC_ACTION Then
    NewProc = CallNextHookEx(hHook, lngCode, wParam, lParam)
    Exit Function
End If

strClassName = String$(256, " ")
lngBuffer = 255

If lngCode = HCBT_ACTIVATE Then    'A window has been activated
    RetVal = GetClassName(wParam, strClassName, lngBuffer)
    If Left$(strClassName, RetVal) = "#32770" Then  'Class name of the Inputbox
        'This changes the edit control so that it display the password character *.
        'You can change the Asc("*") as you please.
        SendDlgItemMessage wParam, &H1324, EM_SETPASSWORDCHAR, Asc("*"), &H0
    End If
End If
   
'This line will ensure that any other hooks that may be in place are
'called correctly.
CallNextHookEx hHook, lngCode, wParam, lParam

End Function

'// Make it public
'// Lets simulate the VBA Input Function
Public Function InputBoxDK(Prompt As String, Optional Title As String, _
            Optional Default As String, _
            Optional Xpos As Long, _
            Optional Ypos As Long, _
            Optional Helpfile As String, _
            Optional Context As Long) As String
   
Dim lngModHwnd As Long, lngThreadID As Long
   
'// Lets handle any Errors JIC! due to HookProc> App hang!
On Error GoTo ExitProperly
lngThreadID = GetCurrentThreadId
lngModHwnd = GetModuleHandle(vbNullString)
   
hHook = SetWindowsHookEx(WH_CBT, AddrOf("NewProc"), lngModHwnd, lngThreadID)
If Xpos Then
    InputBoxDK = InputBox(Prompt, Title, Default, Xpos, Ypos, Helpfile, Context)
Else
    InputBoxDK = InputBox(Prompt, Title, Default, , , Helpfile, Context)
End If

ExitProperly:
UnhookWindowsHookEx hHook

End Function

Sub TestDKInputBox()
Dim x

x = InputBoxDK("Type your password here.", "Password Required")
If x = "" Then End
If x <> "yourpassword" Then
    MsgBox "You didn't enter a correct password."
    End
End If

MsgBox "Welcome Creator!", vbExclamation
   
End Sub


#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~

You would then use InputBoxDK function as opposed to InputBox and this would * out the entered text as you enter it (just like a password character).

Can something simular be done with MS Access, as I don't want to have to create custom form, I want to just be able to use code to accomplish the relevant task.

Many thanks,

Gaz.




Avatar of Rey Obrero (Capricorn1)
Rey Obrero (Capricorn1)
Flag of United States of America image

<I don't want to have to create custom form> ?
It is easier to do this with form.

Create a new form;
Place two text boxes and two command button for OK and Cancel

For the password textbox set the Input Mask property
to ;
click the three  dots {...} and select the format and mask.
For the codes to check the password against the username;
create a table and do a lookup on the click of the OK button.

Do you like it this way?


Avatar of Gazza110
Gazza110

ASKER

I don't want to have lots of forms on the database there are already enough !!

I'm sure that it must be possible to have a masked inputbox, so I'd rather do things the hard way.

Any ideas anyone ??

Gaz.
It's not about looking up the password (This will be contained within the code), it is purly about masking the input without having to create several custom forms for this, when an input box would be more than sufficient as long as in masks out the text being typed.

Gaz.
You can not do this except on a form.  
An inputbox command will not get it.  
An inputbox is an object you do not have format control over.

capricorn1 is giving to you straight.  You might not like it, but that's the way it is.
-j-
The Standard "InputBox" command will not give you a password character thats right.

However it is possible to create your own custom input boxes that you can specify to have a password character as my original questions specifies.

If this can be done in MS Excel, then I'm 100% confident this can also be done in MS Access too.

What I am really asking for is the relevant code to do this, my programming skills don't extend that far yet !!!

Gaz,
That is what i think i explained in my first post.

We have to start by creating a blank form and placing two textboxes for the username and password.
then the coding will be next.
Are you having problem creating a form?
<If this can be done in MS Excel,>
I think you are pertaining to File protection where you could set a password, and when
you try to open the file, it will ask for the password and the password you type are displayed as * or whatever mask
was set.
I DON'T WANT A FORM !!!!!!!!!!!!!!!!!!!!

I'm fairly advanced at using MS Access, I can easily create forms with unbound fields, use Dlookup to lookup usernames and passwords if that was what I wanted to do however it isn't.

I have restricted access to some forms by using an input box that asks for a password (password within the code), which all works fine. However you can see the password being typed in as an input box does not mask the entry.

Yes - I know that I could have a form with text fields that have password fields on them, however I don't want to have to create a great number of form to accomplish this task. As I stated I'm sure there is a way to create a custom input box that masks out the text entered in it.

I have a MS Excel file that this works on!, however I want this to work on a MS Access form. I'm sure it is possible.

Thanks for the alternative suggestions, however I really want an answer to this question - not a near substitute answer.

Thanks,

Gaz.
Ok then this is what you need.
You have to create a Password form and use it for all password protected form
Here you can set the mask

How to Create a Password Protected Form or Report
http://support.microsoft.com/?kbid=209871
Whether you can do this in EXCEL is totally IRRELEVANT, because, as has been adequately stated, you CANNOT (ABSOLUTELY CANNOT) do this in Access VBA.  The two versions of VBA are INDEPENDENT and though similar, are in fact UNRELATED - they are sort of like distant cousins, who just happen to have the same last name, and speak the same language - they ARE NOT the same thing. ( My last name is Wood, but that does not mean that I am in the same family as all the other Wood's who happen to live on planet Earth, even if they also happen to speak English, or even happen to also live in Nothern Virginia - we just happen to have the same last name.)

You are dealing here with guaranteed EXPERTS in Access VBA, who have, collectively, tried and done far more that you will ever attempt to do( if the extent of your coding involves using DLookup, then you have barely scratched the surface), and to suggest that they are not knowledgable enough to provide you every possible solution is total nonsense.  If a solution along the lines of what you seem set on were possible, then one or more of thses experts would gladly tell you how to go about it.  But such a solution is NOT possible in Access VBA, so deal with it.  Your only choice is to create a separate form, and set the Password character for the password text box.  Period, end of discussion.

AW
Arthur ...

Thanks for your input but sarcasm really ISN'T all that helpful.

Please don't try and comment on my level of knowledge, as you don't know anything about me, equally I haven't comment on anyone else's ability <they are not knowledgeable enough to provide you every possible solution > when have I said this ?? - These are your words not mine.

I have been presented with alternative suggestions of which I have responded to advising that the response wasn't quite the technique I wanted to employ.

Yes I am aware that Excel and Access VB operates in different ways, but the fundamental principals of input (all be it input boxes, messages boxes etc) are universal and I fully believe that if there is a way of creating the same type of custom function in Access as indeed I know it is possible in Excel.

I know that it can be frustrating when you make suggestions that someone rejects, however I have not yet had a satisfactory answer to my question, and insulting me and my intelligence really is NOT appreciated.

Now, If you or anyone can help on this problem, I would be grateful (If however you can't please send no reply as opposed to the sarcastic comment just received)

Regards,

Gaz.
Arthur:  Very well put, and I was about to post the very same arguement, but lets look at these additional facts.

The code posted is noted to have been modified for XL97.  It appears to simply divert the keystrokes from a standard Inputbox before display.  It uses the standard input box for this purpose.
API calls would presumeably be used for 97 product versions.

I created a new module and put all that stuff into it and it hung Acc97 when I tried to step thru the code.  I suspect that the operation is close, but modified in such a way as to make it Excel specific.

This passle of code could very well be it, but you're going to have to modify it and that may require the permissions of the authors if you are going to do it legit.  and.... since the code is copy righted the Experts here can not have a part in violating that trust with other developers.  

I have also asked a moderator to look in to see that we don't go over the line on the membership agreement on this question since it involves something this close to a copyright.
Gazza110:

Some advice:
  For your first question you are getting off to a simply MARVELOUS start in requesting the services of the best Experts in MS Access.  You might want to at least consider more seriously the input given.
  The Experts here are volunteers, not paid staff.  You might want to keep that in mind when you decide to get really demanding.  
  Word travels fast in professional communities too.
  just a thought.

-j-
aw:  please contact me at your convenience.  i need your advice on another question.
Permission to adapt above Excel Code:

==================================================================
 
Hi Gary
 
Yes, by all means.
Let me know if you get this to work.
 
 
Regards
 
Ivan



--------------------------------------------------------------------------------
From: Gary Mellor
Sent: Sunday, 11 April 2004 5:25
To: consult@xcelfiles.com
Subject: InputBox password character


Hi,
 
I'm currently trying to get a password character to work on an Inputbox using MS Access.
 
Can I please have permission to modify your Excel code listed on your website (http://www.xcelfiles.com/API_09.html)  ???
 
 
Best Regards,
 
Gary J Mellor.
Mask an InputBox... hmm

I do this in one of my db's, will look and see if I can find it for you, give me a little time please...

Alan
Alan: (g'day dude!)
I've been to find the right kung fu for that function off and on since I  posted.
I can't get it to give up the ClassID of the Access Inputbox that its using.
I can't wait for your findings sir!
-j-
ASKER CERTIFIED SOLUTION
Avatar of Alan Warren
Alan Warren
Flag of Philippines image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Jack,

there it is mate :)
been using it for some time now...

Alan
This seems like a huge effort to replace what would be a simple new User form.  But what the heck, why do something in 15-30 lines of code, if you can accompished the same thing in 200?

If it works for you, then go for it.

AW
AW, howabout in 8 lines

Global PWFromForm as String

if PWFrm() <> "ThePassword" then
  'doh!
else
 'alrighty then!
endif

Public function PWFrm() as String
  docmd.openform "PassWordPlease",....
  'when closing the form passes the "unmasked"password to the variable
  PWFrm= PWFromForm
end function

<--->
If you are all itchy about using Global variables,... too bad.  I like them sometimes, and I use them sparingly enough.

The code posted by the asker that what was causing me to think my machine was hung,... is constantly polling for keyboard input while the inputbox was loaded.  {CTRL}{BREAK} would not work due to the speed of the repetition of the API loop.

If anyone else comes along on a search and finds this question the,...my code does not "hold up" the processor to get a string of 4 to 20 keystrokes from the user.  All other regular windows activities may take place in the background.

Also if you are not workingly familiar API yet, a regular old teeny weeny form and about 8 lines of VBA can get you the very same effect.
This also reduces the dependencies of this operation to just VBA with no dependencies on operating system or office version.

Capricorn1's first several responses to the questioner would have sufficed in this case but as he made so very clear...  
  I DON'T WANT A FORM !!!!!!!!!!!!!!!!!!!!  
I think that bears repeating on this question.  Because the answer to the "password" masking is in cap's commentary.

thanx to alanwarren, et al, for that "no form required" answer!  You're too good to us alan
THANKS Alan  -  This is fantastic, just what I wanted!!!!!.

There was one problem I encountered, that was that the code did not work in Access 97 as the "AddressOf" function was not supported (works fine in Access 2000), however I managed to find a fix to this by ....

Adding a module " mdlAddrOf "

===============(mdlAddrOf)==========================================

Option Compare Database
Option Explicit
'-------------------------------------------------------------------------------------------------------------------
'   Declarations
'
'   These function names were puzzled out by using DUMPBIN /exports
'   with VBA332.DLL and then puzzling out parameter names and types
'   through a lot of trial and error and over 100 IPFs in MSACCESS.EXE
'   and VBA332.DLL.
'
'   These parameters may not be named properly but seem to be correct in
'   light of the function names and what each parameter does.
'
'   EbGetExecutingProj: Gives you a handle to the current VBA project
'   TipGetFunctionId: Gives you a function ID given a function name
'   TipGetLpfnOfFunctionId: Gives you a pointer a function given its function ID
'
'-------------------------------------------------------------------------------------------------------------------
Private Declare Function GetCurrentVbaProject Lib "vba332.dll" Alias "EbGetExecutingProj" (hProject As Long) As Long
Private Declare Function GetFuncID Lib "vba332.dll" Alias "TipGetFunctionId" (ByVal hProject As Long, ByVal strFunctionName As String, ByRef strFunctionId As String) As Long
Private Declare Function GetAddr Lib "vba332.dll" Alias "TipGetLpfnOfFunctionId" (ByVal hProject As Long, ByVal strFunctionId As String, ByRef lpfn As Long) As Long

Public Function AddrOf(strFuncName As String) As Long

'-------------------------------------------------------------------------------------------------------------------
'   AddrOf
'
'   Returns a function pointer of a VBA public function given its name. This function
'   gives similar functionality to VBA as VB5 has with the AddressOf param type.
'
'   NOTE: This function only seems to work if the proc you are trying to get a pointer
'       to is in the current project. This makes sense, since we are using a function
'       named EbGetExecutingProj.
'-------------------------------------------------------------------------------------------------------------------
   
    Dim hProject As Long
    Dim lngResult As Long
    Dim strID As String
    Dim lpfn As Long
    Dim strFuncNameUnicode As String
   
    Const NO_ERROR = 0
   
    ' The function name must be in Unicode, so convert it.
    strFuncNameUnicode = StrConv(strFuncName, vbUnicode)
   
    ' Get the current VBA project
    ' The results of GetCurrentVBAProject seemed inconsistent, in our tests,
    ' so now we just check the project handle when the function returns.
    Call GetCurrentVbaProject(hProject)
   
    ' Make sure we got a project handle... we always should, but you never know!
    If hProject <> 0 Then
        ' Get the VBA function ID (whatever that is!)
        lngResult = GetFuncID(hProject, strFuncNameUnicode, strID)
       
        ' We have to check this because we GPF if we try to get a function pointer
        ' of a non-existent function.
        If lngResult = NO_ERROR Then
            ' Get the function pointer.
            lngResult = GetAddr(hProject, strID, lpfn)
           
            If lngResult = NO_ERROR Then
                AddrOf = lpfn
            End If
        End If
    End If
End Function

============== End of (mdlAddOf) ===================================

Then replace the line .....

 lTemp = SetTimer(Me.hwnd, NV_INPUTBOX, 1, AddressOf TimerProc)


With  .....

 lTemp = SetTimer(Me.hwnd, NV_INPUTBOX, 1, AddrOf("TimerProc"))


Then this works fine in Access 97.

Thanks again Alan - you have really helped me out.

Best Regards,

Gaz.
Pleasure Gaz,

thanks for the positive feed-back and the backwards compatibility modification, cool.

hmmm... will it work in Access version 2 ??

nah, just kidding <Grin>

Alan
Does anyone know a way of making this code work with BOTH Access 97 & 2000 without the different procedures for each version - one unified solution ????

Gaz.
I have to admit I'm with AW on this one.  The difference between a popup, modal form with a textbox whose input mask is set to 'password' (without quotes), a label with a caption, and a command button, and an inputbox is vanishingly small.  Code for such a form is:

Option Compare Binary
Option Explicit
Public NumStrikes As Integer

Private Sub cmdSubmit_Click()
Dim thePassCode As String
Dim theInput As String
thePassCode = "SoME CasE SenstIVe StriNG"
theInput = Me.txtPassword.Value
If theInput = thePassCode Then
    DoCmd.OpenForm "frmTheProtectedForm"
    DoCmd.Close acForm, Me.Name, acSaveYes
    DoCmd.SelectObject acForm, "frmTheProtectedForm"
    DoCmd.Maximize
Else
    NumStrikes = NumStrikes + 1
    Select Case True
        Case NumStrikes < 4
            MsgBox "Try again!"
            Me.txtPassword.Value = Null
        Case Else
            MsgBox "Sorry, the exam app will now close"
            DoCmd.Close
            DoCmd.Quit
    End Select
End If
End Sub

This code gives you a number of chances before killing the app--which I don't know if you could EVER get an inputbox to do--without coding it elsewhere, anyway.

Now, why else would anyone want to use an inputbox--It is reusesble.  Well, so is a form like this, but you have to look after some of the details, but then it is also way more flexible too!  I have a similar form--but it has a calendar control on it--(A2K7 finally gave us popup calendars for date fields, but I had to roll my own 4 years earlier)  Code that calls the form passes Me.name to a global string variable names MyForm, when the form closes, it passes values back to the form that called it and cleans up the global vaiable behind itself.  Very simple and very effective.  I would never use a passle of API code to do what a simple modal popup form could do instead.

For the authors purpose, replacing the if...then...else block with a select case true setup would provide the ultimate in simple, reusable and extensible password protection...

select case true
    Case myForm = "frmTheProtectedForm" and theInput = "SoME CasE SenstIVe StriNG"
       'do some stuff
    Case myForm = "frmTheOtherForm" and theInput = "SoME different STRING"  
      'do other stuff
    Case Else
    NumStrikes = NumStrikes + 1
    Select Case True
        Case NumStrikes < 4
            MsgBox "Try again!"
            Me.txtPassword.Value = Null
        Case Else
            MsgBox "Sorry, the exam app will now close"
            DoCmd.Close
            DoCmd.Quit
    End Select
End select

Kudos to the answerers for giving the author what he asked for, but the author could have gotten an easier, more elegant, more robust--and over versions, less likely to break, and more maintainable solution if he had described more what he required operationally, than insisting on what method he wanted to use to get the result.

Nick67
I have been looking for a simple way to mask a password for some time now.  Creating a tiny little form with tiny bits of code (as outlined on this post) was amazingly simple and works like a charm.  Thanks.

With regard to GAZZA110?  As a user and not a mod, I can openly say that I am surprised ANYBODY bothered helping him or her with this issue.  In the first place, the form worked perfectly and was super simple.  In the second place, the antagonistic and aggressive tone of the posts were a total put-off.  Good job getting the "right" answer.  I know I wouldn't have lifted a finger to help.