I was wondering if there is a way to excute a Script that is in Textbox1
Like you write this code inside textbox1
msgbox("Hello World")
and when you click on the button or press enter it will run the command/script you wrote in Textbox1
Yes, you can. This is a bit messy and was cobbled together from various articles on the web, but you get the general idea...
Imports System.IO
Imports System.Reflection
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports Microsoft.VisualBasic
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' read code from textbox
Dim Code As String = TextBox1.Text
' clear output textbox
TextBox2.Clear()
' create fully functional assembly string
Code = ("Imports System" & vbCrLf &
"Imports System.Windows.Forms" & vbCrLf &
"Imports Microsoft.Visualbasic" & vbCrLf &
"Public Class TempClass" & vbCrLf &
"Public Sub MyCode(ByVal Textbox2 As TextBox)" & vbCrLf &
Code & vbCrLf &
"End Sub" & vbCrLf &
"End Class")
' create the compiler
Dim vbProv = New VBCodeProvider()
' create parameters to pass to the compiler
Dim vbParams = New CompilerParameters()
' add referenced assemblies.
vbParams.ReferencedAssemblies.Add("System.dll")
vbParams.ReferencedAssemblies.Add("System.Windows.Forms.dll")
vbParams.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll")
' generate an assembly in memory
vbParams.GenerateExecutable = False
vbParams.GenerateInMemory = True
' give it a name
vbParams.OutputAssembly = "MyCode"
' compile the code and get the compiler results
Dim compResults = vbProv.CompileAssemblyFromSource(vbParams, Code)
' check for compile errors
If compResults.Errors.HasErrors Then
Dim ErrorMsg As String = compResults.Errors.Count.ToString & " Errors:"
For x As Integer = 0 To compResults.Errors.Count - 1
ErrorMsg = ErrorMsg & vbCrLf & "Line: " & compResults.Errors(x).Line.ToString & " - " + compResults.Errors(x).ErrorText
Next
TextBox2.Text = ErrorMsg & vbCrLf & vbCrLf + Code
Else
' create instance of the temporary compiled class
Dim obj As Object = compResults.CompiledAssembly.CreateInstance("TempClass")
' use textbox 2 for output
Dim args() As Object = {Me.TextBox2}
Try
' execute the code
Dim result As Object = obj.GetType().InvokeMember("MyCode", BindingFlags.InvokeMethod, Nothing, obj, args)
Catch Oops As Exception
' oops
MessageBox.Show(Oops.Message)
End Try
End If
End Sub
End Class
You're looking for CodeDOM. This basically lets you run the compiler from within your program. Be careful, the user could type anything into the box and compromise your program with it.
Related
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.
I want to create a routine that when called will perform the function base on the control names dynamically. Here's my code:
Private Sub myControl(counter as string)
If mySecondControl & counter.Value = "Y" Then
myThirdControl & counter.Caption = "Do Something Here" 'Error syntax
End If
End Sub
Private Sub doThis_Change()
myControl("1")
myControl("2")
End Sub
You need to get the Control you want from the form's Controls collection:
If Controls("mySecondControl" & counter).Value = "Y" Then
Controls("myThirdControl" & counter).Caption = "Do Something Here"
End If
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 a class based on this msdn page the only problem my process.exited event is never reached.
The .exe for the process is a console application that I have created. And it closes it self when it's done. But my event does not get reached and I have to wait 30s for the code to resume.
Is there something that i am doing wrong? For my test case the .exe only takes +- 5 seconds to complete.
I assume when a console application closes after the code is done the process is exited. My this assumption is wrong?
Imports System
Imports System.Diagnostics
Imports System.Threading
Public Class CopyDesignProcessClass
Private WithEvents oProcess As New Process()
Private elapsedTime As Integer
Private eventHandled As Boolean
Public Event Exited As EventHandler
Shared Sub Start(ByVal oArgument As String)
' Verify that an argument has been entered.
If oArgument Is Nothing Or oArgument = "" Then
Exit Sub
End If
' Create the process and copy the design.
Dim myCopyDesignProcess As New CopyDesignProcessClass
myCopyDesignProcess.CopyDesign(oArgument)
End Sub
' Print a file with any known extension.
Sub CopyDesign(ByVal oArgument As String)
elapsedTime = 0
eventHandled = False
Try
' Start a process to copy a design and raise an event when done.
oProcess.StartInfo.FileName = "C:\Program Files\Autodesk\CopyDesign Tool\CopyDesignTool.exe"
oProcess.StartInfo.Arguments = oArgument
oProcess.Start()
Catch ex As Exception
MsgBox("An error occurred trying to copydesign " & oArgument & " :" &
vbCrLf & ex.Message, MsgBoxStyle.Exclamation, "CopyDesign Failed")
Return
End Try
' Wait for Exited event, but not more than 30 seconds.
Const SLEEP_AMOUNT As Integer = 100
Do While Not eventHandled
elapsedTime += SLEEP_AMOUNT
If elapsedTime > 30000 Then
Exit Do
End If
Thread.Sleep(SLEEP_AMOUNT)
Loop
End Sub
' Handle Exited event and display process information.
Private Sub myProcess_Exited(ByVal sender As Object,
ByVal e As System.EventArgs) Handles oProcess.Exited
eventHandled = True
Debug.Print("Exit time: {0}" & vbCrLf &
"Exit code: {1}" & vbCrLf &
"Elapsed time: {2}",
oProcess.ExitTime, oProcess.ExitCode, elapsedTime)
End Sub
End Class
Additional:
The answer may be given in this post but it's in c# and this I don't understand.
c# possible answer
Corrected code, but used another solution posted as answer.
Imports System
Imports System.Diagnostics
Imports System.Threading
Public Class CopyDesignProcessClass
Private WithEvents oProcess As New Process()
Private elapsedTime As Integer
Private eventHandled As Boolean
Public Event Exited As EventHandler
Shared Sub Start(ByVal oArgument As String)
' Verify that an argument has been entered.
If oArgument Is Nothing Or oArgument = "" Then
Exit Sub
End If
' Create the process and copy the design.
Dim myCopyDesignProcess As New CopyDesignProcessClass
myCopyDesignProcess.CopyDesign(oArgument)
End Sub
' Print a file with any known extension.
Sub CopyDesign(ByVal oArgument As String)
elapsedTime = 0
eventHandled = False
Try
' Start a process to copy a design and raise an event when done.
oProcess.StartInfo.FileName = "C:\Program Files\Autodesk\CopyDesign Tool\CopyDesignTool.exe"
oProcess.StartInfo.Arguments = oArgument
oProcess.EnableRaisingEvents = True
oProcess.Start()
Catch ex As Exception
MsgBox("An error occurred trying to copydesign " & oArgument & " :" &
vbCrLf & ex.Message, MsgBoxStyle.Exclamation, "CopyDesign Failed")
Return
End Try
' Wait for Exited event, but not more than 30 seconds.
Const SLEEP_AMOUNT As Integer = 100
Do While Not eventHandled
elapsedTime += SLEEP_AMOUNT
If elapsedTime > 30000 Then
Exit Do
End If
Thread.Sleep(SLEEP_AMOUNT)
Loop
End Sub
' Handle Exited event and display process information.
Private Sub myProcess_Exited(ByVal sender As Object,
ByVal e As System.EventArgs) Handles oProcess.Exited
eventHandled = True
Debug.Print("Exit time: {0}" & vbCrLf &
"Exit code: {1}" & vbCrLf &
"Elapsed time: {2}",
oProcess.ExitTime, oProcess.ExitCode, elapsedTime)
End Sub
End Class
you can replace this part of the code:
Try
' Start a process to copy a design and raise an event when done.
oProcess.StartInfo.FileName = "C:\Program Files\Autodesk\CopyDesign Tool\CopyDesignTool.exe"
oProcess.StartInfo.Arguments = oArgument
oProcess.Start()
Catch ex As Exception
MsgBox("An error occurred trying to copydesign " & oArgument & " :" &
vbCrLf & ex.Message, MsgBoxStyle.Exclamation, "CopyDesign Failed")
Return
End Try
' Wait for Exited event, but not more than 30 seconds.
Const SLEEP_AMOUNT As Integer = 100
Do While Not eventHandled
elapsedTime += SLEEP_AMOUNT
If elapsedTime > 30000 Then
Exit Do
End If
Thread.Sleep(SLEEP_AMOUNT)
Loop
with:
Try
' Start a process to copy a design and raise an event when done.
oProcess.StartInfo.FileName = "C:\Program Files\Autodesk\CopyDesign Tool\CopyDesignTool.exe"
oProcess.StartInfo.Arguments = oArgument
oProcess.Start()
oProcess.WaitForExit()
Catch ex As Exception
MsgBox("An error occurred trying to copydesign " & oArgument & " :" &
vbCrLf & ex.Message, MsgBoxStyle.Exclamation, "CopyDesign Failed")
Return
End Try
waitforexit method is very useful, it will freeze your code until given software is done. If running longer processes background worker may be necessary.
I have a BackgroundWorker that includes a class ExcelOutput, used to output various data to a workbook, and I should mention straight away that bw.WorkerSupportsCancellation = True is set.
At each stage of the output I'm checking for errors in ExcelOutput using Try/Catch, and if necessary displaying an error (using a function called ErroReport().
In conjunction with the error message, I want to cancel the BackgroundWorker to avoid further errors. To that end I have added the OutputWorker property to the ExcelOutput class and I set that to be a copy of my BackgroundWorker in the bw_DoWork() method.
However, the cancellation carried out in ExcelOutput.ErroReport() is not working, and I don't know why.
Note that I've tested the value of bw.CancellationPending and it is set to True after an error. I've also tested that the If condition following is working by showing a message box, and that also works. For some reason it seems as though the Exit Sub command is ignored though.
Can anyone suggest what I am doing wrong? Thanks.
Here is how the bw_DoWork() function from the BackgroundWorker class is set up -
Private Sub bw_DoWork(ByVal sender As Object,
ByVal e As DoWorkEventArgs)
Dim Excel As New ExcelOutput ' Create a new instance of the ExcelOutput class
Dim CurrentRow As Integer = 4 ' Set the first output row
'** Include a copy of the OutputWorker in the ExcelOutput (so that the OutputWorker can be cancelled)
Excel.OutputWorker = Me
If bw.CancellationPending = True Then
e.Cancel = True
Exit Sub
Else
Excel.Prepare()
End If
If bw.CancellationPending = True Then
e.Cancel = True
Exit Sub
Else
CurrentRow = Excel.OutputGroup("General", Headers, Data, 4)
End If
' More stuff here...
End Sub
Here is how the ErrorReport() function from the ExcelOutput class is set up -
Private Sub ErrorReport(ByVal Ex As Exception,
Optional ByVal CustomMessage As String = "")
Call Me.ResetRange() ' Destroy the 'Range' object
Dim ErrorMessage As String = "Message: " & Ex.Message ' Set the default message
If CustomMessage <> "" Then ErrorMessage = CustomMessage & vbCrLf & vbCrLf & Ex.Message
Dim Result As Integer = MessageBox.Show(ErrorMessage,
"An Error Has Occured",
MessageBoxButtons.OK,
MessageBoxIcon.Stop)
'** Close the workbook (if it's open) and stop the OutputWorker *'
Try
Call Me.WB.Close(SaveChanges:=False)
If Me.OutputWorker.WorkerSupportsCancellation = True Then
Me.OutputWorker.CancelAsync()
End If
Catch
End Try
End Sub
You should try to add the DoWorkEventsArgs as parameter to your ErrorReport function.
Private Sub ErrorReport(ByVal Ex As Exception,
Optional ByVal CustomMessage As String = "",
ByVal e As DoWorkEventsArgs)
Call Me.WB.Close(SaveChanges:=False)
If e.WorkerSupportsCancellation = True Then
e.CancelAsync()
End If
You'll be able to cancel the Backgroundworker.