Solved

User-proofing an Access Application

Posted on 2011-03-11
28
473 Views
Last Modified: 2012-05-11
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.
0
Comment
Question by:epuglise
  • 10
  • 10
  • 8
28 Comments
 
LVL 26

Expert Comment

by:Nick67
ID: 35113583
You'll look at this code and go

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

Option Compare Database
Option Explicit

Private Type USER_INFO_2
    usri2_name As Long
    usri2_password  As Long  ' Null, only settable
    usri2_password_age  As Long
    usri2_priv  As Long
    usri2_home_dir  As Long
    usri2_comment  As Long
    usri2_flags  As Long
    usri2_script_path  As Long
    usri2_auth_flags  As Long
    usri2_full_name As Long
    usri2_usr_comment  As Long
    usri2_parms  As Long
    usri2_workstations  As Long
    usri2_last_logon  As Long
    usri2_last_logoff  As Long
    usri2_acct_expires  As Long
    usri2_max_storage  As Long
    usri2_units_per_week  As Long
    usri2_logon_hours  As Long
    usri2_bad_pw_count  As Long
    usri2_num_logons  As Long
    usri2_logon_server  As Long
    usri2_country_code  As Long
    usri2_code_page  As Long
End Type

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


Private Declare Function GetComputerName Lib "Kernel32" _
Alias "GetComputerNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long

 
Private Declare Function apiNetGetDCName _
    Lib "netapi32.dll" Alias "NetGetDCName" _
    (ByVal servername As Long, _
    ByVal DomainName As Long, _
    bufptr As Long) As Long
 
' function frees the memory that the NetApiBufferAllocate
' function allocates.
Private Declare Function apiNetAPIBufferFree _
    Lib "netapi32.dll" Alias "NetApiBufferFree" _
    (ByVal buffer As Long) _
    As Long
 
' Retrieves the length of the specified wide string.
Private Declare Function apilstrlenW _
    Lib "Kernel32" Alias "lstrlenW" _
    (ByVal lpString As Long) _
    As Long
 
Private Declare Function apiNetUserGetInfo _
    Lib "netapi32.dll" Alias "NetUserGetInfo" _
    (servername As Any, _
    username As Any, _
    ByVal Level As Long, _
    bufptr As Long) As Long
 
' moves memory either forward or backward, aligned or unaligned,
' in 4-byte blocks, followed by any remaining bytes
Private Declare Sub sapiCopyMem _
    Lib "Kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, _
    Source As Any, _
    ByVal Length As Long)
 
Private Declare Function apiGetUserName Lib _
    "advapi32.dll" Alias "GetUserNameA" _
    (ByVal lpBuffer As String, _
    nSize As Long) _
    As Long
 
Private Const MAXCOMMENTSZ = 256
Private Const NERR_SUCCESS = 0
Private Const ERROR_MORE_DATA = 234&
Private Const MAX_CHUNK = 25
Private Const ERROR_SUCCESS = 0&


'******** Code Start ********
'This code was originally written by Dev Ashish.
'It is not to be altered or distributed,
'except as part of an application.
'You are free to use it in any application,
'provided the copyright notice is left unchanged.
'
'Code Courtesy of
'Dev Ashish
'
 
Function fGetFullNameOfLoggedUser(Optional strUserName As String) As String
'
' Returns the full name for a given UserID
'   NT/2000 only
' Omitting the strUserName argument will try and
' retrieve the full name for the currently logged on user
'
On Error GoTo ErrHandler
Dim pBuf As Long
Dim dwRec As Long
Dim pTmp As USER_INFO_2
Dim abytPDCName() As Byte
Dim abytUserName() As Byte
Dim lngRet As Long
Dim I As Long
 
    ' Unicode
    abytPDCName = fGetDCName() & vbNullChar
    If (Len(strUserName) = 0) Then strUserName = fGetUserName()
    abytUserName = strUserName & vbNullChar
 
    ' Level 2
    lngRet = apiNetUserGetInfo( _
                            abytPDCName(0), _
                            abytUserName(0), _
                            2, _
                            pBuf)
    If (lngRet = ERROR_SUCCESS) Then
        Call sapiCopyMem(pTmp, ByVal pBuf, Len(pTmp))
        fGetFullNameOfLoggedUser = fStrFromPtrW(pTmp.usri2_full_name)
    End If
 
    Call apiNetAPIBufferFree(pBuf)
ExitHere:
    Exit Function
ErrHandler:
    fGetFullNameOfLoggedUser = vbNullString
    Resume ExitHere
End Function
 
Private Function fGetUserName() As String
' Returns the network login name
Dim lngLen As Long, lngRet As Long
Dim strUserName As String
    strUserName = String$(254, 0)
    lngLen = 255
    lngRet = apiGetUserName(strUserName, lngLen)
    If lngRet Then
        fGetUserName = Left$(strUserName, lngLen - 1)
    End If
End Function
 
Function fGetDCName() As String
Dim pTmp As Long
Dim lngRet As Long
Dim abytBuf() As Byte
 
    lngRet = apiNetGetDCName(0, 0, pTmp)
    If lngRet = NERR_SUCCESS Then
        fGetDCName = fStrFromPtrW(pTmp)
    End If
    Call apiNetAPIBufferFree(pTmp)
End Function
 
Private Function fStrFromPtrW(pBuf As Long) As String
Dim lngLen As Long
Dim abytBuf() As Byte
 
    ' Get the length of the string at the memory location
    lngLen = apilstrlenW(pBuf) * 2
    ' if it's not a ZLS
    If lngLen Then
        ReDim abytBuf(lngLen)
        ' then copy the memory contents
        ' into a temp buffer
        Call sapiCopyMem( _
                abytBuf(0), _
                ByVal pBuf, _
                lngLen)
        ' return the buffer
        fStrFromPtrW = abytBuf
    End If
End Function


Function ReturnUserName() As String
' returns the NT Domain User Name
Dim rString As String * 255, sLen As Long, tString As String
    tString = ""
    On Error Resume Next
    sLen = GetUserName(rString, 255)
    sLen = InStr(1, rString, Chr(0))
    If sLen > 0 Then
        tString = Left(rString, sLen - 1)
    Else
        tString = rString
    End If
    On Error GoTo 0
    ReturnUserName = UCase(Trim(tString))
End Function

 
Function ReturnComputerName() As String
    Dim rString As String * 255, sLen As Long, tString As String
    tString = ""
    On Error Resume Next
    sLen = GetComputerName(rString, 255)
    sLen = InStr(1, rString, Chr(0))
    If sLen > 0 Then
        tString = Left(rString, sLen - 1)
    Else
        tString = rString
    End If
    On Error GoTo 0
    ReturnComputerName = UCase(Trim(tString))
End Function

Open in new window

0
 
LVL 75
ID: 35114511
I forget ... what Version of Access are you using ?

mx
0
 

Author Comment

by:epuglise
ID: 35131411
2007
0
 
LVL 75

Accepted Solution

by:
DatabaseMX (Joe Anderson - Access MVP) earned 350 total points
ID: 35131591
1) Since User Level Security (ULS) is no longer supported in A2007 and beyond, you pretty much have to roll your own security in that context.  You can determine the Windows logged in user ( see this code -  http://www.mvps.org/access/api/api0008.htm ) and then set Form properties accordingly.

2) See attached image

3) OK ... then implement the Shift Key Bypass code if  necessary to be sure (do you need this code?)

4) OK

You  can add a password to your VBA code - see screen shot 2 ... OR ... create an ACCDE which will prevent any design changes in code, forms and reports.

This should get you started ...

mx
Capture1.gif
Capture1.gif
0
 
LVL 75
ID: 35131667
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
0
 

Author Comment

by:epuglise
ID: 35131706
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.
0
 
LVL 26

Expert Comment

by:Nick67
ID: 35131781
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.
0
 
LVL 75
ID: 35131818
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
0
 
LVL 26

Expert Comment

by:Nick67
ID: 35131948
@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
0
 
LVL 75
ID: 35131990
0
 
LVL 26

Expert Comment

by:Nick67
ID: 35132131
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.
0
 
LVL 75
ID: 35132180
"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
0
 
LVL 26

Expert Comment

by:Nick67
ID: 35132271
@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!
0
 
LVL 75
ID: 35132299
"fOSUserName ... not so much."
What do you mean ?

mx
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 26

Expert Comment

by:Nick67
ID: 35132786
LOL

"What was the name of that function that returned the username?  Oh yeah--ReturnUserName!"

LOL
0
 
LVL 75
ID: 35133020
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
0
 
LVL 26

Expert Comment

by:Nick67
ID: 35133466
:)
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.
0
 
LVL 75
ID: 35133504
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
0
 
LVL 26

Expert Comment

by:Nick67
ID: 35133611
@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
http://www.experts-exchange.com/Microsoft/Development/MS_Access/Q_26878741.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
0
 

Author Comment

by:epuglise
ID: 35139207
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 :(

0
 
LVL 26

Assisted Solution

by:Nick67
Nick67 earned 150 total points
ID: 35139305
API code'll do that for you :)
Now, I built a custom toolbar that shows only the items that I think the end-user needs.  I then turn off the regular toolbars and turn on the custom one, based on logon name.

Here's more code to hurt your head -- but not as badly 'cause it's just nicely commented VBA

Call ToolbarsOff to turn them off
Call ResetToolbars to turn them back on
Option Compare Database
Option Explicit

Public Function ToolbarsOff()
'On Error GoTo Err_ToolbarsOff

' Turns off the Database toolbar.
DoCmd.ShowToolbar "Database", acToolbarNo
' Turns off the Relationship toolbar.
DoCmd.ShowToolbar "Relationship", acToolbarNo
' Turns off the Table Design toolbar.
DoCmd.ShowToolbar "Table Design", acToolbarNo
' Turns off the Table Datasheet toolbar.
DoCmd.ShowToolbar "Table Datasheet", acToolbarNo
' Turns off the Query Design toolbar.
DoCmd.ShowToolbar "Query Design", acToolbarNo
' Turns off the Query Datasheet toolbar.
DoCmd.ShowToolbar "Query Datasheet", acToolbarNo
' Turns off the Form Design toolbar.
DoCmd.ShowToolbar "Form Design", acToolbarNo
' Turns off the Form View toolbar.
DoCmd.ShowToolbar "Form View", acToolbarNo
' Turns off the Filter/Sort toolbar.
DoCmd.ShowToolbar "Filter/Sort", acToolbarNo
' Turns off the Report Design toolbar.
DoCmd.ShowToolbar "Report Design", acToolbarNo
' Turns off the Print Preview toolbar.
DoCmd.ShowToolbar "Print Preview", acToolbarNo
' Turns off the Toolbox toolbar.
DoCmd.ShowToolbar "Toolbox", acToolbarNo
' Turns off the Formatting (Form/Report) toolbar.
DoCmd.ShowToolbar "Formatting (Form/Report)", acToolbarNo
' Turns off the Formatting (Datasheet) toolbar.
DoCmd.ShowToolbar "Formatting (Datasheet)", acToolbarNo
' Turns off the Macro Design toolbar.
DoCmd.ShowToolbar "Macro Design", acToolbarNo
' Turns off the Utility1 toolbar.
DoCmd.ShowToolbar "Utility 1", acToolbarNo
' Turns off the Utility2 toolbar.
DoCmd.ShowToolbar "Utility 2", acToolbarNo
' Turns off the Web toolbar.
DoCmd.ShowToolbar "Web", acToolbarNo
' Turns off the Source Code Control toolbar.
DoCmd.ShowToolbar "Source Code Control", acToolbarNo

Exit_ToolbarsOff:
Exit Function

Err_ToolbarsOff:
MsgBox Err.Number & " " & Err.Description
Resume Exit_ToolbarsOff
End Function

Public Function ResetToolbars()
'On Error GoTo Err_ResetToolbars


' Turns on the Database toolbar.
DoCmd.ShowToolbar "Database", acToolbarWhereApprop
' Turns on the Relationship toolbar.
DoCmd.ShowToolbar "Relationship", acToolbarWhereApprop
' Turns on the Table Design toolbar.
DoCmd.ShowToolbar "Table Design", acToolbarWhereApprop
' Turns on the Table Datasheet toolbar.
DoCmd.ShowToolbar "Table Datasheet", acToolbarWhereApprop
' Turns on the Query Design toolbar.
DoCmd.ShowToolbar "Query Design", acToolbarWhereApprop
' Turns on the Query Datasheet toolbar.
DoCmd.ShowToolbar "Query Datasheet", acToolbarWhereApprop
' Turns on the Form Design toolbar.
DoCmd.ShowToolbar "Form Design", acToolbarWhereApprop
' Turns on the Form View toolbar.
DoCmd.ShowToolbar "Form View", acToolbarWhereApprop
' Turns on the Filter/Sort toolbar.
DoCmd.ShowToolbar "Filter/Sort", acToolbarWhereApprop
' Turns on the Report Design toolbar.
DoCmd.ShowToolbar "Report Design", acToolbarWhereApprop
' Turns on the Print Preview toolbar.
DoCmd.ShowToolbar "Print Preview", acToolbarWhereApprop
' Turns on the Toolbox toolbar.
DoCmd.ShowToolbar "Toolbox", acToolbarWhereApprop
' Turns on the Formatting (Form/Report) toolbar.
DoCmd.ShowToolbar "Formatting (Form/Report)", acToolbarWhereApprop
' Turns on the Formatting (Datasheet) toolbar.
DoCmd.ShowToolbar "Formatting (Datasheet)", acToolbarWhereApprop
' Turns on the Macro Design toolbar.
DoCmd.ShowToolbar "Macro Design", acToolbarWhereApprop
'Turns on the Utility1 toolbar.
DoCmd.ShowToolbar "Utility 1", acToolbarWhereApprop
'Turns on the Utility2 toolbar.
DoCmd.ShowToolbar "Utility 2", acToolbarWhereApprop
'Turns on the Web toolbar.
DoCmd.ShowToolbar "Web", acToolbarWhereApprop
'Turns on the Source Code Control toolbar.
DoCmd.ShowToolbar "Source Code Control", acToolbarWhereApprop

Exit_ResetToolbars:
Exit Function

Err_ResetToolbars:
MsgBox Err.Number & " " & Err.Description
Resume Exit_ResetToolbars
End Function

Open in new window

0
 

Author Comment

by:epuglise
ID: 35139308
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.
0
 

Author Comment

by:epuglise
ID: 35139313
(PS if that is a different question let me know and I'll open a separate question)
0
 

Author Comment

by:epuglise
ID: 35139376
@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?
0
 
LVL 26

Assisted Solution

by:Nick67
Nick67 earned 150 total points
ID: 35139505
No, I created a custom toolbar, which is separate from the standard ones.  It is then the only one left on for the end-users.  Nicely enough, I have a button on it that calls ResetToolbars -- so if they need them all turned on, they can be.

The Ribbon is a different monster -- and would probably need to be a new question.

As for globals -- IF -- IF you split your database to a front-end and back-end, and you push out the front-end to each individual workstation, so everyone is using their own copy of the front-end -- then globals are wonderful.

Otherwise, Danger Will Robinson!

Using the ReturnUserName and a Select Case structure, I give all my users a UserClass from 1 to 5 in the Switchboard On_Open event.  I then store that in an invisible, unbound textbox on the Switchboard.  Everything else then references that control when it comes to user customization
0
 
LVL 75

Assisted Solution

by:DatabaseMX (Joe Anderson - Access MVP)
DatabaseMX (Joe Anderson - Access MVP) earned 350 total points
ID: 35139878
"and I think I do need the shift bypass code you reference."

The link below contains an MDB which allows you to 'set' and 'reset' the Shift Key Bypass from a REMOTE mdb.  
It's very cool. Scroll down the page to 'By Pass Shift Key Code'

http://www.members.shaw.ca/AlbertKallal/msaccess/msaccess.html

" I'm scared to death of globals because"
Starting in A2007, you not have TempVars ... look it up in VBA Help.  Basically globals that do not get trashed when crashes/errors occur.  Also, you can store info in small local tables - I'm definitely a table driven guy.

The best Ribbon site - for info and a GREAT tool is:

http://www.accessribbon.de/en/

mx
0
 

Author Closing Comment

by:epuglise
ID: 35141876
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.
0
 

Author Comment

by:epuglise
ID: 35142025
PS @dbmx:  i've seen other references to locking a db remotely, but the www.members.shaw link isn't working.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In the article entitled Working with Objects – Part 1 (http://www.experts-exchange.com/Microsoft/Development/MS_Access/A_4942-Working-with-Objects-Part-1.html), you learned the basics of working with objects, properties, methods, and events. In Work…
I originally created this report in Crystal Reports 2008 where there is an option to underlay sections. I initially came across the problem in Access Reports where I was unable to run my border lines down through the entire page as I was using the P…
Familiarize people with the process of utilizing SQL Server stored procedures from within Microsoft Access. Microsoft Access is a very powerful client/server development tool. One of the SQL Server objects that you can interact with from within Micr…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now