I'm new to SAP scripting. Someone told me it is possible to automatize my work with VBA, so I looked into it. I looked on the internet how to connect, it works fine. I use the recorder to know what code to write. Everything works very well until the last line of this code:
session.findById("wnd[0]/usr/ctxtCAUFVD-AUFNR").Text = "000000000" 'write service order number
session.findById("wnd[0]").sendVKey 0 'Confirm (enter)
session.findById("wnd[0]/mbar/menu[0]/menu[9]/menu[2]/menu[4]").Select 'execute a function to close the order
session.findById("wnd[1]/usr/btnSPOP-OPTION1").press 'A popup appears (always) with "No" in autoselect. I want to click on "Yes"
.findById("wnd[1]") should allow me to use the confirmation popup window, but it always returns Error 619, Control not found. I have no idea why, since this line was written by the recorder. I explored for many hours the Internet and I can't find the answer.
Thank you in advance for your help.
Of course, I needed to ask to have the resolution idea...
The was I set up my connection was that session was actually the SAP session .ActiveWindow(), therefore only wnd[0]. It couldn't find wnd[1]. I execute the findById() from the SAP session and it works.
If Not IsObject(SAPGuiApp) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set SAPGuiApp = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = SAPGuiApp.Children(0)
End If
If Not IsObject(SAP_session) Then
Set SAP_session = Connection.Children(0)
End If
Set session = SAP_session.ActiveWindow()
session.findById("wnd[1]") 'Bad. session is only wnd[0]
SAP_session.findById("wnd[1]") 'Good it can find wnd[0] and wnd[1]
I have a button on my MS Access form that uses VBA to update the modified date/time stamp on all records on a datasheet style form that have a checkbox checked in a field called "Confirm Existing Update". After it makes these updates, it is supposed to clear all of the check boxes. This is currently accomplished via a simple SQL update query that executes via VBA once the date/timestamps have been updated:
"Update [CMO Deviations Tracker] SET [CMO Deviations Tracker].[Confirm Existing Update] = FALSE WHERE [CMO Deviations Tracker].[Confirm Existing Update] = TRUE"
The problem is that the query doesn't seem to want to clear the last checkbox checked (in the last row that was interacted with). I've tested the query by copy/pasting it into a blank query design window and it works perfectly there (clears all check boxes, including the final one clicked). So far, I've attempted to add the following to my form button's VBA code:
Shifting the record to the next line before running the Update query via "Me.Recordset.MoveNext"
Saving the last record interacted with via "If Me.Dirty Then Me.Dirty = False"
I added "Forms![CMO Deviations Tracker].Requery" to the end of the code to ensure that I was seeing the latest info
None of these seem to result in the clearing of the last checkbox checked. What could be causing this?
EDIT: I just tried running my separate Update query while the form was open immediately after trying and failing with the button. It failed to remove the last checkbox due to a "lock violation". Interesting...
EDIT2: So the only thing that I've found to work (as a manual workaround) is to check the boxes for all of the rows that I want to update the timestamp for, and then check and uncheck the box for one additional row before clicking the button. Access will then clear all of the desired check boxes like it's supposed to.
EDIT3: Just a point of clarity. The updating of the timestamp on the last record checked appears to work perfectly. It seems like, for whatever reason, it's only the "Confirm Existing Update" checkbox field that is getting locked. Thinking that it could be the method being used, I attempted to clear these checkboxes by editing the Recordset and using a loop to make the "Confirm Existing Update" field for each of the rows in the Recordset equal to "False". It still seems to clear all check boxes except the last one, only this time, the vba code will error out on the final line by saying "Could not update | currently locked". Same error, completely different implementation.
EDIT4: Updating the "Record Locking" property of the form to either "Edited Record" or "No Locks" seems to fix the issue, but only if done as part of the button click code. If I put VBA to update this property in the "On Open" event trigger of the form, or simply update the property in the GUI, it doesn't seem to fix the issue - even with "No Locks" set as the default property. What the heck?
EDIT5: Per request, the following is the VBA from my button. Please note that I've updated the methodology to update the check boxes using a DAO.Recordset, rather than the original SQL Update query.
Private Sub Command187_Click()
Dim Temp_ID As String
Dim DBS_Temp1 As DAO.Database
Dim DevTracker As DAO.Recordset
Dim DevUpdates As DAO.Recordset
If MsgBox("This will confirm that the latest update provided is still current for all items with the 'Confirm Existing Update' box checked above. Are you sure that you want to do this?", vbYesNo) = vbYes Then
Set DBS_Temp1 = CurrentDb
Set DevTracker = DBS_Temp1.OpenRecordset("CMO Deviations Tracker")
Set DevUpdates = DBS_Temp1.OpenRecordset("Deviation Updates")
DevTracker.MoveFirst
DevUpdates.MoveFirst
Do Until DevTracker.EOF = True
If DevTracker![Confirm Existing Update] = True Then
DevUpdates.MoveFirst
Temp_ID = "[Deviation ID] = '" & DevTracker![Deviation ID] & "'"
DevUpdates.FindLast (Temp_ID)
DevUpdates.Edit
DevUpdates![Status Update] = DevUpdates![Status Update] & " "
DevUpdates![Status Update] = Left(DevUpdates![Status Update], Len(DevUpdates![Status Update]) - 1)
DevUpdates.Update
DevTracker.Edit
DevTracker![Confirm Existing Update] = False
DevTracker.Update
End If
DevTracker.MoveNext
Loop
DevUpdates.Close
DevTracker.Close
Set DevUpdates = Nothing
Set DevTracker = Nothing
Set DBS_Temp1 = Nothing
MsgBox "Existing updates for the selected deviations have been confirmed."
Else
DevTracker.MoveFirst
Do Until DevTracker.EOF = True
DevTracker.Edit
DevTracker![Confirm Existing Update] = False
DevTracker.Update
DevTracker.MoveNext
Loop
MsgBox "Update Confirmation Cancelled."
Forms![CMO Deviations Tracker].Requery
Exit Sub
End If
Forms![CMO Deviations Tracker].Requery
End Sub
While running a form that runs multiple queries that connect to an ODBC Database I get the SQL Server Login Dialog box. I can click OK to login since I am able to use a trusted connection.
Since this query is automatically run through a VBA macro that loops through multiple queries multiple times, the dialog box appears quite often. I would just click OK every time it pops up but in this case it takes a very long time to run.
Is there a way to prevent this dialog box from even showing up?
VBA Code:
Private Sub Run_All_Months_Click()
Dim db As DAO.Database
Dim rst As Recordset
Set db = CurrentDb()
Set rst = db.OpenRecordset("MDate query")
With rst
.MoveFirst
[BOP Date].Value = rst("Monthly Dates").Value
.MoveNext
[Reporting Date].Value = rst("Monthly Dates").Value
DoCmd.RunMacro ("Monthly Report Macro")
Do
[BOP Date].Value = rst("Monthly Dates").Value
.MoveNext
If (Not .EOF) Then
[Reporting Date].Value = rst("Monthly Dates").Value
DoCmd.RunMacro ("Monthly Report Macro")
End If
Loop Until .EOF
End With
db.Close
End Sub
I was able to figure out the problem. I had to relink all of the tables from the OBDC by right clicking on one of them which brought up an option to relink. The VBA code was working correctly
I have a table that has usernames, passwords, and a yes/no column for isadmin.
How do I make it so if they login with an account that has a check mark under "isadmin" they get access to design view, the ribbon, etc? Though if they log in with an account that doesn't have a check mark under the isadmin box they only can view the forms, not edit them, and the ribbon is inaccessible?
I just don't know where to start, as I had assumed there was a way to save the database as a seperate copy that only users can view forms in, and if the admin runs his copy he gets all the changes to the tables (via the forms) the users made. So when the admin edits a form, and saves it it doesn't remove all the user's data as when it was saved, it was saved to the admin's copy too. I'm really confused.
I am using Access 2013
This is a simple solution for user level security being removed in newer releases of Access; using a lot of VBA.
STEP 1: Creating The Table
First, create a table. I will name mine LogininfoT. Now, for the columns inside of the table, name them EmployeeID, LoginID, LoginPassword, EmployeeName, and lastly IsAdmin. Make EmployeeID your key, and IsAdmin a YES/NO field.
For testing, add two users to this table. With this information:
EmployeeID LoginID LoginPassword EmployeeName IsAdmin
1 1111 1234 Bob [x]
2 2222 1234 Stewert [ ]
STEP 2: Creating The Forms
Now that we have the table made, let's design the form to use this set of data.
I will name my form LoginF. Go into design view, and slap down a text box, a combo box, and a button. For the combo box rename the text to say something like Login ID (you can change this to whatever fits your need) and for the text box, put the text as Password (once again, change this to whatever you want it doesn't effect the outcome). The text in the button can be whatever you want, I will be putting Login on it.
Click the combo box and rename it. I will be naming it LoginCmBx. Next, click the text box and rename it, I will be naming it PasswordTxt. Lastly, click the button and rename it, I will be naming it LoginBtn.
Click the combo box again and under the event tab, go into the After Update scripting. Use code and type this in:
Private Sub LoginCmBx_AfterUpdate()
Me.PasswordTxt.SetFocus
End Sub
This makes it so after you select a username, it automatically puts the focus onto the password text box so you can start typing right away without using TAB on your keyboard, or using your mouse.
Next, go to the button and under the event tab, go into the On Click scripting. Use code and type this in:
Private Sub LoginBtn_Click()
If IsNull(Me.LoginCmBx) Or Me.LoginCmBx = "" Then
MsgBox "You must enter a User Name.", vbOKOnly, "Required Data"
Me.LoginCmBx.SetFocus
Exit Sub
End If
If IsNull(Me.PasswordTxt) Or Me.PasswordTxt = "" Then
MsgBox "You must enter a Password.", vbOKOnly, "Required Data"
Me.PasswordTxt.SetFocus
Exit Sub
End If
If Me.PasswordTxt.Value = DLookup("LoginPassword", "LoginInfoT", _
"[EmployeeID]=" & Me.LoginCmBx.Value) Then
EmployeeID = Me.LoginCmBx.Value
On Error Resume Next
DoCmd.DeleteObject acQuery, "IsAdminQ"
On Error GoTo Err_LoginBtn_Click
Dim qdef As DAO.QueryDef
Set qdef = CurrentDb.CreateQueryDef("IsAdminQ", _
"SELECT IsAdmin " & _
"FROM LoginInfoT " & _
"WHERE EmployeeID = " & LoginCmBx.Value)
Exit_LoginBtn_Click:
DoCmd.Close acForm, "LoginF", acSaveNo
DoCmd.OpenForm "MenuF"
Exit Sub
Err_LoginBtn_Click:
MsgBox Err.Description
Resume Exit_LoginBtn_Click
Else
MsgBox "Password Invalid. Please Try Again", vbOKOnly, _
"Invalid Entry!"
Me.PasswordTxt.SetFocus
End If
End Sub
What this does is check if you selected a username, if not it spits out an error telling the user to select one. If you did, it checks if you entered a password. If they didn't, it spits out another error saying they didn't enter a password. If they selected both, and the password doesn't match the one in the table for the username you selected it spits out an error saying you got the password wrong. If you got the password right to the username you selected, it logs you in. It will then close the current form you are on, and open up a new one named "MenuF" it will also create a query with that little bit of information under the username you selected, either if it's an admin or not.. We haven't created MenuF yet, so lets quickly do that. We aren't done with LoginF just quite yet though, so be prepared to come back to that later!
Create the form, and put down a button. Here is your menu form, you can create as many buttons as you want going to other forms or even just put a subform on here and have your entire database. Taht button you put down, you can name the text to whatever you want. I put mine as Log out. Name the button MenuLogOutBtn. Go into the event tab, and under the On Click scripting click code and type this in:
Private Sub MenuLogOutBtn_Click()
DoCmd.DeleteObject acQuery, "IsAdminQ"
DoCmd.OpenForm "LoginF"
DoCmd.Close acForm, "MenuF", acSaveNo
End Sub
What this does is delete the query the login button created, opens the login form again, and closes the menu. Simple!
Now I need you to throw down a checkbox, and name it MyCheckbox. This box requires no special coding, or control sources. Though I do suggest changing visible as no, and deleting the text that comes along with it.
Now, go to the form's event properties and under the Open scripting go to code and type this in:
Private Sub Form_Open(Cancel As Integer)
Me.MyCheckbox.Value = GetLoginStateIsAdmin()
If GetLoginStateIsAdmin = True Then
Me.ShortcutMenu = True
DoCmd.ShowToolbar "Ribbon", acToolbarYes
DoCmd.ShowToolbar "Menu Bar", acToolbarYes
Application.SetOption "ShowWindowsinTaskbar", True
DoCmd.SelectObject acTable, , True
Else
Me.ShortcutMenu = False
DoCmd.ShowToolbar "Ribbon", acToolbarNo
DoCmd.ShowToolbar "Menu Bar", acToolbarNo
Application.SetOption "ShowWindowsinTaskbar", False
DoCmd.NavigateTo "acNavigationCategoryObjectType"
DoCmd.RunCommand acCmdWindowHide
End If
End Sub
What this does is checkbox's information which is attached to query's IsAdmin column and give GetLoginStateIsAdmin that boolean variable. After it does that, it starts a simple If statement that turns off menu bars and disabled right click if you aren't an admin; if you are, it allows you do right click and all menu bars are visible.
Though if you didn't notice yet, our checkbox doesn't get the information from the query yet! Oh no!
STEP 3: Creating The Public Modules
If you were on your toes, you would notice even the login code wouldn't work at this point. First, we need some public modules. Go to the Create tab in the ribbon, and create a module. Type this in:
Public EmployeeID As Long
Save this module as LoginModule.
Create another module, and type this in:
Function GetLoginStateIsAdmin()
'
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("IsAdminQ")
GetLoginStateIsAdmin = Nz(rst(0), False)
Set rst = Nothing
'
End Function
Save this one as GetAdmin.
Lets create one more module; so the user opening the database can't by bass stuff by using the shift key to launch it.
Type this in it:
Function ap_DisableShift()
'This function disable the shift at startup. This action causes
'the Autoexec macro and Startup properties to always be executed.
On Error GoTo errDisableShift
Dim db As DAO.Database
Dim prop As DAO.Property
Const conPropNotFound = 3270
Set db = CurrentDb()
'This next line disables the shift key on startup.
db.Properties("AllowByPassKey") = False
'The function is successful.
Exit Function
errDisableShift:
'The first part of this error routine creates the "AllowByPassKey
'property if it does not exist.
If Err = conPropNotFound Then
Set prop = db.CreateProperty("AllowByPassKey", _
dbBoolean, False)
db.Properties.Append prop
Resume Next
Else
MsgBox "Function 'ap_DisableShift' did not complete successfully."
Exit Function
End If
End Function
Save that as ShiftModule.
We are done the modules! Lets go back to the LoginF now.
STEP 4: Finishing Up LoginF
Go to the form's event tab, and click the on load scripting. Click code, then type this in:
Private Sub Form_Load()
On Error Resume Next
DoCmd.DeleteObject acQuery, "CustomerMoreInfoQ"
End Sub
What this does is make sure that the query the login button creates is deleted when this form starts up, just in case the user closes the database without logging out. So if you click login, it won't cause errors because the query isn't still there.
STEP 5: Testing It Out.
Run the form LoginF in form view, and select Bob as the username. Type in the password 1234 into the password text box, and click login. It should open up the MenuF and you see all menus and you can right click. Good. Now, log out and login with Stewert, using the same password. Now you see all the menus remove themselves, and you can't right click! Yay!
For extra security, in the LoginF's Other tab, make sure Shortcut Menu is set to No. This will set right click to be disabled always; as you aren't logged in as a user at this point. It doesn't know if you are an admin or not.
STEP 6: Disabling The Toolbars On Start Up & launching LoginF On Start Up.
Go to File > Options > Current Database.
Under Display Form, select FormF.
Under the Navigation section, unclick Display Navigation Pane.
Click okay, then go back to LoginF; go into the On Load code and add this just before the End Sub:
DoCmd.ShowToolbar "Ribbon", acToolbarNo
You are done! Save your database, then close it and open it again. It should load the LoginF form where you can't right click, there are no menus etc. The only way to get the menus to edit things is to log into an admin account!
Step 7: Expanding
This doesn't automatically expand the more you add forms though. You need to add that checkbox named MyCheckbox (I suggest copy + pasting it) to each form you add, and add this code to each form you add:
Private Sub Form_Open(Cancel As Integer)
Me.MyCheckbox.Value = GetLoginStateIsAdmin()
If GetLoginStateIsAdmin = True Then
Me.ShortcutMenu = True
Else
Me.ShortcutMenu = False
End If
End Sub
Though once you do that to every form, the security works and you need to log in to an admin account to change anything. If you are just a user, you can use the form normally (click buttons, edit data on subforms, etc) You can't edit the form it self though.
I am trying to open another db using VBA from my current db then close the one I am in. When I use the code listed here it opens Access but closes it immediately. I am sure it is simply something I am overlooking but the past hour I have wracked my brain. Any help would be greatly appreciated.
Private Sub Command115_Click()
Dim objAccess As Access.Application
Const conPATH = "C:\Users\user\Desktop\Database1.accdb"
'Create an instance of the Access application object.
Set objAccess = CreateObject("Access.Application")
'Open the database
objAccess.Visible = True
objAccess.OpenCurrentDatabase conPATH
'Open the form.
objAccess.DoCmd.OpenForm "Main-Form"
' Maximize other Access window
objAccess.DoCmd.RunCommand acCmdAppMaximize
End Sub
Thanks in advance for any help in this matter
If you use the shell then when you close your first database, the second will remain open.
Sub test()
Dim sh As Variant
sh = Shell("""C:\...\MSACCESS.EXE"" ""C:\...\FileName.accdb""")
End Sub
My guess the reason your code didn't work is because, the second access you start is an object that exists within the first one. The moment the first one closes and cleanup starts for its objects/variables. It closes the second one.
Say your first app is access1 and it is trying to open access2 and then close access1 app and makes access2 as active app. One thing you could do is,
Once your access1 app loads try to open access2 app programatically and make it visible and then use Application.closeCurrentdatabase to close access1 database and then in the unload event of access1 apps form (if there is any form in access1 app) call Application.Quit.
This works.