January 31, 2006
.NET Scripting Hosts, Part TwelveMark M. Baker
The ActivDbg.tlb file from the SDK is used to generate definitions of the Active Debugging interfaces, and the initial calls to setup support for debugging are added to our host.
In the previous issue in this series, we covered the Machine Debug Manager and Process Debug Manager components explaining why they are needed on any machine that has an application that wants to use the advanced Active Scripting debugging interfaces. If you haven't read that issue, I encourage you to stop here and go back and read it thoroughly. Otherwise, you may find that the code we are working on in this series won't run on your machine.
Up to now, we've been reviewing how these advanced debugging interfaces look and how they are attributed in .NET. As with the basic host interfaces, you need to be aware of the common problems that you can encounter with any kind of COM Interop, especially how data is marshaled. However, we can now make use of a Visual Studio .NET capability that will make our life a lot easier as we move along. We will use its ability to read a standard COM type library to generate the .NET interface, class, and enumeration definitions for all of the items.
If you recall, when Microsoft released the Active Scripting interfaces in the late 1990's they included them in a variety of SDK packages. Typically, the header file (.h) and IDL (.idl) files were included along with some simple documentation. As I mentioned in an earlier article in this series, creating a type library from the ActivScp.idl file proved to be problematic at best -- often the parameters weren't marshaled correctly and odd COM interop errors would result. So we spent time together writing out our own .NET versions of those interfaces. Interestingly, Microsoft decided back in 1997 to release the debugging interfaces with a type library, but not an IDL file! Fortunately for us, I'd much rather have the .tlb for the Active Debugging interfaces than the .tlb for the basic interfaces -- they are much more numerous and complex.
When I scanned my hard drive for ActivDbg.tlb in both Visual Studio .NET 2003 and Visual Studio .NET 2005 (including the SDK) I came up empty. No ActivDbg.tlb files were found. If you hit the Microsoft.com site looking for ActivDbg.h, you come across a knowledge base article referring you to the SCRIPTING.EXE package that includes the debugging interface header file and other assorted items, but no .tlb file. It turns out that you have to reach way, way back in time to the INetSDK that was released in 1997 for IE 4.01 to find the needed .tlb. Fortunately, this download is still available at Microsoft and can be found here. I highly recommend you get a copy of this SDK and put it someplace safe. I haven't found the needed .tlb anywhere else and there's no way to know if Microsoft may decide to remove this ancient SDK at some point in the future.
After installing the SDK, go to the \InetSDK\Include directory. You'll find the ActivDbg.h and ActivDbg.tlb files there and we'll need them for the next step. Within Visual Studio .NET, you can add a Reference to a COM library including a .tlb file. Visual Studio then generates a .NET interop layer for the items in that library for you to use. Simply go to References for your project, browse to the \InetSDK\Include\ActivDbg.tlb file and after a slight pause, you will get a reference to the items in the type library.
If you then right click on the new reference, click the Object Browser menu item to see the COM items that were detected. You'll notice all of the advanced interfaces, constants, and so on are now available to your application. So far, I haven't had any issue with the definitions that were generated, but we'll see if this holds as we move along.
To get a better idea of how the interfaces and other .NET code actually looks that was generated by Visual Studio .NET (and how it compares to the interface definitions we laid out), you can use reflection to disassemble the DLL that was created for the type library. Go to the \Bin\Debug directory for your project and you'll likely see a file named Interop.ProcessDebugManagerLib.dll. Next, you'll need a tool that can disassemble a .NET assembly and create a source code definition of what's there. A great (and free) tool that you can use to do this is Loet zRoeder's Reflector utility that you can find here. Download the tool and install it somewhere on your computer. Launch it and browse to the Interop.ProcessDebugManagerLib.dll file. Once Reflector opens it, navigate to the ProcessDebugManagerClass item in the tree listing of items. Right click and select the Disassemble menu item. You'll get a window showing you the code listing for this class which represents the PDM we discussed last time. Here is how it looks for me: |
|||||||||
|
You'll notice how Reflector interpreted the Interop assembly's definition of the PDM wrapper class. The most interesting aspect of this C# code is the marshaling specifications on each parameter -- in cases where a .NET interface is passed either as an in or out parameter it is marshaled as UnmanagedType.Interface. If a typeless IUnknown was requested by the original COM interface, a generic .NET object is passed that is marshaled as UnmanagedType.IUnknown. This is exactly as we've been talking about over this series -- knowing what marshaling attributes to apply is critical for COM Interop success.
Alright, with the type library properly imported into out project, we can begin updating our host to begin using the 3 initial interfaces in the debugging area -- IProcessDebugManager, IDebugApplication, and IDebugDocumentHelper. These interfaces are used to set up the debugger support within Active Scripting for your host. Let's get started:
Step 1 -- Include the namespace in the script host source file
using ProcessDebugManagerLib;Step 2 -- Create an instance of the Process Debug Manager ProcessDebugManagerClass pdmObject = new ProcessDebugManagerClass(); IProcessDebugManager pdm = pdmObject as IProcessDebugManager;Step 3 -- Create an "application" object via the PDM IDebugApplication da; pdm.CreateApplication( out da );Step 4 -- Set the name of the PDM application as the name of the host application da.SetName( "MyScriptHost" );Step 5 -- Create the debug document helper object via the PDM CDebugDocumentHelper ddhObject; pdm.CreateDebugDocumentHelper( null,out ddhObject );Step 6 -- Initialize the debug document helper object ddhObject.Init( da,"MyScriptHost","MyScriptHost",0 ); ddhObject.Attach( null );Step 7 -- Add the script text to the helper the same way we do for IActiveScriptParse.ParseScriptText string text = "Util.DoSomething();"; ddhObject.AddUnicodeText(text);Step 8 -- Define the size of the script text block and apply code attributes uint cookie=0; ddhObject.DefineScriptBlock( 0,(uint)text.Length, (ProcessDebugManagerLib. IActiveScript)ias,0,out cookie);
If you're read through the Active Scripting FAQ on my site then you've seen these steps listed for C++ code. They're basically the same for .NET. You include this new code during the initialization of your .NET scripting host before the call to ParseScriptText.
CMP DevNet .NET Cast
Whether you are moving to .NET from Win32 or have been using .NET since 1.0, I encourage you to listen to .NET Cast, an Internet radio show that I host and produce for CMP Media. Hear from the people behind .NET and key experts in the industry working with it. You can get CMP DevNet .NET Cast at devnet.developerpipeline.com/podcasts/dotnetcast/ or via RSS feed at syndication.sdmediagroup.com/feeds/public/cmp_podcast_dotnet.xml. Listen to the show and send feedback to me at dotnetcast@sunburstsoftware.com!
Do you have a passion for Scripting?
If you want to access the extensive exchanges between other developers about Active Scripting, head over to Google's archive of Usenet newsgroups and read through the microsoft.public.scripting.hosting group. If you're working with the newer .NET version of scripting, you might look through microsoft.public.dotnet.scripting.
Also, if you have questions about how to use Active Scripting, I'd encourage you to read through my Active Scripting FAQ document that covers a wide range of problems other developers have had and many useful answers from their experiences. You can find it here.
A rich source of material on Active Scripting, JScript and VBScript from a true Microsoft insider is Eric Lippert's blog.
Whether you're just getting started with .NET or you've been using it since it was in beta, check out my twice-monthly column "Windows/.NET Q&A" at www.ddj.com/columns/wqa/.
|
|
|||||||||||||||||||
|
|
|
|