![]() |
MS Access FAQ - Modules |
![]() |
![]() |
How can I open a form or report in code and make the code wait until that form or report has been closed.. | ![]() |
![]() |
The simple answer for forms is to open the form as a modal dialog box, like this: DoCmd OpenForm "frmFormName", , , , , A_DIALOG Note the commas, the A_DIALOG parameter is the fifth parameter. Of course, this will not work for reports in preview mode, and may not be the desired result for a particular form, some polling will be called for, e.g.
DoCmd OpenForm "frmFormName"
Do While IsFormLoaded("frmFormName")
DoEvents
Loop
DoCmd OpenReport "rptReportName"
Do While IsReportLoaded("rptReportName")
DoEvents
Loop
Then in a global module, the following functions will test if a particular form or report is loaded: Function IsFormLoaded(pstrFormName As String) As Integer IsFormLoaded = SysCmd(SYSCMD_GETOBJECTSTATE, A_FORM, pstrFormName) End Function Function IsReportLoaded(pstrReportName As String) As Integer IsReportLoaded = SysCmd(SYSCMD_GETOBJECTSTATE, A_REPORT, pstrReportName) End Function Updated: 04/11/1996 - Trevor Best | ![]() |
![]() |
Where can I obtain a list of Access Basic Errors and their associated messages | ![]() |
![]() |
All Versions: From Access itself, simply write a function that loops around each error number, e.g.For e = 1 to 9000 Debug.Print e; " - "; Error(e) Next Bear in mind a lot of these are "User Defined Error" or "Reserved Error", you may want to filter these out with an "If" or "Select Case" structure in your function, alternatively you can write each number & message to a text file or Access table. Updated: 21/12/1997 - Trevor Best | ![]() |
![]() |
How do I access the recordset of a SUBform. I know how to clone the set of a form, but this doesn't work for subforms. | ![]() |
![]() |
All Versions: Let me guess, you tried: forms!myform!MySubForm.RecordsetClone This will always fail as MySubForm points to a control on the form, you need to access it's Form propery, thus: forms!myform!MySubForm.Form.RecordsetClone Should work OK. Updated: 21/12/1997 - Trevor Best | ![]() |
![]() |
How do I emulate the "Record X of Y" that Access displays in the navigation buttons | ![]() |
![]() |
Access 2.0: The following function will do this for a form, just send any string and the form object as the parameters, e.g. in a ControlSource use =RecordNumber("Item",[Form]) For code, use: strVariable = RecordNumber("Item",Me) or strVariable = RecordNumber("Item",Forms!MyForm) This will return something like "Item 4 of 899", if the form is on a new record it will return the string "New Record".
------- begin cut here -----------
Function RecordNumber (pstrPreFix As String, pfrm As Form) As String
On Error GoTo RecordNumber_Err
Dim rst As Recordset
Dim lngNumRecords As Long
Dim lngCurrentRecord As Long
Dim strTmp As String
Set rst = pfrm.recordsetclone
rst.MoveLast
rst.bookmark = pfrm.bookmark
lngNumRecords = rst.recordcount
lngCurrentRecord = rst.absoluteposition + 1
strTmp = pstrPreFix & " " & lngCurrentRecord & " of " & lngNumRecords
RecordNumber_Exit:
On Error Resume Next
RecordNumber = strTmp
rst.Close
Set rst = Nothing
Exit Function
RecordNumber_Err:
Select Case Err
Case 3021
strTmp = "New Record"
Resume RecordNumber_Exit
Case Else
strTmp = "#" & Error
Resume RecordNumber_Exit
End Select
End Function
------- end cut here ----------- Access 97: Same but for the fact that the trap for new record doesn't work so it displays "Record 0 of xxx", I haven't investigated this yet but I would assume that checking for rst.AbsolutePosition returning -1 could prove fruitful, then again you might like the Record 0 approach. Updated: 21/12/1997 - Trevor Best | ![]() |
![]() |
How do I run an internal DOS command from within Access Basic, if I try x=Shell("copy file1 file2",1) I get a message "File not found". | ![]() |
![]() |
Dos internal commands are processed by the command processor shell so you should be calling this program and not trying to execute the internal command itself. The command processor is usually command.com but this can vary and so can it's location (indeed it can even reside outside of the dos search path) for this reason it's not a good idea to hard code it's location or name into an application as this may change if the application is moved to another pc. Use the Environ function to retrieve the %COMSPEC% environment variable as this always points to the current command processor shell. e.g. Dim hTask As Integer hTask = Shell(Environ("COMSPEC") & " /C COPY file1 file2", 1) Note: Some of the DOS internal commands are available in Access Basic (in the long form of the command), e.g. RmDir, ChDir, MkDir. The Dir command can be emulated using the Dir() function although this only returns files, not hidden/system files or directory names. Updated: 21/07/1996 - Trevor Best | ![]() |
![]() |
Now I know how to shell an internal command such as copy, I need to wait for it to finish before continuing, at present Access will carry on to the next statement, which needs to access the new file that's just been copied. | ![]() |
![]() |
Access 2.0: This is usual for a multitasking environment such as Windows, however as "Shell" is a function in Access Basic it returns the handle to the task (or module) that it just started so you can use this return value to see when it's finished, you'll need an API call for this.
(declarations)
Declare Function GetModuleUsage Lib "Kernel" (ByVal hModule As Integer) As Integer
(somewhere within a module)
Dim hModule as Integer
hModule = Shell("whatever.exe",1)
Do While GetModuleUsage(hModule)
DoEvents
Loop
DoCmd Echo True, "This message will only come up when whatever.exe has finished"
-------------- The DoEvents within the loop ensures that Access relinquishes processor time to the called program otherwise it could wait forever. Access 97: GetModuleUsage was revoked from the Win32 API as programs would run in their own address space. I haven't as yet found a suitable replacement for this. Perhaps some other propeller head can enlighten me? Updated: 22/12/1997 - Trevor Best | ![]() |
![]() |
How do I stop the message box warnings issued whenever I run an action query with DoCmd RunSQL or DoCmd OpenQuery or from a macro? | ![]() |
![]() |
In a macro, SetWarnings: Off In Code, "DoCmd SetWarnings False". It's worth noting that you should turn the warnings back on afterwards as this applies to just about everything, even saving a form in design mode so it won't let you abandon it if you wanted to. Another thing in Code, you can use the .Execute method on a QueryDef object or DataBase Object, this has the advantages of being able to run inside a transaction and so execute faster, "DoCmd" starts another session of Jet (the database engine in Access) so will execute outside of the current default workspace, therefore running independantly of any transactions and you can't rollback from them. Updated: 21/07/1996 - Trevor Best | ![]() |
![]() |
How do I play a (WAV) sound file? | ![]() |
![]() |
If your computer is equipped with a sound card or a speaker driver, you can play .WAV (waveforms). First, add the following declaration (all on one line) to the Declarations section: Access 2.0 Declare Function csvSndPlaySound Lib "MMSYSTEM.DLL" Alias _ "SndPlaySound" (ByVal FileName As String, ByVal How As _ Integer) As Integer Next, enter this funciton: Function csvPlayWave (ByVal FileName As String, ByVal How As _ Integer) As Integer csvPlayWave = csvSndPlaySound(Trim(FileName), How) End Function You can call this from a form or field event like so: =csvPlayWave("c:\windows\tada.wav", 1) Access 97 Declare Function PlaySound Lib "winmm.dll" Alias "PlaySoundA" _ (ByVal lpszName As String, ByVal hModule As Long, _ ByVal dwFlags As Long) As Long Function csvPlayWave (ByVal FileName As String, ByVal How As _ Integer) As Integer ' I have no idea what the hModule bit is, but zero ' works fine here. csvPlayWave = PlaySound(Trim(FileName),0, How) End Function Updated: 22/12/1997 - Chris St. Valentine | ![]() |
![]() |
How do I captitalise the first letter of each word (proper case) | ![]() |
![]() |
Function Proper (var As Variant) As Variant
' Purpose: Convert the case of var so that the first letter of each word capitalized.
Dim strV As String, intChar As Integer, i As Integer
Dim fWasSpace As Integer 'Flag: was previous char a space?
If IsNull(var) Then Exit Function
strV = var
fWasSpace = True 'Initialize to capitalize first letter.
For i = 1 To Len(strV)
intChar = Asc(Mid$(strV, i, 1))
Select Case intChar
Case 65 To 90 ' A to Z
If Not fWasSpace Then Mid$(strV, i, 1) = Chr$(intChar Or &H20)
Case 97 To 122 ' a to z
If fWasSpace Then Mid$(strV, i, 1) = Chr$(intChar And &HDF)
End Select
fWasSpace = (intChar = 32)
Next
Proper = strV
End Function
Updated: 04/11/1996 - Allen Browne | ![]() |
![]() |
Why are the Domain (DLookup(), DCount(), etc.) so slow | ![]() |
![]() |
I don't know to be honest, but download this file, unzip it and stick it in a module, replace 'DLookup' with 'tLookup', 'DCount' with 'tCount', etc. and Bob's yer uncle. I've not yet tested these in Access 97, they do work in 97 but I haven't tested them in terms of speed over 97's built in domain functions. I would however go as far to make the third argument option in 97 to be more in line with the domain functions, this wasn't possible in version 2.0 so you have to supply the third argument (the where clause without the word "where"), even if you just send a zero length string. Updated: 22/12/1997 - Trevor Best | ![]() |
![]() |
How do I get the Network User ID of the current user | ![]() |
![]() |
A simple API function will do for this, I've tested this on a Windows network but not yet on a Novell network. Access 2.0
Declare Function WNetGetUser Lib "user" (ByVal szUser As String, nBufferSize As Integer) As Integer
Function NetworkUserName () As String
Dim iStringLength As Integer
Dim sString As String * 255
iStringLength = Len(sString)
sString = String$(iStringLength, 0)
If WNetGetUser(sString, iStringLength) = 0 Then
NetworkUserName = Left$(sString, iStringLength)
Else
NetworkUserName = "Unknown"
End If
End Function
Access 97 See Below as the credit goes to a different author. Updated: 22/12/1997 - Steven Drinovsky | ![]() |
![]() |
How do I make a combo box drop down as soon as the user puts the cursor in there. | ![]() |
![]() |
Access 2.0 Use an On Enter event procedure like: Sub cboSupplier_OnEnter() Sendkeys "{F4}" ' or you can use Sendkeys "%{Down}" End Sub Beware when doing this OnEnter, as if the users first action on this combo before entering it is to click the down arrow with the mouse then your code will actually have the opposite effect as the F4 or Alt+Down is a toggle. Access 97 Combo Boxes have a .Dropdown method. Updated: 22/12/1997 - Trevor Best | ![]() |
![]() |
How Can I get the name of the control that the mouse pointer passes over, Screen.ActiveControl doesn't work as users have a habit of moving the mouse over other objects on the screen apart from the active one (the awkward so and so's :-) | ![]() |
![]() |
This'll take some coding, you'll need two procedures, one to get the name of the control, and one to blank it out when the mouse moves over a blank part of the screen. In a global module, create a global variable and....(Declarations) Option Explicit Global gctlUnderMouse As Control Function SetCtlUnderMouse(pctl As Control) Set gctlUnderMouse = pctl End Function Now, in the form, you need to set the MouseMove property of each control, for the background (Form, detail, header, footer) use: =SetCtlUnderMouse(Nothing) This will set the global variable to nothing, indicating that the mouse is not hoverig over a control that you're intrested in. For Controls that you're intrested in use: =SetCtlUnderMouse([ControlName]) Where controlName is the name of the control, of course this would be ultra tedious doing this in one form, let alone every form in the database so here's a bit of code that will do it for you, just bring up the form in design mode, select the objects you want to have this done to using [Shift] + Click, then open the code window, and in the immediate window type: CreateSetCtlUnderMouse Me Here's the code that will run (in a global module):
Sub CreateSetCtlUnderMouse(pfrm As Form)
Dim ctl As Control, i As Integer
For i = 0 to pfrm.Count - 1
Set ctl = pfrm(i)
If ctl.InSelection Then
ctl.OnMouseMove = "=SetCtlUnderMouse([" & ctl.Name & "])"
End If
Set ctl = Nothing
Next
End Sub
| ![]() |
![]() |
How do I get the Network User ID of the current user in the 32 bit version | ![]() |
![]() |
Same as for the 16 bit version except the declaration of the API call is different. Also like all 32 bit ports of 16 bit code, Integers are now Long Integers.
Declare Function wu_GetUserName Lib "advapi32" Alias "GetUserNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long
Function NetworkUserName () As String
Dim lngStringLength As Long
Dim sString As String * 255
lngStringLength = Len(sString)
sString = String$(lngStringLength, 0)
If wu_GetUserName(sString, lngStringLength) Then
NetworkUserName = Left$(sString, lngStringLength)
Else
NetworkUserName = "Unknown"
End If
End Function
Updated: 22/12/1997 - Christopher Schmidt | ![]() |
![]() |
How can I trap a ODBC Error in VBA? All the VBA Err object returns is "ODBC Call Failed" | ![]() |
![]() |
Use the DbEngine.Errors collection
Sub Update_TempLib()
On Error GoTo ErrorTrap
' Executing connect code at this point
Exit_errortrap:
Exit Sub
ErrorTrap:
Dim myerror As Error
For Each myerror In DBEngine.Errors
With myerror
If .Number <> 3146 Then
MsgBox .Description
End If
End With
Next
Resume Exit_errortrap
End Sub
Updated: 07/05/1998 - Sol Shapiro | ![]() |