|
Nick Parker wrote:
what you need to understand is that you can't write an assembly in C# and then simply write a VBScript file where you can call CreateObject and use your C# classes within the VBScript.
Maybe I'm not making myself clear. I don't want to access my C# code from VBScript, I want to do the opposite. I want to invoke a method in my VBScript from inside my C# code. I'm not trying to create a com object to run my .Net stuff, I know better than that!
I have seen examples on msdn (using Windows Scripting host setting up your script to be read as a COM object, using VSA by attempting to compile and run a script, trying to figure out how to pull in WSH into my code) but I can't figure out which of these ways are valid, reasonable solutions(or if none of them are).
I guess what I was trying to say is if I used JScript as my scripting language (which runs on CLR as far as I know), then I can use the .Net namespace System.CodeDom (inside my c# code)in order to run the script. Is that correct?
Also, if I am attempting to read VBScript or some other scripting language, then I assume I have to use some other non-.Net scripting engine in order to compile and read the script. From what I understand of the past e-mails, this engine may only exist in COM terms and I will need to understand how to use com objects with .Net stuff.
If this is all wrong, please let me know!
thanks,
Johanna
|
|
|
|
|
Dear Johanna,
adding scripting capabilities to .NET programs is, indeed, possible.
There was an article on that subject in a german .NET magazine some time ago. Here's the link to a sample project (comments in german, though):
Scripting .NET
The sample shows how to set up a scripting host in your program, make objects available to scripts and how to load and execute JScript scripts to modify your application's behaviour.
If you have problems with understanding the code or comments, then drop me a line, I'll translate.
Regards,
mav
|
|
|
|
|
mav,
This example is *exactly* what I've been looking for! Now, I just hope I can get through the German enough to understand what the heck I'm doing! I appreciate your help! I was kind of under the impression that VSA might be the way to go!
Thanks again!
Johanna
|
|
|
|
|
You still need to expose your .NET components - your object model (OM) - as COM objects, though. You can embed the scripting engine (I never said you can't; only that .NET is not a script host itself and that scripting revolves around COM) because it itself is a COM component (so you create a CCW, or COM-Callable Wrapper), but in order for script to access your object model you have to expose COM objects.
I'm not sure why you stumbled into the CodeDom. What you need to read is Interoperating with Unmanaged Code[^].
Software Design Engineer
Developer Division Sustained Engineering, Microsoft
My Articles
|
|
|
|
|
Sorry to contradict, Heath!
The sample doesn't use COM interop to achieve scripting abilities. It revolves around Microsoft.Vsa.IVsaSite.
The application implements a scripting host and executes JScript scripts in this context.
Using IVsaGlobalItem the scripting host can publish objects to be used in the script (quite similar to what Word does in a VBA script when it exposes the global Application object, for example).
I'm thinking about writing an article on that subject when I have time...
Regards,
mav
|
|
|
|
|
mav.northwind wrote:
quite similar to what Word does in a VBA script when it exposes the global Application object, for example
The Application object is an OLE/COM automation object implementing IDispatch to provide late-binding.
.NET is the natural progressional of COM and if you expose an entire assembly to COM (use ComVisibleAttribute at the assembly level) then there's no problem, but this doesn't follow good COM programming guidelines and you will run into problems (re-ording the methods in a class, for example, can screw up both late- and VTBL-binding).
Now, if you had something to marshal calls to your assembly that was a managed host, then you wouldn't need to expose COM yourself. But like it or not - and trust me on this - script relies on COM 100% (automation) so something has to expose your .NET components to the script engine.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles]
|
|
|
|
|
Calm down Heath, I didn't want to doubt your overall expertise, we're just talking about two different things.
I just wanted to illustrate what I meant with global objects, I didn't say the mechanisms involved are the same.
Sure, deep down Word.Application implements IDispatch and VBA invokes the methods over this interface. I never said it wouldn't.
But from what I've seen while browsing through the sample code you _can_ publish objects to be accessable from a script executed by IVsaEngine. This is done by calling IVsaItems.CreateItem() and the object published does _not_ have to have a ComVisibleAttribute set to be usable in this context.
Sure, the objects "published" in this way will never be usable from a VBA macro or a WSH script, but I think that wasn't what johanna42 meant.
mav
|
|
|
|
|
I wasn't upset, but tend to get so when people tell me to "calm down".
If IVsaItems.CreateItem (or rather the implement of it) is exposing objects, then it - as I mentioned in my previous post - is marshalling calls from COM to .NET.
Trust me - script revolves and exists solely on automation. Not only do I speak from experience and from what's written in the Platform SDK documentation (among other places), I'm actually working with script source at Microsoft.
The fact is that script wouldn't work without automation. IDispatch is not "deep down" - it is the heart and soul of automation. It - along with ITypeInfo - exposes properties and methods of an object. This provides late-binding to script which calls IDispatch::Invoke with the DISPID of a member (cached or not) along with DISPPARAMS (basically an array of VARIANTs) and other information if necessary.
Every type in an assembly actually has a GUID associated with it. If you use the GuidAttribute , this GUID is fixed instead of assigned at compile time (whether you expose the type to COM or not). It very likely that the implementation of IVsaItems is using that GUID to create objects and to identify the class in order to marshal calls and expose type information (all of which can be easily done thanks to the type metadata).
This still relies on an automation layer, except that you aren't actually registering your coclasses and interfaces, nor a typelib.
Still, you can embed the script host and through the engine expose the objects so long as something is providing a class factory and is marshalling calls.
Scripting your application would only work within your application so long as it provides a root object (like the Application object) from which the OM flows.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles]
|
|
|
|
|
Heath, you sounded _a bit_ upset, but my "calm down" wasn't completely serious either (mark the smiley).
I suggest we end this discussion here because it's getting more and more academic.
Scripting relys on automation, agreed.
Using IVsaEngine in your application and exposing objects using IVsaItems.CreateItem() doesn't require you to think about how to automation-enable your objects' classes.
IVsaEngine may or may not use IDispatch internally to marshal calls to objects' members - it simply doesn't matter from a class user's point of view. With enough effort you or I could fire up reflector and prove one point or the other but right now I think it's useless effort, as long as an IVsaEngine implementation does what it's supposed to do.
Johanna42 got what (s)he wanted, and that's what this forum is all about, isn't it?
If you disagree then I suggest we'll continue this discussion in the general or COM forum, ok?
Best regards,
mav
|
|
|
|
|
|
Has anyone encountered a control (text box or RTF) which supports all of the great features of the RichTextbox control, but also supports drag-and-drop? For some reason, Microsoft exposes the drag and drop abilities only to themselves internally.
This signature left intentionally blank
|
|
|
|
|
|
Nick,
Heh heh ... I read all of the documents on drag-and-drop operations with the RichTextbox and how easy it is as well. Unfortunately, if you go into VSS and lookup RichTextBox.DragOver you will see the following message:
This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
As a result there is no way I can wire in my handlers since there are not events exposed.
And that is why I am looking for an alternative.
This signature left intentionally blank
|
|
|
|
|
Would something like this work?
public class RtbDerivitive : RichTextBox
{
public event DragEventHandler DragOver;
protected override void OnDragOver(DragEventArgs drgevent)
{
if (DragOver != null)
DragOver(this, drgevent);
base.OnDragOver(drgevent);
}
}
Judah Himango
|
|
|
|
|
He shouldn't need to subclass the RichTextBox to perform a simple drag and drop operation, see my example below.
- Nick Parker My Blog | My Articles
|
|
|
|
|
theRealCondor wrote:
As a result there is no way I can wire in my handlers since there are not events exposed.
Strange, it does work, I just tested this:
using System;
using System.Drawing;
using System.Windows.Forms;
public class test : System.Windows.Forms.Form
{
RichTextBox rtb;
public test()
{
InitializeComponents();
}
public void InitializeComponents()
{
rtb = new RichTextBox();
rtb.Location = new Point(0, 0);
rtb.Size = new Size(200, 250);
rtb.AllowDrop = true;
rtb.DragEnter += new DragEventHandler(rtbDragEnter);
rtb.DragDrop += new DragEventHandler(rtbDragDrop);
this.Controls.AddRange(new Control[] {rtb});
}
private void rtbDragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.None;
}
private void rtbDragDrop(object sender, DragEventArgs e)
{
int i;
String s;
i = rtb.SelectionStart;
s = rtb.Text.Substring(i);
rtb.Text = rtb.Text.Substring(0,i);
rtb.Text = rtb.Text +
e.Data.GetData(DataFormats.Text).ToString();
rtb.Text = rtb.Text + s;
}
[STAThread]
public static void Main()
{
Application.Run(new test());
}
}
- Nick Parker My Blog | My Articles
|
|
|
|
|
I cut and paste the code into a project here and it compiled (and accepted drop) correctly. So I went into my main project ...
I cannot see the drag/drop events in the property grid.
But I can program them by hand.
And the Browse(false) is set on these events!!!!
So they don't show up in Intellisense but they respond once coded.
So they are just removing them from the browser to keep people from using them. Which makes me think there may be a reason. No?
I'll see what happens...
This signature left intentionally blank
|
|
|
|
|
Just because the documentation says you shouldn't use it doesn't mean you can't - just be ready for errors. I've implemented IXmlSerializable on numerous occassions and the .NET Framework SDK says you shouldn't in .NET 1.0 and 1.1. In .NET 2.0 they are releasing the documentation for it, but it really wasn't hard to figure out.
The documentation isn't the thing that you should be looking at anyway. Open ildasm.exe in the .NET Framework SDK Bin directory or use .NET Reflector[^] and take a look at the actual code (the IL instructions or the best-guess decompilation in whatever languages .NET Reflector currently supports or are provided through add-ins). That's the only way to know for sure.
Software Design Engineer
Developer Division Sustained Engineering, Microsoft
My Articles
|
|
|
|
|
Heath Stewart wrote:
I've implemented IXmlSerializable on numerous occassions and the .NET Framework SDK says you shouldn't in .NET 1.0 and 1.1.
Hey, I've done that too, mine was because Javier asked me for a way to serialize a Hashtable to XML.
- Nick Parker My Blog | My Articles
|
|
|
|
|
I've been looking at how to change the password of an Active Directory user in a C# application. I've seen many examples of code that create a DirectoryEntry object for the user and then Invoke("setPassword","newPassword"); . While this is useful, I can't help wondering where they are getting this information from. I haven't, yet, been able to find where I get a list of the methods I can "invoke" on a DirectoryEntry of an Active Directory User, or any other Active Directory object.
Perhaps, because I'm new to actually using Active Directory, I'm just looking in the wrong place. And, although I can do the job I need to based on the sample code I've seen, I still want to know how it is actually working.
Would someone be good enough to point me in the right direction?
"If a man empties his purse into his head, no man can take it away from him, for an investment in knowledge pays the best interest." -- Joseph E. O'Donnell
Not getting the response you want from a question asked in an online forum: How to Ask Questions the Smart Way!
|
|
|
|
|
|
Thanks, I'll definitely have a look at that in more detail when I get in to work tomorrow morning.
"If a man empties his purse into his head, no man can take it away from him, for an investment in knowledge pays the best interest." -- Joseph E. O'Donnell
Not getting the response you want from a question asked in an online forum: How to Ask Questions the Smart Way!
|
|
|
|
|
How are you drawing onto the picture box?
You can easily save the image with custom drawn stuff:
Image img = ...;
Graphics g = Graphics.FromImage(img);
g.DrawString(...)
g.DrawLine(...)
g.Dispose();
now you're image has the stuff you have drawn on it, so you can do:
img.Save(filename);
if you don't want to change the original image you can do:
Image img = ...;
Bitmap bmp = new Bitmap(img.Width, img.Height);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(img, 0, 0, img.Width, img.Height);
... other drawing stuff
g.Dispose();
bmp.Save(filename);
|
|
|
|
|
I tried that, I keep getting an out of memory exception...
not sure what to do
You Know We Non-Stop
|
|
|
|
|
What file format are you saving it as?
There is a bug that won't let you save it to file png files.
Try using:
img.Save("file.bmp", ImageFormat.Bmp);
|
|
|
|