epuglise
asked on
User-proofing an Access Application
I'm creating a new routine for all my apps that will "clean" everything up before I release the tool.
I'm looking for best practices and advice for what I should include in the lock-down of my tool. Here are some of the things I'm looking to do:
1. Make my administrative forms and reports inaccessible or password protecting them somehow so I can access the stuff I need to but users can not.
2. Setting the current database properties to hide the application objects (tables, code, etc.)
3. My user base isn't too very technically savvy, so some of the "tricks" (like holding down shift when opening the app) aren't going to be a problem.
4. I don't have any security issues with the data, but I want to keep users from hurting themselves :) or accidentally breaking something.
I am not a fluent coder (yet) and any code snippets would be greatly appreciated.
I'm looking for best practices and advice for what I should include in the lock-down of my tool. Here are some of the things I'm looking to do:
1. Make my administrative forms and reports inaccessible or password protecting them somehow so I can access the stuff I need to but users can not.
2. Setting the current database properties to hide the application objects (tables, code, etc.)
3. My user base isn't too very technically savvy, so some of the "tricks" (like holding down shift when opening the app) aren't going to be a problem.
4. I don't have any security issues with the data, but I want to keep users from hurting themselves :) or accidentally breaking something.
I am not a fluent coder (yet) and any code snippets would be greatly appreciated.
I forget ... what Version of Access are you using ?
mx
mx
ASKER
2007
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Here is a KB on how to password protect a form or report ...
How to Create a Password Protected Form or Report
http://support.microsoft.com/?kbid=209871
mx
How to Create a Password Protected Form or Report
http://support.microsoft.com/?kbid=209871
mx
ASKER
Yay!! Thanks so much! I'll be working on this later today and can't wait to try this out. What i'd love to have on my apps is a "Release Me" button that I click and that turns off all my debuggers, cleans everything up, and gets the app ready for users... oh yeah and makes the Release Me button invisible :)
this will go a long way to helping.
this will go a long way to helping.
LOL
With the ReturnUserName code, on the form that has the cmdReleaseMe button, you put in the Form Open event
if returnusername <> "epuglise" them
me.cmdReleaseMe.visible = false
end if
The API code I posted gets put in a standard module and can then get used ANYWHERE in the rest of your VBA code.
I use it to hide buttons, change what opens on click events, filter what combo boxes display, the whole nine yards.
With the ReturnUserName code, on the form that has the cmdReleaseMe button, you put in the Form Open event
if returnusername <> "epuglise" them
me.cmdReleaseMe.visible = false
end if
The API code I posted gets put in a standard module and can then get used ANYWHERE in the rest of your VBA code.
I use it to hide buttons, change what opens on click events, filter what combo boxes display, the whole nine yards.
The Get Login name code/link I posted is much simpler and accomplishes the same thing ... Gets the Windows logged in user name.
"Release Me"
or Rescue Me !
You can certainly add code that does this ... which you could call from a hidden Macro I suppose.
mx
"Release Me"
or Rescue Me !
You can certainly add code that does this ... which you could call from a hidden Macro I suppose.
mx
@DatabaseMX
Both your code and mine come from Dev Ashish's site.
I find both the logon username and computername to be immensely useful.
Different printers, different install bases, different x86/x64 configurations...
I use them both across 50+ and reports and they're dead simple to use.
Each to their own, I guess.
Best page I ever googled when I started out
http://www.mvps.org/access/tencommandments.htm
Both your code and mine come from Dev Ashish's site.
I find both the logon username and computername to be immensely useful.
Different printers, different install bases, different x86/x64 configurations...
I use them both across 50+ and reports and they're dead simple to use.
Each to their own, I guess.
Best page I ever googled when I started out
http://www.mvps.org/access/tencommandments.htm
The entire module I posted came in its entirety from Dev site -- I think!
I can't find it now, there, anymore -- but it was the first API code I ever used.
Never messed with it, add to it, or subtracted from it.
On the other hand, It is simpler syntax from what is posetd there now.
Maybe someone extended it -- and didn't post there own disclaimer in there, so now I think it was all Dev's code
I'm not sure.
One thing I am sure of, is it's dead simple.
I can't find it now, there, anymore -- but it was the first API code I ever used.
Never messed with it, add to it, or subtracted from it.
On the other hand, It is simpler syntax from what is posetd there now.
Maybe someone extended it -- and didn't post there own disclaimer in there, so now I think it was all Dev's code
I'm not sure.
One thing I am sure of, is it's dead simple.
"The entire module I posted came in its entirety from Dev site -- I think!"
I get that ... it came form this link:
http://www.mvps.org/access/api/api0066.htm
I'm just saying the other two code snippets are a lot shorter and is what I've been using for years.
mx
I get that ... it came form this link:
http://www.mvps.org/access/api/api0066.htm
I'm just saying the other two code snippets are a lot shorter and is what I've been using for years.
mx
@DatabaseMX
I don't disagree. What I posted is long, and I also don't understand it.
I like the syntax though!
Dim SomeString as string
SomeString = ReturnUserName
I can remember that when I find my next nifty use of it.
fOSUserName ... not so much.
But that's me :)
Looking at API alphabet soup makes my head hurt.
Doesn't mean I don't use it when it's needful.
Up to the OP now!
I don't disagree. What I posted is long, and I also don't understand it.
I like the syntax though!
Dim SomeString as string
SomeString = ReturnUserName
I can remember that when I find my next nifty use of it.
fOSUserName ... not so much.
But that's me :)
Looking at API alphabet soup makes my head hurt.
Doesn't mean I don't use it when it's needful.
Up to the OP now!
"fOSUserName ... not so much."
What do you mean ?
mx
What do you mean ?
mx
LOL
"What was the name of that function that returned the username? Oh yeah--ReturnUserName!"
LOL
"What was the name of that function that returned the username? Oh yeah--ReturnUserName!"
LOL
What's so funny ?
Private Declare Function apiGetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Function ReturnUserName() As String
' Returns the network login name
Dim lngLen As Long, lngX As Long
Dim strUserName As String
strUserName = String$(254, 0)
lngLen = 255
lngX = apiGetUserName(strUserName , lngLen)
If ( lngX > 0 ) Then
ReturnUserName = Left$(strUserName, lngLen - 1)
Else
ReturnUserName = vbNullString
End If
End Function
How hard is that ?
mx
Private Declare Function apiGetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
Function ReturnUserName() As String
' Returns the network login name
Dim lngLen As Long, lngX As Long
Dim strUserName As String
strUserName = String$(254, 0)
lngLen = 255
lngX = apiGetUserName(strUserName
If ( lngX > 0 ) Then
ReturnUserName = Left$(strUserName, lngLen - 1)
Else
ReturnUserName = vbNullString
End If
End Function
How hard is that ?
mx
:)
I'd have to understand the code to do that
API code is where I come closest to breaking Dev Ashish's commandment #8
'Thou shalt not copy and paste other people's code without at least attempting to understand what it does.'
I don't really understand the API code--so I don't monkey with any farther than functionality requires, lest it destroy the entire universe. I honestly wouldn't dare to attempt what you did there--because most of the dependencies are incomprehensible to me. Any time I do monkey with it, I break it. And then I wind up copying and pasting in the code without alterations anyway.
API -- the magical black box. Not that I like black boxes. I'd prefer to understand my code--but I haven't got the time to become an API coder. So I use it when VBA can't or won't do what I need.
I'd have to understand the code to do that
API code is where I come closest to breaking Dev Ashish's commandment #8
'Thou shalt not copy and paste other people's code without at least attempting to understand what it does.'
I don't really understand the API code--so I don't monkey with any farther than functionality requires, lest it destroy the entire universe. I honestly wouldn't dare to attempt what you did there--because most of the dependencies are incomprehensible to me. Any time I do monkey with it, I break it. And then I wind up copying and pasting in the code without alterations anyway.
API -- the magical black box. Not that I like black boxes. I'd prefer to understand my code--but I haven't got the time to become an API coder. So I use it when VBA can't or won't do what I need.
But the code you propose (and the link I referenced) has API code ...
All I did was change the name of the Function ... which could be anything you want to call it.
mx
All I did was change the name of the Function ... which could be anything you want to call it.
mx
@DatabaseMX
But lets say I get it in my head to change this:
Private Declare Function GetComputerName Lib "Kernel32" _
Alias "GetComputerNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long
Almost certainly it'll get busted. My latest foray into API is here
https://www.experts-exchange.com/questions/26878741/MS-Access-VBA-Open-Explorer-exe-window-to-thumbnails-extra-large-icons-view.html
All I wanted to do at the end was pass in a path to this function:
Function EnumChildProc(ByVal lhWnd As Long, ByVal lParam As Long) As Long
Dim RetVal As Long
Dim WinClassBuf As String * 255, WinTitleBuf As String * 255
Dim WinClass As String, WinTitle As String
Dim WinRect As RECT
Dim WinWidth As Long, WinHeight As Long
RetVal = GetClassName(lhWnd, WinClassBuf, 255)
WinClass = StripNulls(WinClassBuf) ' remove extra Nulls & spaces
RetVal = GetWindowText(lhWnd, WinTitleBuf, 255)
WinTitle = StripNulls(WinTitleBuf)
ChildCount = ChildCount + 1
' see the Windows Class and Title for each Child Window enumerated
'Debug.Print " Child Class = "; WinClass; ", Title = "; WinTitle
' You can find any type of Window by searching for its WinClass
If WinClass = "ShellTabWindowClass" Then
Call ChangeView(lhWnd)
Exit Function
End If
If WinClass = "ThunderTextBox" Then ' TextBox Window
RetVal = GetWindowRect(lhWnd, WinRect) ' get current size
WinWidth = WinRect.Right - WinRect.Left ' keep current width
WinHeight = (WinRect.Bottom - WinRect.Top) * 2 ' double height
RetVal = MoveWindow(lhWnd, 0, 0, WinWidth, WinHeight, True)
EnumChildProc = False
Else
EnumChildProc = True
End If
End Function
Crash! Bang! Boom! MS Access has encountered an error and is restarting....
So I don't mess with the API code I google up ... much :)
It can be very unforgiving if mistreated...and I only have a vague idea of how to treat it.
But that's me.
YMMV, epuglise's too, No Biggie
But lets say I get it in my head to change this:
Private Declare Function GetComputerName Lib "Kernel32" _
Alias "GetComputerNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long
Almost certainly it'll get busted. My latest foray into API is here
https://www.experts-exchange.com/questions/26878741/MS-Access-VBA-Open-Explorer-exe-window-to-thumbnails-extra-large-icons-view.html
All I wanted to do at the end was pass in a path to this function:
Function EnumChildProc(ByVal lhWnd As Long, ByVal lParam As Long) As Long
Dim RetVal As Long
Dim WinClassBuf As String * 255, WinTitleBuf As String * 255
Dim WinClass As String, WinTitle As String
Dim WinRect As RECT
Dim WinWidth As Long, WinHeight As Long
RetVal = GetClassName(lhWnd, WinClassBuf, 255)
WinClass = StripNulls(WinClassBuf) ' remove extra Nulls & spaces
RetVal = GetWindowText(lhWnd, WinTitleBuf, 255)
WinTitle = StripNulls(WinTitleBuf)
ChildCount = ChildCount + 1
' see the Windows Class and Title for each Child Window enumerated
'Debug.Print " Child Class = "; WinClass; ", Title = "; WinTitle
' You can find any type of Window by searching for its WinClass
If WinClass = "ShellTabWindowClass" Then
Call ChangeView(lhWnd)
Exit Function
End If
If WinClass = "ThunderTextBox" Then ' TextBox Window
RetVal = GetWindowRect(lhWnd, WinRect) ' get current size
WinWidth = WinRect.Right - WinRect.Left ' keep current width
WinHeight = (WinRect.Bottom - WinRect.Top) * 2 ' double height
RetVal = MoveWindow(lhWnd, 0, 0, WinWidth, WinHeight, True)
EnumChildProc = False
Else
EnumChildProc = True
End If
End Function
Crash! Bang! Boom! MS Access has encountered an error and is restarting....
So I don't mess with the API code I google up ... much :)
It can be very unforgiving if mistreated...and I only have a vague idea of how to treat it.
But that's me.
YMMV, epuglise's too, No Biggie
ASKER
Ok, I think I understand the shorter bit of code from DatabaseMX better and I hate using code i don't understand (make debugging even harder for me).
DbMX: I'm using your steps with the images embedded and I think I do need the shift bypass code you reference.
Nick67: thx for the explicit code for opening the db with admin functions if it is "me".
My head hurts :(
DbMX: I'm using your steps with the images embedded and I think I do need the shift bypass code you reference.
Nick67: thx for the explicit code for opening the db with admin functions if it is "me".
My head hurts :(
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Ok another question. I'm scared to death of globals because i think some coding class at one time made a big deal about not using globals... BUT... do you think it makes sense to create a global that identifies the user as either an "Admin" or a "User" (which would be determined based on who the user is (from the get user id function)? I was thinking that the user type could be set when the app is opened the first time?
Then depending on what form needs what access, I could determine on a form-by-form basis what is visible and available and what is not.
Thank you for your advice.
Then depending on what form needs what access, I could determine on a form-by-form basis what is visible and available and what is not.
Thank you for your advice.
ASKER
(PS if that is a different question let me know and I'll open a separate question)
ASKER
@Nick: so those two functions turn on or off the entire tool bar; I assume a custom toolbar would consist of:
1. turning everything off
2. turning on only those things that apply to a particular user?
1. turning everything off
2. turning on only those things that apply to a particular user?
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Lots of good suggestions (and code) that got me to my solution: a global that identifies the type of user and then makes visible (or not) various program elements depending on that user type.
Thanks for the advice and code.
Thanks for the advice and code.
ASKER
PS @dbmx: i've seen other references to locking a db remotely, but the www.members.shaw link isn't working.
HUH
and for the most part, I do too.
It's Windows API code from Dev Ashish, and I don't pretend to understand it.
The upshot is you can put this code in a regular module, and then call
ReturnUserName()
ReturnComputerName()
That is monstrously useful...
Private sub Form_Open(Cancel as Integer)
if ReturnUserName <> "MyLoginName"
Cancel = True ' the form bails
end if
end sub
OR
Private sub SomeButton_Click()
select case true
case ReturnUserName = "JoeWho"
docmd.openform "JoesForm"
case ReturnUserName = "BobbyWhat"
msgbox "forget Bob, no joy for you"
case else
Msgbox "I don't know you from Jack the Bear"
end select
end sub
Please see Dev Ashish's wonderful site at http://www.mvps.org/access/ for more
Open in new window