Problem 1
You would have to put some code in the Form_Load event to test the user and disable (or even make invisible) the buttons you don't want to use. Properties are .Enabled and .Visible, True/False. You can look them up in the Help Files. I would advise that you not allow them to be tab stops, which you can do permanently from the properties sheet, Other tab. That one probably does not need to be dynamic (though it could be).
Problem 2
You probably want to make a query by-owner and then make the table have no access to folks not in the admins group. Look up the topic of "By Owner" and also do a search in this forum for that phrase. If you own the query, then others can open it as a recordset even if they don't have access to the underlying table.
Problem 3
If you have a startup form, you have most of this problem licked already. Here is what is left to do.
1. Build your "audit" table with date & time, username, event text, and anything else you are going to keep. This will be your action history table, or whatever you want to call it.
2. Make the startup form's Form_Load routine open the audit table as a recordset, do an .AddNew, load values to the recordset fields, and do a .Update This entry becomes your "user logged in" event.
3. Don't allow the startup form to exit. Disable all of its "automatic" controls that Windows defines (like the X box in the upper right corner, etc.) Instead, create a button that says "Close This Startup Form." But when someone clicks the form, don't close it. Just minimize it and make it invisible. It will stay in the background, invisible and inactive, but still there.
4. Now put code in the Form_Close that updates your audit table. The event logged here would be your "User Logout" event because the form will now only close when the database is closed.
5. The tricky part is to put audit update code in each form through which someone can do something to a record. Probably in each form's AfterUpdate routine.
This part is tedious, but if you make the audit writer a fully enclosed subroutine that does the recordset open, addnew, data definition, update, and close, then all you really need to do is to provide the event text for each event you are recording. And if you REALLY wanted to be kinky, then you could scan each control on the form that has a .OldValue to compare it to .Value, then make entries in your table based on differences found. The latter is a "For Each ctlControl in frmForm".... and you have to make sure that the form is of a type (.Type) that has an intrinsic value in the first place. Not all controls do.
Anyway, the point of this is that if you are using your own security or Workgroup security, in either case you will have a username to include as the "Who" part. So you won't need to ask that, it should still be available from login.
The current date and time is easy, use Now() function to get it. So you don't have to work for that one, either.
It is up to you as to what text you pass into the event message that will be logged. You could do like I did and have two parts to this message, an object name and an event message.
Just a note: It is probably ok to make the date&time field a key but if you log more than one event as a result of a single user action, don't make the date&time key unique. It won't be, so it is not a candidate for Prime Key. Make it "Indexed: Yes(duplicates OK)."
You COULD make the primary key the combination of date&time plus the name of the object you are updating, including the table name AND field name. Just the table name plus date and time won't be unique, either. I've already tried that. Didn't work. (Duplicate time/date & table name.)
[This message has been edited by The_Doc_Man (edited 05-21-2002).]