Unable to Get Cypress Enable Scripting Statements to Work - vba

I'm a Technical Writer going through our application's documentation and I came across some issues trying to get some existing Cypress Enable code snippets to work.
We have a stripped-down version of the VBA editor and compiler in our application.
When I try to run a couple of programs using some of the statements, I never get the results I'm expecting, or nothing happens.
For example, when I run this script to test the Declare statement, instead of getting a dialog, nothing happens:
Declare Function GetFocus Lib "User32" () As Integer
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (Byval hwnd As Long, Byval lpstring As String, Byval lpstrlen As Long)
Sub Main
Dim hWindow%
Dim str1 As String *51
Dim str2 As String *25
hWindow% = GetFocus()
Print "GetWindowText returned: " & GetWindowText( hWindow%, str1, 51)
Print "GetWindowText2 returned: " & GetWindowText( hWindow%, str2, 25)
Print str1
Print str2
End Sub
For the first print statement (Print str1), I'm expecting a MessageBox with:
Title = "Enable Scripting Language Editor"
Body text = "GetWindowText returned: 50"
A single OK button.
With this code to test the DlgFocus statement, no matter which of the OK/Cancel controls I click, the dialog just shuts down:
Sub Main()
Dim ListBox1$()
Begin Dialog UserDialog ,,112,74,"Untitled",.DlgProc
TextBox 12,20,88,12,.TextBox1
OKButton 12,44,40,14
CancelButton 60,44,40,14
Text 12,11,88,8,"Enter Desired Salary:",.Text1
End Dialog
Dim d As UserDialog
Dialog d
End Sub
Function DlgProc(ControlName$,Action%,SuppValue%) As Integer
If Action% = 2 and ControlName$ = "OK" Then
If IsNumeric(DlgText$("TextBox1")) Then
Msgbox "Duly Noted."
Else
Msgbox "Sorry, you must enter a number."
DlgFocus "TextBox1"
DlgProc = 1
End If
End If
End Function
In this version to test the DlgFocus statement, no matter which control I click, the value returned is always zero:
Sub Main
Begin Dialog UserDialog 200,120,"Script #9",.DialogFunc
Text 10,10,180,15,"Please push the OK button"
TextBox 10,40,180,15,.Text
OKButton 30,90,60,20
PushButton 110,90,60,20,"&Hello"
End Dialog
Dim dlg As UserDialog
Print Dialog(dlg)
MsgBox "Dialog info: " & Dialog(dlg)
End Sub
Function DialogFunc%(DlgItem$, Action%, SuppValue%)
Print "Action=";Action%
Select Case Action%
Case 1 ' Dialog box initialization
Beep
Case 2 ' Value changing Or button pressed
If DlgItem$ = "Hello" Then
MsgBox "Hello"
DialogFunc% = True 'Do Not Exit the Dialog
End If
Case 4 ' Focus changed
Print "DlgFocus=""";DlgFocus();""""
MsgBox "DlgFocus info: " & DlgFocus() & """"
End Select
End Function
Any help is greatly appreciated.

Related

text box exit event in multipage userform

I have multipage user form which has sub multipage. the text box exit event is not working it is working when userform exits. So I have tried the after update event. It works fine but I am not able to set focus the textbox if the entered value is not numeric. the code is working fine. userform doesnt show the previos page text box.
below is the screen shot and code
At page no 4 I have text box and once the details entered,I click the page2 to proceed. before that I need to check whether the entered detaisl is numeric or not. If its not numeric I have to show the page4 and focus on text box1 to re-enter the details that is not working. please help me guys.
Private Sub TextBox3_AfterUpdate()
If Len(UserForm1.TextBox3.Value) <> 0 And _
IsNumeric(UserForm1.TextBox3.Value) = False Then
UserForm1.MultiPage1.Value = 0
userform1.multipage2.value = 1
UserForm1.TextBox3.SetFocus
MsgBox "Only Numbers are Allowed!!"
End If
End Sub
the code didnot show error but Its not focusing on the text box still showing the page2.
Messagebox interrupts set Focus
Displaying a messagebox (window) interrupts your SetFocus code. In order to work around this issue just redisplay the userform after hiding via
Me.Hide: Me.Show
Another approach would be to display the error message by a Label caption message.
Modified example using your original code:
Private Sub TextBox3_AfterUpdate()
If Len(Me.TextBox3.Value) <> 0 And _
IsNumeric(Me.TextBox3.Value) = False Then
Me.MultiPage1.Value = 0
MsgBox "Only Numbers are allowed!!"
Me.MultiPage2.Value = 1
Me.TextBox3.SetFocus
Me.Hide: Me.Show ' << work around by redisplaying userform
End If
End Sub
Hint
It's better to use the Me. prefix than UserForm1. within the userform code module itself to identify controls (and allow IntelliSense).
You could consider using keydown events to prevent non numeric input all together with something like this
'' allows checking numlock
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Private Const ksCapital As Long = 20
Private Const ksNumLock As Long = 144
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case vbKeyBack, vbKeyDelete, vbKeyLeft, vbKeyRight, vbKeyInsert, vbKeyNumlock
'' allow deleting, moving, changing numlock
Case Asc(0) To Asc(9)
'' if input is a number, not a symbol let it remain
If Shift Eqv Not GetKeyState(ksNumLock) Then KeyCode = 0
Case Asc("-")
'' allow negatives
If InStr(1, Me.TextBox1.Text, "-") > 0 Or Me.TextBox1.SelStart > 0 Then Let KeyCode = 0
Case Asc(".")
'' allow decimals
If InStr(1, Me.TextBox1.Text, ".") > 0 Then Let KeyCode = 0
Case Else
'' allow nothing else
Let KeyCode = 0
End Select
End Sub

Vba: ‘On error’ statement safety

I made a macro that records, then changes the local settings (in my case the decimal separator). At the end of the macro it would restore the settings.
When there is an error I make the program also restore the local settings using the ‘on error’ statement.
(A simplified example of the program is given below)
So far I got no issues; however, as I am now planning to transfer the program to my working colleagues, I really wish to not interfere with them and overwrite their own local settings.
Does the On error statement is here safe enough to use and make sure that the settings are restored?
Is there any case where the program could run into an error that the On error would fail to redirect to the error handler?
PS: I already know I can convert all my numbers using String = Replace(Number, ",", ".") but for some reasons I cannot afford to go through all the many variables of the macro.
Example Code:
Private Declare Function GetUserDefaultLCID% Lib "kernel32" ()
Private Declare Function GetLocaleInfoA Lib "kernel32" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Private Declare Function SetLocaleInfoA Lib "kernel32" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String) As Boolean
Sub test()
' what to do on error
On Error GoTo ErrorHandler:
' define a number (Your local settings are set up to
Dim MyNumber As Single
MyNumber = 0.03
MsgBox ("Number is 0,03 ->" & MyNumber)
' record the settings in the variable LocalSettingsDecimal
Dim LocalSettingsDecimal As String
Dim Buffer As String
Buffer = String(256, 0)
Dim le As Integer
le = GetLocaleInfoA(GetUserDefaultLCID(), 14, Buffer, Len(Buffer))
LocalSettingsDecimal = Left(Buffer, le - 1)
' force decimal settings to '.'
Call SetLocaleInfoA(GetUserDefaultLCID(), 14, ".")
' Now is the program body
MsgBox ("Number is now 0.03 ->" & MyNumber)
' an unfortunate error:
MyNumber = "aa"
Call SetLocaleInfoA(GetUserDefaultLCID(), 14, LocalSettingsDecimal)
MsgBox ("Number should be back 0,03 ->" & MyNumber)
Exit Sub
ErrorHandler:
Call SetLocaleInfoA(GetUserDefaultLCID(), 14, LocalSettingsDecimal)
MsgBox ("There was an error but it's ok, it should be back to 0,03 ->" & MyNumber)
End Sub
There are many ways VBA code can get interrupted, some not even involving a clever user that would break on a MsgBox and hit the Stop button: If the host crashes for of something completely unrelated to your code (some KB updates come to mind), in the middle of a procedure's execution, then your error handlers won't be jumped into and there's nothing you can do to prevent that.
Don't tamper with user's local settings. Fix your code instead.
I already know I can convert all my numbers using String = Replace(Number, ",", ".")
Your code is treating numbers as strings, or vice-versa. If the number came from a cell in a worksheet, you can read it into a Double without having to think about what the user's decimal separator is.
Dim myNumber As Double
With ActiveSheet
If IsNumeric(.Range("A1").Value) And Not IsError(.Range("A1").Value) Then myNumber = CDbl(.Range("A1").Value)
'myNumber contains a valid numeric value
End With
If the number came from a textbox on a UserForm you crafted, and you allowed the user to enter a comma when your code requires that to be a dot, then you need to fix your data entry code and add some input validation to prevent that. One way to do this is to handle the KeyPress event of the TextBox control that's receiving the user's input - and "swallow" any invalid keys:
Private Sub txtInput_KeyPress(ByVal keyAscii As MSForms.ReturnInteger)
If Not IsValidKeyAscii(keyAscii, txtInput.Value) Then keyAscii = 0
End Sub
Private Function IsValidKeyAscii(ByVal keyAscii As Integer, ByVal value As String) As Boolean
'returns true if specified keyAscii is a number, or if it's a dot and value doesn't already contain one
IsValidKeyAscii = (keyAscii = vbKeyDot And InStr(1, value, Chr$(vbKeyDot)) = 0) Or (keyAscii >= vbKey0 And keyAscii <= vbKey9)
End Function
If the number came from an InputBox, you won't be able to prevent the user from entering whatever they want, but you can still validate the input and prevent bad input from being propagated further into your code.
Private Function PromptForNumber() As Double
Dim isValid As Boolean
Dim userInput As String
Do
userInput = InputBox("Enter a decimal number:")
isValid = IsNumeric(userInput) And InStr(userInput, ",") = 0
If Not isValid Then MsgBox "Value '" & userInput & "' is not numeric. Please make sure to use [en-US] decimal separator."
While Not isValid
PromptForNumber = CDbl(userInput)
End Function
There's simply no excuse for messing with the user's Control Panel settings.
If the End command is encountered anywhere in the code then this will foil your plan.
Take a look at the example below. If A calls B then no problem, errors are handled and when control returns to A the handler will still execute your locale reset. But uncomment the call to C and run the code again. Execution simply stops and control never returns to A so the reset is not performed.
So your scenario is that you send the workbook to your colleague and then they to add on some more logic which uses the End command for whatever reason.
Option Explicit
Sub A()
On Error GoTo ErrHandler
Dim foo As Long
'call B
B
' call C - uncomment to see impact
'C
ErrHandler:
Debug.Print "Error occurred in A"
Debug.Print "Fixing locale stuff..."
End Sub
Sub B()
On Error GoTo ErrHandler
Dim foo As Long
'cause an error
foo = "bar"
ErrHandler:
Debug.Print "Error occurred in B"
Debug.Print Err.Description
End Sub
Sub C()
On Error GoTo ErrHandler
Dim foo As Long
'cause an error
foo = "bar"
ErrHandler:
Debug.Print "Error occurred in C"
Debug.Print Err.Description
End
End Sub

Detecting when data is added to a document, eg. a character or white space

Is there a way to detect when a user presses a key in Microsoft Word using VBA. I have searched for a method which does this. I have also searched for methods which create a way around this, such as detecting when the insertion point moves or it detects when a new character is placed in the word document, but I have had no look. I am currently using appWord_WindowSelectionChange(ByVal Sel As Selection) but this does not detect as you type.
I would appreciate anyone showing me how to either detect a keypress or would be able to show me a workaround which will accomplish the same goal.
Edit
I apologise if the summary of what I want above is not clear. What I have is a sub which fires using appWord_WindowSelectionChange(ByVal Sel As Selection). However what I want is this sub to fire whenever any data is entered into the word document, eg. a letter or a white space character. For example, if there was a character count in the footer of the word document and this sub which I have updates this character count, the character count field should update as the user types in the document.
Not my Code but HTH.
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Sub KeyStrokeLogger()
Dim i As Integer
Dim KeyAsciiValue As Integer
StartLogging
Do While True
For i = 1 To 255
If GetAsyncKeyState(i) = -32767 Then
If CapsLockIsOn() Then
If ShiftIsPressed() = True Then
KeyAsciiValue = Asc(LCase(Chr(i)))
Else
KeyAsciiValue = Asc(UCase(Chr(i)))
End If
Else
If ShiftIsPressed() = True Then
KeyAsciiValue = Asc(UCase(Chr(i)))
Else
KeyAsciiValue = Asc(LCase(Chr(i)))
End If
End If
LogKeyStroke KeyAsciiValue
End If
Next i
DoEvents
Loop
End Sub
Private Function CapsLockIsOn() As Boolean
CapsLockIsOn = CBool(GetKeyState(20))
End Function
Private Function ShiftIsPressed() As Boolean
ShiftIsPressed = CBool(GetAsyncKeyState(16))
End Function
Private Sub StartLogging()
Open "C:\keylog.txt" For Binary As #1
Seek #1, LOF(1) + 1
End Sub
Private Sub LogKeyStroke(KeyAsciiValue As Integer)
Dim c As String * 1
c = Chr(KeyAsciiValue)
Select Case KeyAsciiValue
Case 8
Put #1, , "{BACKSPACE}"
Case 9
Put #1, , "{TAB}"
Case 13
Put #1, , "{ENTER}"
Case 32 To 126
Put #1, , c
Case Else
Put #1, , "{" & KeyAsciiValue & "}"
End Select
End Sub
*"How to use the above code:
Step 1
Create a new document in MS-Word.
Step 2
Go to Tools, Macro, Visual Basic Editor
Step 3
Double click on ThisDocument Object under Project(Document1) in the Project Window.
Step 4
Copy the above code and paste it into the Visual Basic Editor.
Step 5
Close the Visual Basic Editor and save the document.
Step 6
Ensure that macros are enabled. To start logging keystrokes at any time click on Tools, Macro, Macros. Select KeyStrokeLogger and click Run. All the keystrokes will be stored in C:\keylog.txt.
"*
LinkBack to Post
Use keybindings to bind characters to the function you want. For example, the following code (when run) fires a message box when the user enters 0 in the word document.
Put this in module 1
Sub AddKeyBinding()
With Application
.CustomizationContext = ThisDocument
.KeyBindings.Add KeyCode:=BuildKeyCode(wdKey0), _
KeyCategory:=wdKeyCategoryCommand, _
Command:="userpressedzero"
End With
End Sub
Put this in module 2
Sub userpressedzero()
Dim MyText As String
Selection.TypeText ("0")
MsgBox ("user pressed 0")
End Sub
Now run module 1 and press 0 in your word document.

Hiding MS Access from background and taskbar

I am looking forward to hide the Access background of my project when it's running to give it a more professional look and make it running like a standalone application. I am using Access 2003 and a form is already opening when the project is loaded. I would like to add some code in the Private Sub Form_Open(Cancel As Integer) of that form to hide the Access background.
The following will work on older versions of Access (tested on Access 2003):
Option Compare Database
Option Explicit
Global Const SW_HIDE = 0
Global Const SW_SHOWNORMAL = 1
Global Const SW_SHOWMINIMIZED = 2
Global Const SW_SHOWMAXIMIZED = 3
Private Declare Function apiShowWindow Lib "user32" _
Alias "ShowWindow" (ByVal hWnd As Long, _
ByVal nCmdShow As Long) As Long
Function fSetAccessWindow(nCmdShow As Long)
Dim loX As Long
Dim loForm As Form
On Error Resume Next
Set loForm = Screen.ActiveForm
If Err <> 0 Then
loX = apiShowWindow(hWndAccessApp, nCmdShow)
Err.Clear
End If
If nCmdShow = SW_SHOWMINIMIZED And loForm.Modal = True Then
MsgBox "Cannot minimize Access with " _
& (loForm.Caption + " ") _
& "form on screen"
ElseIf nCmdShow = SW_HIDE And loForm.PopUp <> True Then
MsgBox "Cannot hide Access with " _
& (loForm.Caption + " ") _
& "form on screen"
Else
loX = apiShowWindow(hWndAccessApp, nCmdShow)
End If
fSetAccessWindow = (loX <> 0)
End Function
Just call fSetAccessWindow(0) to hide and fSetAccessWindow(1) to show. Alternatively, use fSetAccessWindow(2) and fSetAccessWindow(3) to show minimized/maximized. You can use the Global Const too. Be careful: Access will be hidden from the taskbar.
If it doesn't work with Access 2010, here is another code that could work: http://www.tek-tips.com/faqs.cfm?fid=2562
The forms must be modal or it won't work. If for some reason you messed up and Access is still running in background but not showing in the taskbar or the task-manager, double click on any Access project again (nothing will happen because Access is still running) and then press ALT+TAB to reach the Access icon (it should magically show up). Nothing happens again because it's hidden, but it's now possible to close it with ALT+F4 if it still has the focus, thus preventing you from rebooting your computer...
In Ms Access 2003 a simple way seem to make the form
1. pop up
2. border style none
3. On form load event run maximise command
Private Sub Form_Load()
DoCmd.Maximize
End Sub

Access 2007 Show Full Screen

Can anyone tell me how I can show the full screen on a Form in Access 2007 so that there are no Toolbars etc open, so no one can tamper with anything ?
Cheers,
Nick C
There are several methods for doing this. One of the slickest I've seen is listed below. Unfortunately, I don't remember where I got this code from, so I can't give credit where it's due.
Post the code below into a new module in your database.
Global Const SW_HIDE = 0
Global Const SW_SHOWNORMAL = 1
Global Const SW_SHOWMINIMIZED = 2
Global Const SW_SHOWMAXIMIZED = 3
Private Declare Function apiShowWindow Lib "user32" Alias "ShowWindow" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Function DoAccessWindow(nCmdShow As Long)
' This function can minimize Access behind the scenes.
'Usage Examples
'Maximize window:
' ?DoAccessWindow(SW_SHOWMAXIMIZED)
'Minimize window:
' ?DoAccessWindow(SW_SHOWMINIMIZED)
'Hide window:
' ?DoAccessWindow(SW_HIDE)
'Normal window:
' ?DoAccessWindow(SW_SHOWNORMAL)
'
Dim loX As Long
Dim loform As Form
On Error Resume Next
Set loform = Screen.ActiveForm
If Err <> 0 Then 'no Activeform
If nCmdShow = SW_HIDE Then
MsgBox "Cannot hide Access unless a form is on screen"
Else
loX = apiShowWindow(hWndAccessApp, nCmdShow)
Err.Clear
End If
Else
If nCmdShow = SW_SHOWMINIMIZED And loform.Modal = True Then
MsgBox "Cannot minimize Access with " & (loform.Caption + " ") & "form on screen"
ElseIf nCmdShow = SW_HIDE And loform.PopUp <> True Then
MsgBox "Cannot hide Access with " & (loform.Caption + " ") & "form on screen"
Else
loX = apiShowWindow(hWndAccessApp, nCmdShow)
End If
End If
DoAccessWindow = (loX <> 0)
End Function
Now you can use the DoAccessWindow() function to mess with the Access window. You may want to play around with the hide option, as it totally hides the Access interface. A word of warning, any form you want to display must be Popup and Modal in order to be visible.
So for instance, on the Form_Open event, you could use the code DoAccessWindow(0) to hide Access's interface, then on the Form_Close event, you would use DoAccessWindow(1) to show the interface again.