Click Here to Install Silverlight*
United StatesChange|All Microsoft Sites
MSDN
|Developer Centers|Library|Downloads|Code Center|Subscriptions|MSDN Worldwide
Search for


Advanced Search
MSDN Home > MSJ > May 1997
May 1997


Investigating Multilanguage Debugging and the New IDEs of Visual Studio 97

Multilanguage debugging is nothing new, even from Microsoft. So what is new? Visual Basic shares the same code-generating back end as Visual C++. Translation: Visual Basic can now produce COM-aware native code executables and symbolic information (PDB) files.

Robert Schmidt

Code for this article: Debugging.exe (26KB)
Robert Schmidt is a contributing editor to C/C++ Users Journal, a member of the ANSI/ISO C committees, and a regular speaker at the Software Development Conference. You can reach him at rschmidt@netcom.com.

Microsoft® Visual Studio 97 integrates several programming languages into one behemoth development package (see Mary Kirtland’s article in this issue for details). What may not be so obvious is that you can now code different parts of a project with different languages and debug those parts simultaneously. The secret rests on three conditions: each language’s translator must emit the same native code set so that both translated pieces share an execution context; each language must emit the same symbolic information so that each piece can interpret the other’s source context; and each language must support the same binary protocol so that each piece can transfer control to the other.
Now, multilanguage debugging is nothing new, even from Microsoft. You’ve been able to mix high-level and assembly language sources for ages. Every commercial C++ compiler I’ve used also supports C and allows both languages to coexist in a project. And with the advent of COM, Microsoft officially sanctioned multilanguage support at runtime so that an interpreted LISP application can reference a C++ object without either piece knowing (or caring) how the other was written.
So what is new? First, Visual Basic® shares the same code-generating back end as Visual C++®. Translation: Visual Basic can now produce COM-aware native code executables and symbolic information (PDB) files. Second, SQL Server data and stored procedures can be wrapped within Developer Studio data projects that support symbolic debugging. Third, Visual J++™ Java-based projects also live within Developer Studio, support symbolic debugging, and can implement and call into COM interfaces.
To demonstrate, I’ll walk you through the construction and debugging of a simple stock purchasing system. The UI is a Visual Basic-based application containing a stock transaction component object DLL written in C++. This component records the transactions in a SQL database. Once I show you how to build the pieces, I’ll analyze several different methods for debugging the combination and summarize the costs and benefits of each method. I’ll finish with a discussion of Java’s implications and some final observations.

Caveats

The three pieces—container, component, and database—are the foundation for exploring multilanguage debugging and the new Visual Studio integrated development environments (IDEs). They are not designed as a tutorial in programming style or as a study in transaction programming. I will spend a fair amount of time explaining how the IDEs build and use the source files, and how the built pieces flow together. I will spend almost no time analyzing the actual programs themselves.
A brave few at Microsoft have provided me with almost all the code you’ll see here. They wrote it to demonstrate cross-tool development in general, not multilanguage debugging in particular. I’ve made some cosmetic changes to accommodate MSJ’s code-listing format and altered some names to better represent this article’s language-centric view.
Visual Studio contains several new language components and development features. Those required to understand multilanguage debugging I will discuss in detail; others that are simply a means for producing the demonstration system I will gloss over, including the Active Template Library (ATL), the Microsoft Interface Definition Language (MIDL), and the Microsoft Transaction Server (MTS), formerly codenamed Viper.

Getting Started

According to Microsoft, the demo runs on Windows NT® 4.0 only and assumes you use a single computer with at least 32MB of RAM. You also need the Visual Studio Enterprise Edition with these components installed, in this order, from the Visual Studio Master Setup:
  1. Run Setup for Visual Basic Enterprise Edition. Install with the standard features and options.
  2. Run Setup for Visual C++ Enterprise Edition. Install with the standard features and options.
  3. Click the Visual C++ Server Components, then run setup for SQL Server 6.5. Install with the standard features and options, and install the database on the local machine. Microsoft recommends you leave the system administrator (sa) password blank.
  4. Click the Visual C++ Server Components, then run setup for Visual C++ Server Components. Install with the standard features and options.
  5. Click the Visual C++ Server Components, then run setup for SQL Server Service Pack 2. Install with the standard features and options.
  6. Run Setup for Transaction Server. Choose the development addition and the Visual Basic Add-In.
For the remainder of this article, I assume you have downloaded but not yet installed the complete source code archive for this article. As I walk through each piece of the demo, I’ll show you how I created that piece from scratch. That way, you can adapt the techniques to your own real projects. After I’ve shown what you can generate from wizards and the like, I’ll then have you patch in the hand-generated or hand-modified pieces from the source code archive.
I also assume the demo project source folders you create will live within the common folder C:\MSJ_debug_demo. If you decide to use a different root folder name, please substitute that name for C:\MSJ_debug_demo in the following descriptions.

Creating and Configuring the SQL Database

This demo stores stock purchasing information in a SQL database. To install this database:
Figure 2: Project Data View
Figure 2: Project Data View
  1. From the code archive, copy InstSamp.SQL (see Figure 1) to C:\MSJ_debug_demo.
  2. From the taskbar’s Start button, find the Microsoft SQL Server™ 6.5 group and open the ISQL_w application.
  3. Assuming you have just installed SQL Server on your machine, you need to create a local connection. In ISQL/W, choose File | Connect, select Use Trusted Connection as Login Information, and click the Connect button.
  4. Still within the ISQL/W application, chose File | Open, select the InstSamp.SQL file you installed in step 1, and click OK. You now see a Query window filled with the contents of InstSamp.SQL.
  5. Select Query | Execute. In the Results tab of the Query window, you’ll see status messages as the database installs. Once the message "Ending InstSamp.SQL" appears, the installation is complete.
  6. Exit the ISQL/W application.
Next, you must configure the newly created database:
  1. Open the Control Panel and double-click the ODBC icon. Select the System DSN tab and click the Add button. Select SQL Server from the list box and click Finish.
  2. Enter VCEESamples as the Data Source Name, select (local) as the Server name, then click Options. In the Login group, enter VCEESamples as the Database Name.
  3. Click OK in the ODBC SQL Server Setup dialog, and OK to the ODBC Data Source Administrator dialog. Exit Control Panel.

Creating the SQL Database Project

To create the data project managing your new SQL database:
  1. Run Developer Studio and select File | New. From the dialog, select the Projects tab.
  2. On the Projects tab select Database Project. Enter C:\MSJ_debug_demo as the Location, SQL_database as the Project name, and select Create new workspace. Click OK.
  3. In the Select Data Source dialog that displays, select the Machine Data Source tab, highlight VCEESamples as Data Source Name, and select OK.
  4. In the resulting SQL Server Login dialog, select your SQL Login ID and Password, then click OK.
  5. Select File | Save Workspace.

Figure 2 (below) shows the resulting Data View, while Figure 3 summarizes the files in your SQL_database folder. In Figure 2, the name in parentheses is your server name. I’m using Dave Edson’s computer—hence the server name DAVEE1.

Creating the C++ Component

The C++ component is born from an application wizard:
  1. Run Developer Studio and select File | New.
  2. In the resulting dialog, select the Projects tab. On that tab, select ATL/COM AppWizard from the listbox. Enter C:\MSJ_debug_demo as the Location, CPP_component as the Project name, and elect to create a new workspace.
  3. In the AppWizard dialog select Server Type of DLL, and turn on the check box that allows merging of stub/proxy code. Select Finish in this dialog and OK in the next New Project Information dialog.
Your new project folder contains sixteen files. Of these, three (Resource.h, StdAfx.cpp, and StdAfx.h) are the traditional AppWizard boilerplate files, nine (CPP_component.*) form the new project, and four are the merged ATL proxy. I summarize the CPP_component.* files in Figure 4 and the proxy files in Figure 5. Figure 6 shows the Developer Studio FileView itemizing the new source files.
(For the morbidly curious, the proxy files arbitrate control flow between two objects that may not be directly accessible to each other. This is more a COM topic than anything else, and I won’t explore it in this article.)
Figure 6: Wizard-Generated Files
Figure 6: Wizard-Generated Files

Figure 4 and Figure 5 mention Interface Definition Language (IDL) files and the corresponding MIDL compiler. In essence, IDL expresses COM interface information you’d traditionally put in a C or C++ header. Now that Visual Studio supports COM interfaces in multiple languages, and considering that COM has been ostensibly language-independent all along, Microsoft apparently reckoned they needed a language-independent representation for those interfaces.
However intuitively IDL may express interfaces to humans, it doesn’t do C++ compilers a lick of good. So Microsoft also provides the MIDL compiler to convert IDL files into a form digestible by Visual C++. As you build the project, the MIDL compiler will generate CPP, H, and TLB files from CPP_component.idl.

Building the C++ Component

The source generated by the ATL COM AppWizard, like that of application wizards everywhere, is the barest boilerplate. To make this baby crawl, add these source files: CAccount.cpp, CDBStock.cpp, CRow.cpp, CShares.cpp, CStock.cpp, and CTrades.cpp. Also add their collateral headers from the archive for a total of 12 new files. These files form the glue between the Visual Basic container application and the MTS layer abstracting SQL.
Figure 7: Your finished workspace
Figure 7: Your finished workspace

Once you’ve added all the new files to your project, your workspace FileView should look like Figure 7. You will also need to replace three wizard-generated files—CPP_component.cpp, CPP_component.idl, and StdAfx.h—with those from the code archive. In each of these three source files, I’ve flagged new lines with /** **/ comments to help you see the changes.
Make sure the Build tab is visible in the Output window, then select Build | Rebuild All. After deleting the (currently nonexistent) intermediate and output files, the IDE runs the MIDL compiler. In the Build window you’ll see the compiler process CPP_component.idl, making reference to other IDL files (oaidl.idl, objidl.idl, and so on) along the way.
Once the build completes you’ll find five new files in your project directory; I summarize these files in Figure 8. Earlier I suggested that the MIDL compiler would translate CPP_component.idl into several Visual C++ source files during the build. Three of the files are cited in Figure 8 as the result of that translation. In addition, the existing file, CPP_component.h, which was generated empty by the AppWizard, has been altered by the IDL translation.
In the FileView, you’ll see three of these MIDL-generated or altered files showing up as external dependencies (see Figure 9). Figure 10 shows the important parts of the CPP_component source code.
Figure 9: MIDL-Generated Files
Figure 9: MIDL-Generated Files

In what I’m sure is no surprise, you have a new Debug folder containing your built binaries. Also, after you save the workspace, the IDE generates the workspace options file CPP_component.opt. Finally, during the build, the RegSvr32 tool registered your type library, CPP_component.tlb. You’ll see the Visual Basic container referring to this library very soon.

Configuring Microsoft Transaction Server

I said I’d just gloss over the new Microsoft Transaction Server. Unfortunately, to make the demo work, you must make MTS cognizant of your new C++ component:
  1. Open the Transaction Server Explorer.
  2. Double-click the icon representing your computer, then double-click on the Packages Installed icon.
  3. From the menu select File | New. In the resulting Package Wizard dialog, click "Create an empty package".
  4. In the Create Empty Package dialog, enter CPP_component as the package name.
  5. In the Set Package Identity dialog, select Interactive user, then click Finish.
  6. Once back to the main Transaction Server Explorer window, double-click the CPP_component package, then double-click the Component icon.
  7. Select File | New from the menu. In the Component Wizard dialog, click "Install new component(s)."
  8. In the Install Components dialog, select Add files and browse to (or directly enter) the debug version of the C++ component. The path name is C:\MSJ_debug_demo\ CPP_component\Debug\CPP_ component.dll. Click Open.
  9. Once the Select file to install dialog disappears, the Install Components dialog should look like Figure 11. Click Finish.
Figure 11 Install Components Dialog
Figure 11 Install Components Dialog

  1. In the Transaction Server window, right-click on the Stock.Stock.1 component icon and choose Properties.
  2. On the Transaction tab, click the Supports Transactions button.
  3. On the Activation tab, turn on the first three check boxes and turn off the fourth, so the result looks like Figure 12. Click OK.
Figure 12 Activation Parameters
Figure 12 Activation Parameters

If you are the Curious George type, double-click in succession the Stock.Stock.1 component, the Interfaces folder, the IStock interface, and the Methods folder. The C++ component implements these methods in class CStock. You'll see entries for the COM IUnknown methods, those methods particular to the stock transaction class (Buy, Sell, and so on), and IDispatch methods (since IStock, the interface CStock implements, derives from IDispatch). I mention all this to show that, even though the Microsoft Transaction Server setup may seem like a hassle, the end result actually makes sense. Visual Studio's online help has plenty of documentation on the Transaction Server, and I encourage you to browse there to learn more.

Creating and Building the Visual Basic Container

Unlike the C++ component, you create the Visual Basic container application without a wizard:

  1. Create the folder VB_container inside C:\MSJ_debug_ demo. Copy VB_container.frm from the code archive into this folder.
  2. Run the Visual Basic IDE. If the New Project dialog doesn't pop up, bring it up by selecting File | New Project. In the New Project dialog choose Standard EXE. The IDE presents the typical Visual Basic default Form1.
  3. Select Project | Add Form. In the Add Form dialog, select the Existing tab, then open C:\MSJ_debug_demo\VB_container\VB_container.frm.
  4. If the Project Explorer window is not visible in the IDE, select View | Project Explorer to bring it up.
  5. In the Project Explorer, right-click on the icon Form1 (Form1), then choose Remove Form1 from the popup menu. The Form1 window will disappear from the middle of the IDE.
  6. Still in the Project Explorer, right-click on the icon Project1 (Project1) and select Project1 Properties from the popup menu.
  7. Select the General tab of the resulting dialog, change the Project Name to VB_container, and change the Startup Object to VB_container_.
  8. On the Make tab, change the Application Title to VB_container.
  9. On the Compile tab, choose the Compile to Native Code, No Optimization, and Create Symbolic Debug Info options. Click OK.
  10. From the menu, select Project | References, scroll down the resulting list box until you find CPP_component 1.0 Type Library, check that item, then click OK. This is the type library you created in the C++ project earlier.
Building the application is comparatively simple:
  1. Select File | Make VB_container.exe, specify C:\MSJ_ debug_demo\VB_container\VB_container.exe as the target file, and click OK.
  2. You'll see a status bar flash near the top of the IDE as it compiles, then writes, the executable.
  3. In your VB_container folder you should have six files as summarized in Figure 13.
You now have all the pieces in place to run the debugging demonstration.

On with the Show!

In the following section, I'll show you three different multilanguage debugging methods: staying completely within the Visual Basic IDE, staying completely within the Developer Studio IDE, and using both IDEs. No single method is likely to serve all your needs all the time. However, I'm hoping you can combine these methods well enough to suit most debugging problems.

Debugging in the Visual Basic IDE This method is the easiest: do all debugging in the Visual Basic IDE. To see the demo in action, fire up the Visual Basic IDE, select File | Open Project, and open VB_container.vbp. In the Project Explorer, double-click on the VB_container form icon. This brings up the main VB_container UI in the IDE. Double-click on the form to bring up the form's code.
Search the code (there isn't much) and set breakpoints on these two lines:


 CPP_component.Buy account, stock, shares, price
and

 Set CPP_component = New CPP_COMPONENTLib.CStock
Now hit F5 to start debugging the application. The debugger breaks straightway on the line:

 Set CPP_component = New CPP_COMPONENTLib.CStock
What is CPP_COMPONENTLib? If you look in CPP_component.idl you'll find the line:

 library CPP_COMPONENTLib
Remember, the IDL file turned into (among other things) the type library CPP_component.tlb. CPP_COMPONENTLib is the type library's logical name. Later in the library section of the IDL file you see

 coclass CStock
which accounts for the Visual Basic reference to the type CPP_COMPONENTLib.CStock.
If you now try to step into the code (F8) you may be surprised—instead of tracing into the C++ component, you see a momentary pause (while the component is loaded) before control passes to the next Visual Basic line. This is much like debugging C++ calls into the Windows API; if you don't have source, the call is opaque and you can't see into it. Here, you do have source, just not the right kind. Visual Basic knows how to trace into Visual Basic, but does not know how to trace into C++. In this regard, nothing's really changed from earlier versions of Visual Basic. The biggest gain is that the Visual Basic-based application is native, resulting in much faster execution. For your purposes, it means the application fails to trace into C++ faster than an interpreted application would fail to trace.
Actually, if you're a seasoned Visual Basic programmer, there are other advantages—you stay in your familiar IDE and can generate interpreted code instead of native code, which makes for faster edit/debug cycles. However, where programmers familiar with Visual Basic may be at home, C++ programmers may feel lost. I know I'm far from adept in the Visual Basic IDE, so I personally don't consider this method advantageous.
Figure 14 VB_Container
Figure 14 VB_Container

Hit F5 to continue debugging. After pondering a bit longer, the IDE presents you with the container application's UI (see Figure 14). Select the Purchase tab (which should be the default) and fill in the fields as follows: enter a nonzero integral Account Number, a character string Stock name, an integral count of Shares, and a real share Price.
Remember, this is a demo, not a production-quality application. It does a fair amount of checking against the database's integrity and permissions, but almost no input validation; if you feed it bogus data, it may die horribly.
Once you've filled in the fields, click the Purchase button. You'll see a progress bar start to fill, followed by the debugger stopping at the breakpoint on

 CPP_component.Buy account, stock, shares, price
If you once again crack open CPP_ component.idl, you'll see the line:

 HRESULT Buy([in] long lAccount, [in] BSTR bstrStock,
             [in] long lShares, [in] double dblPrice);
This declaration matches the name and argument list of the CPP_component.Buy call. Both the programmer implementing the interface in C++ and the programmer calling the interface in Visual Basic can use the IDL as a common frame of reference. I suspect this is one motivation for IDL; it offers a language-neutral interface expression equally arcane to all programmers.
Hit F5 again. Your machine will grind a bit as VC_container calls into CPP_component, which in turns interacts with the SQL database. After a few moments, the progress bar goes to 100 percent and you'll see a small message box proclaiming Purchase Complete. Click OK. The dialog and progress bar go away, and you're back to the regular UI.
I trust you get the idea, so I won't bother tracing through the other two tabs and their CPP_component calls. Feel free to experiment, although be forewarned that the Commission tab is a little hokey as written—it always seems to return a commission of zero. Also, remember where you set these two breakpoints since you'll need them later.
In summary, debugging in the Visual Basic IDE offers several benefits. It provides a familiar environment for programmers used to working with Visual Basic. In addition, it can use interpreted p-code, speeding the development cycle. However, it's an unfamiliar environment for programmers who don't use Visual Basic much, and you can't trace into components written in other languages.

Debugging in the Developer Studio IDE Since the EXE and PDB files Visual Basic produces are compatible with those Visual C++ produces, you can actually load and debug Visual Basic-based applications within the C++ environment. That's the good news. The bad news is, while C++ source can be read by generic text editors, Visual Basic source is a form of rich text with code and properties formatted in a way that only Visual Basic can properly parse. When you import a Visual Basic form into Developer Studio, the code and properties are translated into plain text and you lose the form's visual representation.
To try this out, stop VB_container and the Visual Basic IDE (if they are still running), launch Developer Studio, and open VB_container.frm (see Figure 15). Most of the file consists of property information. Scroll to the bottom and find the same code you saw in the Visual Basic IDE. Set breakpoints on the same two lines


 CPP_component.Buy account, stock, shares, price
and

 Set CPP_component = New CPP_COMPONENTLib.CStock
that you set earlier. Notice VB_container.frm's lack of syntax coloring? Developer Studio can't parse forms and treats them like any other nonsource text file, to the point of letting you set breakpoints on comments and empty lines.
Next, open CStock.cpp and set a breakpoint on the constructor:

 CStock::CStock()
     {
 m_dblCommission = 0.0; //set
                        //breakpoint
                        //here
     }
Because CPP_container is a DLL, you must bind it to an executable for debugging. From the menu select Project | Settings, go to the Debug tab, enter C:\MSJ_debug_ demo\VB_container\VB_container.exe as the Executable name, and click OK.
Hit F5 in the IDE to start debugging VB_container. After a few moments the debugger should break on

 Set CPP_component = New CPP_COMPONENTLib.CStock
just as it did in the Visual Basic IDE. Bring up the call stack window (View | Debug Windows |Call Stack). The first few lines look something like this:

 VB_container_::Form_Load() line 479
 MSVBVM50! 0f0349b8()
 __vba@0018057C + 3683 bytes
 MSVBVM50! 0f034992()
 MSVBVM50! 0f0348b6()
 MSVBVM50! 0f0435b1()
The first line is the VB_container.frm breakpoint. Note how the call stack represents this in class::method form, as if it were C++ code. I'm guessing the third line is Visual Basic startup code, analogous to __astart in the C++ runtime. The rest is other Visual Basic runtime context for which you don't have symbols.
If you are truly masochistic, go to the menu, select View | Debug Windows | Disassembly, then double-click on the first line in the call stack. You'll see Visual Basic source mixed with assembly:

 479:     Set CPP_component = New CPP_COMPONENTLib.CStock
 004047A8   push        offset ___vba@00182FAC(0x00402b0c)
 004047AD   call        ___vbaNew(0x00401130)
 004047B2   push        eax
 004047B3   lea         eax,dword ptr [unnamed_var1]
 004047B6   push        eax
 004047B7   call        @__vbaObjSet(0x0040118a)
After sating your assembler lust, close the Disassembly window.
Figure 16 Call Stack
Figure 16 Call Stack

Hit F5 to continue. After thinking a spell, the IDE will break on the CStock constructor. The Call Stack window (see Figure 16) is now much more interesting. The first line, of course, is the CStock constructor (the latest breakpoint). The next four lines are ATL wrapper calls—the last of these is the most impressive (aren't C++ templates wonderful?). After the ATL calls come a few without symbols, then the Visual Basic code you broke on originally.
Hit F5 again. The now-familiar VB_container UI comes up. Select the Buy tab, fill in the fields as before, and click Purchase. The debugger once again breaks in VB_container.frm

 CPP_component.Buy account, stock, shares, price
while the call stack shows

 VB_container_::Purchase_Click() line 437
 MSVBVM50! 0f0349b8()
 __vba@0018057C + 3644 bytes
The last time you were here, you couldn't step into the CPP_component.Buy call. This time, fortune favors the foolish—press F11, and you find yourself at the first line of CStock::Buy. The call stack changes to:

 CStock::Buy() line 19
 VB_container_::Purchase_Click() line 437 + 35 bytes
 MSVBVM50! 0f0349b8()
 __vba@0018057C + 3644 bytes
If you didn't already know from the names, you couldn't tell by looking at this stack which call is Visual Basic and which is C++.
At this point, you can hit F5 to continue, then close the VB_container application. Remove the VB_container.frm breakpoints, but leave the ones in CStock.cpp. You'll need them set for the next exercise.
I did find a few glitches while testing this method. First, remember that SQL_database project you created? If you open the project from Developer Studio, you can set breakpoints in sp_validaccount (the only stored procedure in this demo). The syntax coloring and breakpoint control work just as you'd expect. In theory, you can also trace into the stored procedure from the IDE. However, try as I might, I was unable to get the traces to work. I was able to set the breakpoint, but never saw the breakpoint hit. Microsoft confirmed this should work. My only guesses are that either a beta bug bit me, or the Visual Studio Enterprise Edition was installed incorrectly (Microsoft provided me a machine with all software preinstalled).
Second, because Developer Studio doesn't really understand Visual Basic source, it can't adjust breakpoint placement when that source changes externally. If you set Visual Basic breakpoints in Developer Studio, change the form in the Visual Basic IDE, then reload the form into Developer Studio, you may find the breakpoints are on the same absolute line numbers but not on the actual statements you wanted.
Third, as I tested this method, the MTS calls within CPP_component occasionally failed. I never found the cause, but I did find some cures: reinstall CPP_component within the Transaction Server Explorer, rebuild CPP_component, or restart Developer Studio. From what I can tell, some registry values (or some runtime piece's cache of those values) became corrupted. This may have been an artifact of my using beta software. Nonetheless, if you find calls that used to work suddenly failing, you may want to try these solutions.
The bottom line is, using the Developer Studio IDE means you can debug assembler, C, C++, Visual Basic, and (in theory) SQL stored procedures simultaneously from the same IDE session. It's also the most familiar environment for C++ programmers. On the other hand, Developer Studio doesn't have the Visual Basic environment's interactive context. Visual Basic source manifests as text only, and the IDE is unfamiliar to folks who use Visual Basic exclusively.

Debugging in Both IDEs To combine aspects of the previous two methods, you can run both IDEs simultaneously. However, the setup involves a twist compared to what's come before.

  1. In Developer Studio, open the CPP_component workspace. Ensure that the two breakpoints from the previous exercise in Developer Studio are active. Select Project | Settings, then select the Debug tab. Here's the twist: last time you chose VB_container.exe as the debugging executable; this time choose the Visual Basic IDE itself.
  2. Enter the absolute path name of the Visual Basic IDE as the debug session executable. On my machine, that file is C:\Program Files\DevStudio\VB\vb5.exe.
  3. Enter C:\MSJ_debug_demo\VB_container as the working directory.
  4. Enter VB_container.exe as the program argument.
The net result is that Developer Studio spawns Visual Basic, which in turn spawns VB_container within the VB_container home directory. Figure 17 shows how the Project Settings dialog should look. Once you're satisfied you've set it up correctly, click OK on this dialog.
Figure 17 Project Settings Dialog
Figure 17 Project Settings Dialog

If the Visual Basic IDE is running, close it—you need it running as a child of Developer Studio, not standalone. In Developer Studio, hit F5 to start debugging Visual Basic. Depending on how Developer Studio is configured, you may get a message warning that vb5.exe lacks debugging information. Unless you work for Microsoft, subcontract to Microsoft, or engage in industrial espionage, you probably don't have access to the vb5.exe source, so press OK on this dialog.
Once Visual Basic is running, reset the breakpoints you set in the first exercise (debugging in Visual Basic), then hit F5 to debug VB_container. You should soon hit the breakpoint on

 Set CPP_component = New CPP_COMPONENTLib.CStock
Hit F5 again. Control passes to the Developer Studio IDE, breaking on the CStock constructor just as in the second exercise. Take a look at the Developer Studio call stack:

 CStock::CStock() line 9
 [... ATL calls removed]
 OLE32! 77b2c7f1()
 OLE32! 77b2c8db()
 OLE32! 77b2c6eb()
 VBA5! 0fab3181()
 VBA5! 0fbdfd52()
 VBA5! 0fbdfcf9()
 VBA5! 0fbdd0f0()
 VB5! 00481425()
Compare it to the one shown in Figure 16. When debugging in Developer Studio, you were able to see symbols for both CPP_component and VB_container. Now you can see symbols for only the former; VB_container calls show up generically as addresses in VBA5 or VB5.
If you try to go back to the Visual Basic IDE, you may be in for a surprise: you can't activate it. That IDE is just like any other debugged program; once you hit a breakpoint, the debuggee (Visual Basic) freezes and control passes to the debugger (Developer Studio).
Within Developer Studio, hit F5. The Visual Basic IDE thaws, and you eventually see the VB_container UI. At this point, both IDEs and VB_container are active. Fill in the VB_container Purchase form as usual and press the Purchase button. As expected, you break once again in Visual Basic at

 CPP_component.Buy account, stock, shares, price
All three applications are still active. If you now hit F8 (Step Into) from Visual Basic, you land in the other IDE at CStock::Buy. Compare this to the first exercise, where the same Step Into didn't work (the call was opaque). As a side effect, the other two applications once again freeze.
Hit F5 in Developer Studio and control stops in Visual Basic! Remember, you stepped into the C++ code from Visual Basic. Once that C++ code returns, Visual Basic steps to its next source line.
I assume you get the gist, so go back to Developer Studio and stop the vb5.exe debugging session (Shift+F5). Both the Visual Basic IDE and VB_container disappear. Exit Developer Studio.
As I worked through this, I found myself occasionally losing track of which IDE I was in. More than once, I tried to use a Developer Studio keystroke in Visual Basic, and vice versa. I became disoriented by the Visual Basic context alternately freezing and thawing, and by having to remember the state of each IDE as control passed from one to the other.
I also received a low virtual memory warning from Windows
® NT on a 32MB system. These IDEs are memory gluttons; running one is bad enough, but running two (plus Word, as I am for writing this article) turns Windows NT into a hard drive thrash-o-matic. I recommend that you close all nonessential applications and consider running on a machine with more than 32MB of RAM to pull off this method of debugging.
Once the dust settles, this method allows each executable piece to live within its most natural environment. However, it requires a more complex setup; you must have both IDEs running, and you must coordinate control and settings between them. Plus, Visual Basic context freezes when control passes to Developer Studio, and it's RAM-intensive.

Whither Java?

Not wanting to leave you in the lurch, I whipped up a quick Java applet to see if the same techniques work. The source is quite simple:


 import cpp_component.*;

 public class Java_applet
 {
     public static void main(String args[])
  {
  IStock stock = (IStock) new
                 CStock();
  stock.getCommission();
  }
 }
To test this out, run Developer Studio and create a new Java project as C:\MSJ_debug_demo\Java_applet. Copy Java_applet.java from the code archive to this new folder and add the source file to the Java project.
Go into the IDE's Project Settings. On the Debug tab enter Java_applet as the class for debugging/executing, and specify the standalone interpreter. On the Java tab, turn on debugging info generation and turn off optimization. Click OK.
From the Tools menu, run the Java Type Library Wizard. Select CPP_component 1.0 Type Library (the same selection you made from Visual Basic in the first exercise) and click OK. This synthesizes the Java package cpp_component from the C++ component's type library. The package's class files are in C:\WINNT\Java\TrustLib\cpp_component along with a text file describing the package's methods.
To build Java_applet, set a breakpoint on

 stock.getCommission();
then hit F5. You'll see the Java interpreter (jview.exe) come up, followed by control passing back to the IDE at your breakpoint. Hit F11 to Step Into. Just as with Visual Basic, the call is opaque and control passes to the next Java statement. However, the lack of a thrown exception implies that the call to getCommission was a success.
Debugging both languages simultaneously is a different matter. Because Java generates neither EXE nor PDB files, debugging in Developer Studio alone doesn't work. I tried many variations of debugging both IDEs, to the point of hardcoding an INT 3 in CPP_component.dll. No dice—all I got was a second copy of jview.exe running in a debugger.
One of Java's selling points is that it parties within its own private Java Virtual Machine (VM) sandbox. A Java applet calls standard library methods; the Java VM interprets the methods' instructions, making real OS calls on the applet's behalf. The wizard-created class files seem to extend the Java VM's reach to COM objects.
For multilanguage debugging to work, some other language would have to play in the Java VM sandbox, and none of Microsoft's other languages currently do. That's my interpretation anyway; at the time I submitted this article for publication, Microsoft had neither confirmed nor denied the possibility of multilanguage debugging with Java.
Coda

Of the three debugging methods I surveyed, my choice is probably the second, debugging in the Developer Studio IDE. That stems in part from my experience with C++ and in part from the balance between features and convenience. Using Visual Basic is pretty ineffective for direct C++ debugging, while using both Visual Basic and Developer Studio requires a lot of bookkeeping (and RAM).
Assuming you have more luck with SQL debugging than I did, you can drive your language-choice decisions less on the strength of a language's development environment and more from that language's technical and strategic merits. I'm guessing Microsoft may revamp Visual Basic or Developer Studio so the two work seamlessly together. Now that C++ and Visual Basic use the same code generator back end, perhaps the time has come for them to coexist in the same development environment as well.
Java is another matter; the Java VM model may guarantee you'll never use these debugging techniques. I doubt anyone could port C++ to the Java VM without either constraining the language severely or extending the VM in proprietary (and unsafe) ways. As it is, I have to wonder about the security of Microsoft's current COM-enabled Java VM architecture. Microsoft could possibly target interpreted Visual Basic to the Java VM, provided it found a market there.
Alternatively, Microsoft may alter Visual J++ to emit native code, bypassing the Java VM. Given Java's more purely OOP semantics, and the fact that it lacks some of C++'s more treacherous features, I can envision a market cropping up for Java sans VM (call it caffeine-free). The International Organization for Standards (ISO) has recently formed the Java Study Group (SC22JSG) to explore the merit of and issues surrounding Java standardization. One of the group's big topics: should the Java language be standardized separately from the Java VM?
Microsoft is a big player in the study group at present. Don't be surprised if a future version of Visual J++ native-compiles. That, combined with my earlier guesses about Visual Basic melding with Developer Studio, would permit all Microsoft languages to live (and be debugged) under one roof.

From the May 1997 issue of Microsoft Systems Journal. Get it at your local newsstand, or better yet, subscribe.

© 1997 Microsoft Corporation. All rights reserved. Legal Notices.

© 2015 Microsoft Corporation. All rights reserved. Contact Us |Terms of Use |Trademarks |Privacy & Cookies
Microsoft