A week ago I had a presentation where I was making an AI using Voice Recognition with VBA. It worked perfectly (I took the code from this WebSite) till some day I was going to test it again and it didn't work. It returns an error
"Run-time error '70': Permission denied"
I checked my microphone and the VBA References needed that are mentioned in the WebSite. Then I went to the Site I took the code from and I saw a different version of the code (Public, Shared...) and when I ran it, another error appears
"Run-time error '-2147200905 (80045077)': Automation error"
So can someone please help me, the code used to work and I didn't change anything. Here's the code:
Option Explicit
Dim WithEvents RC As SpInProcRecoContext
Dim Recognizer As SpInprocRecognizer
Dim myGrammar As ISpeechRecoGrammar
Private Sub CommandButton1_Click()
'On Error GoTo EH
Set RC = New SpInProcRecoContext
Set Recognizer = RC.Recognizer
Set myGrammar = RC.CreateGrammar
myGrammar.DictationSetState SGDSActive
Dim Category As SpObjectTokenCategory
Set Category = New SpObjectTokenCategory
Category.SetId SpeechCategoryAudioIn
Dim Token As SpObjectToken
Set Token = New SpObjectToken
Token.SetId Category.Default()
Set Recognizer.AudioInput = Token
'EH:
' If Err.Number Then ShowErrMsg
End Sub
Private Sub RC_Recognition(ByVal StreamNumber As Long, ByVal StreamPosition As Variant, ByVal RecognitionType As SpeechLib.SpeechRecognitionType, ByVal Result As SpeechLib.ISpeechRecoResult)
On Error GoTo EH
TextBox1.text = Result.PhraseInfo.GetText
EH:
If Err.Number Then ShowErrMsg
End Sub
Private Sub ShowErrMsg()
' Declare identifiers:
Const NL = vbNewLine
Dim T As String
T = "Desc: " & Err.Description & NL
T = T & "Err #: " & Err.Number
MsgBox T, vbExclamation, "Run-Time Error"
'End
End Sub
'### Second version of the code (Shared, Public...)
Option Explicit
Public WithEvents RC As SpSharedRecoContext
Public myGrammar As ISpeechRecoGrammar
Private Sub CommandButton1_Click()
'On Error GoTo EH
Set RC = New SpSharedRecoContext
Set myGrammar = RC.CreateGrammar
myGrammar.DictationSetState SGDSActive
'EH:
'If Err.Number Then ShowErrMsg
End Sub
Private Sub RC_Recognition(ByVal StreamNumber As Long, ByVal StreamPosition As Variant, ByVal RecognitionType As SpeechLib.SpeechRecognitionType, ByVal Result As SpeechLib.ISpeechRecoResult)
Label1.Caption = Result.PhraseInfo.GetText
End Sub
Private Sub RC_StartStream(ByVal StreamNumber As Long, ByVal StreamPosition As Variant)
'Label2.Caption = Val(StreamNumber)
End Sub
Private Sub ShowErrMsg()
' Declare identifiers:
Const NL = vbNewLine
Dim T As String
T = "Desc: " & Err.Description & NL
T = T & "Err #: " & Err.Number
MsgBox T, vbExclamation, "Run-Time Error"
End
End Sub
That error is saying:
SPERR_RECOGNIZER_NOT_FOUND 0x80045077 -2147200905
No recognizer is installed.
Related
I want to prevent local resources from being assigned to tasks.
Only corporate resources must be assigned.
How to implement this at the time of assignments by event handler?
This can be done with Application Events. Because assignments can be modified directly in a task table and in the Task Information dialog box, two event handlers are required. Create a class module called Events with the following code:
Option Explicit
Public WithEvents App As Application
Private Sub App_ProjectBeforeAssignmentChange(ByVal asg As Assignment, ByVal Field As PjAssignmentField, ByVal NewVal As Variant, Cancel As Boolean)
If Field = pjAssignmentResourceName Then
If Not ThisProject.Resources(NewVal).Enterprise Then
MsgBox "Resource '" & NewVal & "' cannot be added.", vbOKOnly, "Only enterprise resources are allowed"
Cancel = True
End If
End If
End Sub
Private Sub App_ProjectBeforeTaskChange(ByVal tsk As Task, ByVal Field As PjField, ByVal NewVal As Variant, Cancel As Boolean)
If Field = pjTaskResourceNames Then
Dim resNames() As String
resNames = Split(NewVal, ",")
Dim AllEnterprise As Boolean
AllEnterprise = True
Dim i As Integer
For i = 0 To UBound(resNames)
AllEnterprise = AllEnterprise And ThisProject.Resources(resNames(i)).Enterprise
Next i
If Not AllEnterprise Then
MsgBox "Resource Names '" & NewVal & "' is invalid.", vbOKOnly, "Only enterprise resources are allowed"
Cancel = True
End If
End If
End Sub
In the ThisProject module, add this code:
Option Explicit
Dim eClass As New Events
Private Sub Project_Open(ByVal pj As Project)
InitializeEventHandler
End Sub
Sub InitializeEventHandler()
Set eClass.App = Application
End Sub
The code I currently works as follows: I type in a UID and then a message box shows the slack of a task. However, it's not possible to edit the Microsoft Project file while the message box is open.
Is there another object I can use in VBA to show the same output but allow me to work on the project file while having the output out? And, is it possible to have the output be in real time? In other words, if I make changes in my schedule, can I see the output constantly change if the slack changes as I make changes without having to run the application again?
Sub SlackFinder()
Dim User_UID, User_ID As Integer
Dim Slack As Variant
Dim NewSlack As Variant
User_UID = InputBox("Enter UID for slack:")
If User_UID = "" Then Exit Sub
On Error GoTo Error_Not_Found
User_ID = ActiveProject.Tasks.UniqueID(User_UID).ID
On Error GoTo Error_Collapsed
Slack = ActiveProject.Tasks.UniqueID(User_UID).TotalSlack
NewSlack = Slack / 480
MsgBox "Total Slack: " & NewSlack
Exit Sub
Error_Not_Found:
MsgBox "UID " & User_UID & " not found in " & ActiveProject.Name
Exit Sub
Error_Collapsed:
MsgBox "UID is present but cannot be selected. Perhaps it is collapsed?", vbOKOnly, "COLLAPSED UID?"
Exit Sub
End Sub
You can show real-time slack using a modeless userform. Create a userform in VBA, for example something that has a textbox for entering the task UID and a label to display the Total Slack value:
Then add this code to the UserForm module:
Private Sub UID_Change()
UpdateTotalSlack
End Sub
Sub UpdateTotalSlack()
On Error Resume Next
Me.TSlack = "Total Slack = " & ActiveProject.Tasks.UniqueID(Me.UID).TotalSlack / 480
End Sub
Add this to the Project module:
Sub ShowSlack()
UserForm1.Show False
End Sub
Private Sub Project_Change(ByVal pj As Project)
UserForm1.UpdateTotalSlack
End Sub
To start, call the ShowSlack procedure. This shows the user form modelessly (e.g. it floats above the MS Project window, allowing you to make changes in the schedule). Enter a Task UID in the textbox and the Total Slack will be displayed immediately and updated whenever changes are made to the schedule (thanks to the Change event code).
Project Module:
Private Sub Project_Change(ByVal pj As Project)
MsgBox "hi"
UserForm10.UpdateTotalSlack
End Sub
Module 29:
Sub ShowSlack()
UserForm10.Show False
End Sub
Userform10:
Dim User_UID As Variant
Dim TSlack As Variant
Private Sub TextBox3_Change()
User_UID = UserForm10.TextBox3.Value
UpdateTotalSlack
End Sub
Sub UpdateTotalSlack()
On Error Resume Next
If Not User_UID = "" Then
TSlack = ActiveProject.Tasks.UniqueID(User_UID).TotalSlack / 480
Else
TSlack = ""
End If
UserForm10.Label1.Caption = TSlack
End Sub
I want to block some specific textboxes has numeric values only and accept ".". However, it blocks almost all my textboxes in my userform. I don't understand why. What I forgot in my code?
Private Sub tbxHour_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'Making TextBox accept Numbers only
If Not IsNumeric(tbxHour.Value) Then
MsgBox "only numbers allowed"
Cancel = True
End If
End Sub
Private Sub tbxHour_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Select Case KeyAscii
Case 46
If InStr(1, tbxHour, ".") > 0 Then KeyAscii = 0
Case 48 To 57
Case Else
KeyAscii = 0
End Select
End Sub
This one worked for me:
Private Sub tbxHour_AfterUpdate()
'Make sure the item is Numeric or has a "." in it
If Not IsNumeric(Me.tbxHour.Text) And Not Me.tbxHour.Text = "." Then
MsgBox "This is illegal!"
Me.tbxHour.Text = ""
End If
End Sub
Short. Simple. Effective and looks like what you're trying to do anyway.
I use this simply NumKeyValidator class for that, to simply prevent invalid input to be supplied by the user:
Option Explicit
Private Const vbKeyDot As Integer = 46
Public 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
You can use it by simply declaring an instance field for it:
Private validator As New NumKeyValidator
And then you use it in each textbox' KeyPress handler, like this:
Private Sub tbxHour_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If Not validator.IsValidKeyAscii(keyAscii, tbxHour.Value) Then keyAscii = 0
End Sub
There's no need to handle Exit and pop a MsgBox then - either the box is empty, or it contains a valid number; you could have an IsValidForm property that returns True if all required textboxes contain numbers, and false otherwise - and then decide that the form's Ok button is disabled until the form is valid.
FWIW that validator class is quite thoroughly tested (using Rubberduck unit tests [disclaimer: I own that open-source VBE add-in project]):
Option Explicit
Option Private Module
'#TestModule
'' uncomment for late-binding:
Private Assert As Object
'' early-binding requires reference to Rubberduck.UnitTesting.tlb:
'Private Assert As New Rubberduck.AssertClass
'#TestMethod
Public Sub DotIsValidForEmptyValue()
On Error GoTo TestFail
'Arrange:
Dim actual As Boolean
Dim sut As New NumKeyValidator
'Act:
actual = sut.IsValidKeyAscii(Asc("."), vbNullString)
'Assert:
Assert.IsTrue actual
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
'#TestMethod
Public Sub DotIsValidForNonEmptyValueWithoutAnyDots()
On Error GoTo TestFail
'Arrange:
Dim actual As Boolean
Dim sut As New NumKeyValidator
'Act:
actual = sut.IsValidKeyAscii(Asc("."), "123")
'Assert:
Assert.IsTrue actual
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
'#TestMethod
Public Sub DotIsInvalidWhenValueHasDot()
On Error GoTo TestFail
'Arrange:
Dim actual As Boolean
Dim sut As New NumKeyValidator
'Act:
actual = sut.IsValidKeyAscii(Asc("."), "123.45")
'Assert:
Assert.IsFalse actual
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
'#TestMethod
Public Sub AllDigitsAreValid()
On Error GoTo TestFail
Dim sut As New NumKeyValidator
Assert.IsTrue sut.IsValidKeyAscii(Asc("0"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("1"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("2"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("3"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("4"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("5"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("6"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("7"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("8"), vbNullString)
Assert.IsTrue sut.IsValidKeyAscii(Asc("9"), vbNullString)
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
'#TestMethod
Public Sub AlphaIsInvalid()
On Error GoTo TestFail
'Arrange:
Dim actual As Boolean
Dim sut As New NumKeyValidator
'Act:
actual = sut.IsValidKeyAscii(Asc("a"), vbNullString)
'Assert:
Assert.IsFalse actual
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
'#TestMethod
Public Sub DollarSignIsInvalid()
On Error GoTo TestFail
'Arrange:
Dim actual As Boolean
Dim sut As New NumKeyValidator
'Act:
actual = sut.IsValidKeyAscii(Asc("$"), vbNullString)
'Assert:
Assert.IsFalse actual
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
'#TestMethod
Public Sub NegativeSignIsInvalid()
On Error GoTo TestFail
'Arrange:
Dim actual As Boolean
Dim sut As New NumKeyValidator
'Act:
actual = sut.IsValidKeyAscii(Asc("-"), vbNullString)
'Assert:
Assert.IsFalse actual
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
That said I don't see how the code you've shown could ever "block almost all textboxes in your userform".
EDIT: To clarify, the code seen below is within a module and the UserForm is all contained within its own code.
I have the following code. When I go to run it, Excel throws me a compile error: Method or data member not found and highlights the following piece of code: .showInputsDialog. I have no idea how to resolve this error.
To give more information, the sub sportUserForm is supposed to call up a UserForm sportsUsrFrm. Any help with this issue is greatly appreciated.
Option Explicit
Sub sportUserForm()
Dim sSport As String, sPreference As String
If sportsUsrFrm.showInputsDialog(sSport, sPreference) Then
MsgBox "Your favorite sport is " & sSport & ", and you usually " _
& sPreference & "."
Else
MsgBox "Sorry you don't want to play."
End If
End Sub
Public Function showInputsDialog(sSports As String, sPreference As String) As Boolean
Call Initialize
Me.Show
If Not cancel Then
If optBaseball.Value Then sSport = "Baseball"
ElseIf optBasketball.Value Then sSport = "Basketball"
Elss sSport = "Football"
End If
If optTV.Value Then sPreference = "watch on TV" _
Else: sPreference = "go to games"
End If
showInputsDialog = Not cancel
Unload Me
End Function
UserForm code for sportUsrFrm
Option Explicit
Private Sub cmdCnl_Click()
Me.Hide
cancel = True
End Sub
Private Sub cmdOK_Click()
If Valid Then Me.Hide
cancel = False
End Sub
You're getting the error because showInputsDialog isn't a member of the form, it's a member of the module you're calling it from. You should also be getting compiler errors on these two lines...
Call Initialize
Me.Show
...because you seem to be getting the module and form code mixed up.
That said, you're overthinking this. A UserForm is a class module, and it can be stored in a variable (or in this case, in a With block), and can have properties. I'd add a Cancelled property to the form:
'In sportsUsrFrm
Option Explicit
Private mCancel As Boolean
Public Property Get Cancelled() As Boolean
Cancelled = mCancel
End Property
Private Sub cmdCnl_Click()
Me.Hide
mCancel = True
End Sub
Private Sub cmdOK_Click()
If Valid Then Me.Hide '<-- You still need to implement `Valid`
End Sub
And then call it like this:
Sub sportUserForm()
With New sportsUsrFrm
.Show
Dim sSport As String, sPreference As String
If Not .Cancelled Then
If .optBaseball.Value Then
sSport = "Baseball"
ElseIf .optBasketball.Value Then
sSport = "Basketball"
Else
sSport = "Football"
End If
If .optTV.Value Then
sPreference = "watch on TV"
Else
sPreference = "go to games"
End If
MsgBox "Your favorite sport is " & sSport & ", and you usually " _
& sPreference & "."
Else
MsgBox "Sorry you don't want to play."
End If
End With
End Sub
I have created this script to play a wav file when I receive an email. The point is to play the sound only during business hours. If the email is received outside business hours, no sound will play.
Private Declare PtrSafe Function PlaySound Lib "winmm.dll" _
Alias "PlaySoundA" (ByVal lpszName As String, _
ByVal hModule As LongPtr, ByVal dwFlags As Long) As Long
Sub PlayWavFile(WavFileName As String, Wait As Boolean)
If Dir(WavFileName) = "" Then Exit Sub ' no file to play
If Wait Then ' play sound synchronously
PlaySound WavFileName, 0, 0
Else ' play sound asynchronously
PlaySound WavFileName, 0, 1
End If
End Sub
Sub PlayASoundDuringBusinessHours(Item As Outlook.MailItem)
Dim SecondsSinceMidnight
Dim SecondsPerHour
Dim NineOclockAm
Dim NineOclockPm
Dim TooEarly
Dim TooLate
On Error GoTo ErrHandler:
SecondsSinceMidnight = Timer
SecondsPerHour = 60 * 60
NineOclockAm = SecondsPerHour * 9
NineOclockPm = SecondsPerHour * 21
TooEarly = Timer < NineOclockAm
TooLate = Timer > NineOclockPm
If Not (TooEarly) And Not (TooLate) Then
PlayWavFile "c:\windows\media\blahblahblah.wav", False
End If
ExitProcedure:
Exit Sub
ErrHandler:
MsgBox Err.Description, _
vbExclamation + vbOKCancel, _
"Error: " & CStr(Err.Number)
Resume ExitProcedure:
End Sub
I have a rule in Outlook that uses this script when mail comes in and it works! For a while, anyway.
I do not know what the problem is, but once in a while an error occurs in this script and I get a dialog from Outlook that says "Rules in error" and "The operation failed." When this happens, the Outlook rule that uses this script becomes disabled.
Is my exception handling inadequate? What could be causing this error and how do I handle it properly?
Update:
The rule is very basic. It does little beyond executing the script:
Apply this rule after the message arrives
on this computer only
run Project.PlayASoundDuringBusinessHours
Not a direct response to the question but my solution was to switch to ItemAdd.
Examples:
http://msdn.microsoft.com/en-us/library/office/aa171270(v=office.11).aspx
http://www.outlookcode.com/article.aspx?id=62