Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Monday, August 22, 2011 5:14 PM
I am including VB scripting in my C# application. I have a VB script that I am simply popping up a message box right. But I need to be able to access a function or variable from my C# program. How do I go about doing this?
Here is the simple script I have so far:
imports System
imports System.Diagnostics
Imports System.Windows.Forms
module Script
sub Main()
MsgBox("Test script")
end sub
end module
Any help is greatly appreciated.
Thanks.
All replies (17)
Thursday, August 25, 2011 3:27 AM ✅Answered | 2 votes
OK, so let's go for something more simple.
- Create a C# windows forms project
- Add a reference to the COM component "Microsoft Script Control 1.0" (msscript.ocx)
- Add two multi-line text boxes: textInput and textOutput
- Add two buttons: buttonEval and buttonExecute
- Add click handlers for both buttons (double click them in the designer)
- Set the following code for Form1
[ComVisible(true)]
public partial class Form1 : Form
{
MSScriptControl.ScriptControlClass script;
public Form1()
{
InitializeComponent();
script = new MSScriptControl.ScriptControlClass();
script.Language = "VBScript";
script.AddObject( "me", this, true );
}
private void buttonEval_Click( object sender, EventArgs e )
{
textOutput.Text = script.Eval( textInput.Text ).ToString();
}
private void buttonExecute_Click( object sender, EventArgs e )
{
try {
script.ExecuteStatement( textInput.Text );
} catch( Exception x ) {
textOutput.Text = x.Message;
}
}
}
- Now run the program.
- In the input box, enter 2+2 and click the Eval button. Your output text box should contain 4.
- Now enter in the input box: MsgBox(me.Name) and click the Execute button. You should get a dialog box that says Form1
- Now enter in the input box: me.Left = me.Left + 50 and click the Execute button. The window position should move 50 pixels to the right.
You can AddObject any object that has the ComVisibleAttribute. (Note we had to make the form ComVisible(true) and expose all its properties for our little trick to work.
I put a little extra code in there to put error messages into the output box should you happen to make a typo in your script.
[Adapted from here: http://osherove.com/blog/2004/2/17/make-your-net-application-support-scripting-a-practical-appr.html]
Friday, August 26, 2011 11:03 AM ✅Answered | 1 vote
Here's an extention of my first example that exposes an object of type Thing with two methods: Test and GetOtherValue. It exposes it to script with the name thing.
[ComVisible( true )]
public class Thing
{
public void Test( string message )
{
MessageBox.Show( message );
}
public int GetOtherValue( int a, int b )
{
return a + b;
}
}
[ComVisible(true)]
public partial class Form1 : Form
{
MSScriptControl.ScriptControlClass script;
public Form1()
{
InitializeComponent();
script = new MSScriptControl.ScriptControlClass();
script.Language = "VBScript";
script.AddObject( "me", this, true );
Thing myThing = new Thing();
script.AddObject( "thing", myThing, true );
}
private void buttonEval_Click( object sender, EventArgs e )
{
textOutput.Text = script.Eval( textInput.Text ).ToString();
}
private void buttonExecute_Click( object sender, EventArgs e )
{
try {
script.ExecuteStatement( textInput.Text );
} catch( Exception x ) {
textOutput.Text = x.Message;
}
}
}
Execute the following tests:
**thing.Test "Hello" **
Displays a message box containing "Hello"
**MsgBox "Test Script " & thing.GetOtherValue(2,3) **
** ** Displays A message box containing "Test Script 5"
FYI: No need for all the boilerplate in your script. For example, no need to Dim with the "as Integer" part in VBScript. Just Dim val
**
**
Friday, August 26, 2011 4:58 PM ✅Answered | 1 vote
Just do this:
Imports System
Imports System.Diagnostics
Imports System.Windows.Forms
Imports Thing
module Script
sub Main()
Implements Thing
Dim thing as Thing
thing.Test "Hello from script"
MsgBox("Test script " & thing.GetOtherValue(2,2))
end sub
end module
(i.e.: delete all the crossed out stuff.)
And make sure that you included this important stuff below in your C# before executing the script.
Thing myThing = new Thing();
script.AddObject( "thing", myThing, true );
Monday, August 22, 2011 7:05 PM
How about giving your C# object the ComVisibleAttribute and create it from script using CreateObject("MyLibrary.MyObject")
(Note: register your C# assembly with regasm.)
Tuesday, August 23, 2011 5:07 PM
Have you used this method?
Do you have example C# and also the VBScript code to demonstrate this?
Thanks.
Tuesday, August 23, 2011 7:23 PM
Of course, I've used this method. There is example C# at the ComVisibleAttribute link I sent you. Did you follow the link and read the page?
I don't know what more to tell you. Here's another person saying pretty much exactly what I said. In case you find their version more clear.
Tuesday, August 23, 2011 8:11 PM
Does the C# code need to be in a DLL or can it be in an application (EXE)?
So, can I declare a member function in a class in my C# executable as [ComVisibleAttribute(true)] and then call that function from my VBScript (also running "in" my application)?
Thanks.
Wednesday, August 24, 2011 2:01 PM
Yes, you could conceivably host your com object in your exe as an out-of-process server. That's reasonable. The script would try to create the object, determine that the server is the currently running instance of your exe, and send an activation request for the object, then it would be marshalled back into the WSH (or whatever you're using to host VBScript).
Doesn't this make you wish you were using an embedded scripting language though? like python? If you were using an embedded scripting language then you could just put the object into your scripting context directly.
Wednesday, August 24, 2011 11:48 PM
Being more of a novice with this, I'm not sure how I go about doing what you described. I tried declaring a function in my C# app using [ComVisibleAttribute(true)] and then calling it in the VBScript, however, this did not work for me.
I'm stuck using VBScript for now.
Thanks.
Thursday, August 25, 2011 2:44 AM
Hello,
I think that it's not enough to add the ComVisibleAttribute and that you also need to add the GuidAttribute to register it.
Eyal (http://shilony.net), Regards.
EF4 Domain Generator - automatically generates POCO, UoW and Repository classes.
Any fool can write code that a computer can understand. Good programmers write code that humans can understand. -- Martin Fowler.
Thursday, August 25, 2011 5:09 PM
Thanks for the code. I appreciate it.
I was hoping I could ask a more pointed question about the script itself and using the ComVisibleAttribute. I'm trying to see if I can fit what you mentioned before about the ComVisibleAttribute into my existing code.
The script I have right now is
imports System
imports System.Diagnostics
Imports System.Windows.Forms
module Script
sub Main()
dim val as Integer
val = CallCSharpFunc
MsgBox("Test script " + val.ToString())
end sub
end module
I then was wondering if I can put something in my C# class to call the CallCSharpFunc and return a value, such as
[ComVisible(true)]
public int GetOtherValue()
{
return 12 * 2;
}
<br/>
Thanks for any help. I apologize if this is going on way too long for this question.
Friday, August 26, 2011 2:55 PM
Thanks for all the help with my novice skills. I am getting an error in compiling my VB script. Not sure I mentioned this but the script resides in a text box in my C# app. Apparently the class isn't known to the script. The error I see is:
Object reference not set to an instance of an object
I've tried several different ways to let the "Thing" be known to my script...Implements Thing, etc.
Imports System
Imports System.Diagnostics
Imports System.Windows.Forms
Imports Thing
module Script
sub Main()
Implements Thing
Dim thing as Thing
thing.Test "Hello from script"
MsgBox("Test script " & thing.GetOtherValue(2,2))
end sub
end module
Thanks again for the help so far. Any additional help is greatly appreciated.
Friday, August 26, 2011 5:38 PM
Thanks. That seemed to work.
Why can't I use the other VB script code?
I am also trying to use the ICodeCompiler compiler to compile the script.
I also wanted to see if I can make the compiling more robust to get a line number for all errors. You gave me the code:
private void buttonExecute_Click( object sender, EventArgs e )
{
try {
script.ExecuteStatement( textInput.Text );
} catch( Exception x ) {
textOutput.Text = x.Message;
}
}
I tried using script.Error.Line.ToString() to get the line number, but it didn't like that. I wanted to see if I can cycle through using CompilerError.
I greatly appreciate the help so far. Thanks.
Saturday, August 27, 2011 2:40 AM | 1 vote
Oh dear. Some clarification is required.
.Net scripting with Visual Basic is not the same as VBScript. VBScript is a language. Visual Basic is a different language. They are almost the same, but not quite.
What you are doing with ICodeCompiler is more sophisticated than just using VBScript. The kind of "scripting" you want to do is much different, and is NOT called "VBScript." What you are doing is actually called programmatic compilation and you are actually compiling real Visual Basic code at run-time.
On the other hand, VBScript is a scripting language hosted by a scripting engine (usually Windows Script Host - a.k.a. WSH). And that's what my example uses. It has a much more relaxed and dynamic syntax.
Visual Basic, is a full .NET compiled language. It has strong types and is a "real" programming language. Ok, stop laughing. ;)
THis is different again from VBA (Visual Basic for Applications) (something I haven't mentioned until now) which is a different language that can be used to automate applications. It also includes an editor and debugger. You've seen it used for "macros" in apps like Word and Excel, and even Visual Studio's macros.
They are all intentionally designed with very similar in syntax (You could think of them as different dialects of Visual Basic), but they all have different specifications and purposes.
Sorry I didn't pick up on this early on. Hopefully this clears some things up. It might help if you only say VBScript when you actually mean VBScript.
Monday, August 29, 2011 3:57 PM
Thanks for that very helpful and detailed explanation. Sorry for any confusion I caused.
I had a VSA example, but then VC# marked the usage of some of those objects as deprecated and recommended not using them. So, I need to find another way to provide scripting (using VB Script). I think that is what you provided...very helpful.
Does the script execute each (line by line at a time) in the script.ExecuteStatement call? So, the script is not compiled prior to execution, right?
UPDATED MESSAGE: I think I figured out how to get to the line number, but I need to cycle through all the error messages to update a list view control with messages and error line numbers. Any help is appreciated.
Also, do you know of or can you point me to an example that shows debugging of the VBScript (such as single stepping capabilities, breaking, etc.)?
I greatly appreciate your help so far...tremendously useful.
Thanks.
Tuesday, April 10, 2012 1:00 AM
Hi guys....
When I run VBScript file with the following as suggested:
thing.Test "Hello from script"
MsgBox("Test script " & thing.GetOtherValue(2,2))
I get an error:
Error: Object required: 'thing'
Any ideas as to why this is happening to me??
Thank you
Thursday, April 12, 2012 12:58 PM
If you were just typing in things without thinking about it you might have "myThing" vs "thing" maybe? There's only one variable intended here.
Show the code where you created "thing" and assigned it a value.