What Is Mixed Language Programming?

From a conceptual point of view, MLP is about connecting together code, data, and components that have been constructed using different programming languages. (Did you know that most developers use an average of 2.2 language tools?) However, from a design point of view, MLP is also about choosing the right language up front for the job—the so-called Horses for Courses approach (that is, each language being employed for the purpose for which it is best suited)—and about building reusable code blocks.

One of the most popular approaches to developing components is to apply object-oriented techniques. Object-oriented analysis and design are useful because they enable application designers to approach software development from a higher level of abstraction. Viewing an application as a collection of objects (which have both attributes [state] and behaviors [method]) that interact with each other enables a designer to more effectively model the problem and create an appropriate solution. An object design should be more comprehensible than a series of algorithms. We'll be touching on more object "stuff" throughout this chapter.

In short, MLP lets you take advantage of language-specific features and data structures available in languages outside your main language. Therefore, MLP has the potential to exploit fully the complete range of programming languages within your chosen working set.

Typical MLP Scenarios

The following scenarios in which MLP can be advantageous might help kindle your imagination and help whet your appetite for using it.

  1. You might be required to write a fast user interface in Visual Basic and then call into a remote, platform-independent, ActiveX server that was written in Visual J++. In turn, that server might want to connect to a couple of DLLs (via COM), one containing collection-oriented Standard Template Library (STL) code written in Visual C++ and the other containing code, written in assembly language, for accessing a device such as a hard disk controller. This particular situation is one that every MLP developer dreams about.

    NOTE
    How portable is Java code really? While I think it's pretty cool in theory, I find that I must agree with Bill Dunlap, Microsoft's Visual J++ Technical Product Manager, when he says that (I'm paraphrasing here) due to the sensitivity of the Java run time to differences in underlying hardware architectures, operating systems, and the virtual machines themselves, the "write once, run anywhere" mantra has all too often been found to translate directly to "write once, debug everywhere."

  • You have the vision to imagine a world in which your mainframe-hosted COBOL code wasn't pejoratively and routinely labeled "legacy code" (for "legacy code" reads "doomed to expire on the mainframe" or perhaps can be relabeled as "heritage code"<g>). The good news is that with MLP, this tried and tested, smoothly-running, expensive, mission critical business logic doesn't need to be ported to be fully exploited by "modern" languages.

  • You have a need to do something that is, by definition, more suited to one language than to another. Name your poison—that's what MLP is all about.

  • For raw speed or flexibility, you've determined that you have only to write a routine or two in Assembler and then link to these routines by calling into a DLL. Easy MLP!

  • You might need pointers in a program you're creating in, say, Visual Basic. Another language might be considered more useful simply because that language handles pointers (in the C/C++ sense). We all know that the best programs implement, at each turn, the correct algorithm (putting these before data structures) in the most efficient way possible. More often than not a good algorithm implies some sort of underlying, possibly complex, data structure. Such complex data structures frequently dictate that some pointer manipulation will be required. Ergo, pointers are good for implementing this type of algorithm. An appropriate language for this implementation might be Visual C++ or an assembly language (using the _asm capabilities in Visual C++ or perhaps using Microsoft Macro Assembler [MASM]). Because they don't support pointers, we probably wouldn't choose either Visual J++ or Visual Basic. No problem—MLP lets us mix 'n match as we please, more or less.

    NOTE
    Visual Basic cannot (yet) directly use pointers to data or pointers to what's commonly called a "function" (meaning any routine in this context). In this case, the choice between C++, C, or Assembler would most likely come down to some requirement in terms of a clock-cycle count (raw speed) and, perhaps, developer resource.
  • You need to do something that is most suited to a language other than Visual Basic, but the problem doesn't naturally fit into any known language. Normally in such cases you'd resolve this problem by writing your solution in, say, C. (You can pretty much do anything in C correctly!) Alternatively, the proper solution might be to design and write your own language to build certain DLLs. Sound difficult? Don't you believe it—see the section on creating your own "little language," later in this chapter.

    What's Required for Using MLP?

    To use mixed languages on a development project you need competent developers, the right tools (that's all the tools, with debuggers and profilers included, of course) and you need a very good reason; in other words, what do these other languages offer you that you think you need? For example, if your reason is speed or general performance, consider whether a different language will really fix your problems before selecting one. Are you sure that you're using the right algorithm and that it's implemented in the most efficient way possible? Perhaps you should profile your application to make sure that you're focused on the right piece of code, and always do some back-of-the-envelope calculations to ascertain whether you can use your base language in a better way before reaching for some other. After all, it's easier and cheaper to change your existing code using languages you're familiar with than to add to the code using one that's perhaps more alien. However, if you must, and if all else fails, go for it!

    I hope you're using Visual Studio, because there are a few languages to choose from—Visual Basic (Visual B++—you did read the last sidebar didn't you?), Visual C++, Visual J++, Visual InterDev, and last, but by no means least, Microsoft's Macro Assembler (MASM 6.1—what, you mean you didn't know it was on your CD?). Who among you has already spotted the deliberate mistake? Please forgive me for omitting Visual FoxPro—I simply know absolutely nothing about it! Of course, MLP should also allow you to exploit fully your chosen platform and your developer skills.

    NOTE
    Strictly speaking, a discussion on MLP in Visual Studio should perhaps also mention DHTML, HTML, ASP, SQL, and stored procedures (there, now I've done it!) and whatever else you can think of. Again, because of my personal ignorance, I'm afraid that, just like Visual FoxPro, I've had to omit them. Sorry!
  • How Is MLP Possible in Windows?

    As I'm sure I've said elsewhere in this book, one of the truly great and—it must be said—often overlooked features about Windows is the fact that the linkage mechanism (the means by which components connect to one another) is not necessarily defined at the level of the linker. More frequently it's defined at the level of the operating system itself. Throughout the rest of this chapter, linkage defined "early" (by the linker) is referred to as "static linking," while linking defined "late" (by the operating system) is called "dynamic linking." Dynamic linking is at the heart of why MLP is possible in Windows.

    You can perform MLP in Windows one of three ways:

    These three approaches are explained in the following sections.

    Static linking

    Static linking occurs when you use, or consume, a routine that's not defined by your code, but it somehow becomes part of your monolithic executable image on disk.

    The original definition of the routine resides in a library of routines elsewhere when you reference it in your code. When you compile your code to object code (meaning the process whereby you convert textual script into real code), the definition of the routine—let's call it Print—isn't in your code, it's in a library. However, you don't run object code per se; rather, you run a subtly different form of it: an EXE. You create an executable image from your object code by linking it with other object modules and library files (you also usually link in a bootstrap loader). The linker's job is to bind the object modules and the library routines your object code uses into a single EXE file. During link time the definition of Print is literally copied into the resulting executable. Figure 11-1 shows how this looks diagrammatically.

    Figure 11-1 An example of static linking

    Here our source code contains two calls to a routine named Print. We haven't defined this routine in our code; it's simply a routine supplied by the language or the library vendor. When we compile our code into an object module you can see that the code has changed; essentially the call to Print has been replaced with a Jump instruction. A Jump instruction transfers program control to a specified location (a bit like a GoSub statement). In this example, the specified location is 1234. Notice that before we jump we load a parameter, which is the string to be used as a parameter to the Print routine. Don't worry about where this parameter is loaded; just read it as "passes this parameter." The address 1234, which is shown at the bottom of the object code, contains a call to a routine named ?Print. The question mark here signifies that we still don't have a clue as to where Print really is. It's certainly not in this object file! Notice that the two uses of Print in the source code have been compressed into one—in other words, we have only one call to the actual Print routine. (Or anyway, we will have.)

    Next the code is linked. Notice that the linker links not just our single object code file but also includes the library discussed earlier. The linker copies the definition of Print from the library and places it into a new file along with the object code. This new file is the EXE file. In addition to providing the definition of Print, the linker has also updated the original object code to read Call _Print. The definition of Print is called _Print in the library. No matter.

    NOTE
    I should say that this static linkage mechanism is still used in most Windows programs today, but it's mixed with dynamic linking, too. I'll explain this in the next section.

    This static linking behavior is exhibited in DOS programs. I mean real DOS programs and not "console programs," although these, too, can be dynamically linked. Static linking behavior also enables an executable to contain all the code it requires. Remember the days when you could give someone an EXE and they could run it simply by entering its name at the command prompt? Of course, those days have long since passed and we're all aware that it's not as simple as that anymore! We've all seen messages saying that we're missing some file or another and that a particular application therefore cannot be run. The missing file is usually a dynamically loaded library that has eluded the program loader; in other words, it can't find some of your code, so how is it supposed to run the application?

    What's in a Name?

    I find the moniker Visual Basic terribly outdated these days—wouldn't something like "Visual B++" be a much better product label now? After all, isn't C++ purported to be a "better C?" And anyway, when was the last time you saw a language named BASIC that could use and create pointers, forms, classes, DLLs, objects, type libraries, ActiveX controls, documents, and so forth?

    While I'm at it, here's another thought: are you a developer who truly deserves to be using Beginners All-purpose Symbolic Instruction Code? If you're reading this book, I should think not. Likewise, is your company's mission-critical application truly safe in a beginner's hands (by induction, that's both you and the language)? I think it's about time for a name change and I vote for Visual B++—it's better than BASIC. What do you think? Seriously, let me know and I'll forward on the top, say, five suggestions to the Visual Basic team! In fact, I like Visual B++ so much that to try it out, I'm going to use it in the rest of this chapter in preference over Visual Basic!

    Dynamic linking

    Dynamic linking doesn't differ too much from static linking, as it turns out. The compiler still creates more or less the same old object file and the linker creates almost the same old executable, as shown in Figure 11-2.

    Notice that I've changed the name of the library—it's now called an import library. Import libraries contain no code; unlike their static cousins, they contain only information. This information is primarily concerned with where definitions of routines are stored.

    Picking up our example at link time, the linker "sees" that the object code needs to use Print and therefore must resolve this reference. However, the object code doesn't find the definition of Print in the import library, but instead finds a further reference to the routine, something like X:_Print. This reference means that the routine is contained within a DLL named X. The linker doesn't find X.DLL, extract the code for Print, and then insert it into the EXE it's building; instead, the linker simply places roughly the same reference into the code that it did last time. The EXE still doesn't contain the actual code for Print; it contains a roadmap that leads the program loader to the definition at load time. In this case, the definition is the _Print routine in X.DLL.

    Figure 11-2 An example of dynamic linking

    When the application is loaded, the Windows program loader determines that the code is incomplete. (It's missing the Print routine in our case.) The loader sees that the definition of Print resides in X.DLL and tries to find it in your file system. Let's assume that the loader finds the definition, loads the DLL into memory, and then searches it for the routine _Print. When the loader finds _Print it establishes at which address the routine's been loaded (remember, it just did this) and then inserts that actual address into the EXE image that it's still in the process of loading. In other words, as your application is loading, Windows resolves an implicit request for a service or routine in your binary image and replaces it with a call to the actual implementation of the routine.

    In truth, the preceding was a somewhat simplified description of what actually goes on. (You really don't want, or probably need, to know all the gory details!) But you should still have a good idea of how clever Windows is!

    Mixed static and dynamic linking

    Both static and dynamic linking are used in Visual Basic (Visual B++). This is especially true when you're compiling to native code because each module in your project (Class, Module, or Form) is compiled to an object module, which are linked together statically by LINK.EXE. However, a Visual B++ application also uses a run-time library, in this case the MSVBVM60.DLL. Because this is a dynamic link library, you can see that a Visual B++ application consists of both statically and dynamically linked code and data.

    In fact, Visual B++ applications can also use both forms of dynamic linking (straight DLLs and ActiveX components). Visual B++ applications use ActiveX linking all the time—VBA, the language, lives in such a server component.

    The cool things about dynamic linking

    A good question to ask at this time is "Why do all this dynamic linking?" The answer is not terribly straightforward because there are many reasons, including some that are historical and that I don't intend to cover here. However, one reason might be that, traditionally, developers have used libraries of routines as a way of accessing the functionality of a component. These libraries implement their routines through an API. Reusing routines like these, packaged as a DLL, is as simple as learning the semantics of the API and linking to the library.

    Whatever the reason, however, it's generally a good idea to use and build DLLs because they allow the operating system a greater degree of freedom in how it handles shared resources. The bottom line is that since the linking of components is being done at the operating system level, mixing languages should be much easier to accomplish now than it was in the dark ages of MS-DOS (A-Mess-DOS).

    That all said, the traditional approach of using APIs to access the functionality of a software component does have its drawbacks. These drawbacks include evolution of the API, versioning, component communication, and the implementation language. I'll discuss these issues shortly, but first it's time for more history.

    Let me tell you a story

    Before we had this dynamic linking mechanism, to use MLP we had to find a linker that could link, say, Microsoft C with some other vendor's language. The problem was that such a linker just couldn't exist. Why not? Because each and every language vendor defined their own proprietary object file formats. In other words, the Microsoft linker couldn't understand the object code produced by any other language vendor's compiler, and no other vendor's linker could understand Microsoft C object code. The result was an impasse; and to save everyone's hair from being pulled out, a single-language programming mentality reigned. In fact, to a large degree, it still does.

    We've seen that it was very difficult to get languages from different vendors to talk to one another. However, in truth, it was often worse than I've described, because even the languages produced by the same vendor hardly linked up without a fight. I can well remember trying to get code from Microsoft Pascal version 4 to link with Microsoft C code—there were 40 pages devoted to the topic in the Pascal manual and it took me days to figure it out. Man, do I feel old!

    Of course, as soon as every vendor's object file format was effectively "neutralized" by Windows, things got a lot easier and I have since been involved with a great many projects where we mixed languages to build an entire system. (Very successfully, too, I might add.)

    Mixed Language Approaches

    You can actually perform MLP in a variety of ways. The following sections present a few for you to consider.

    Using a straight DLL

    Probably the easiest way for most languages to communicate is by using a straight DLL, which exports a simple API. In other words, a straight DLL is a traditional DLL. What I mean by "traditional" in this case is a DLL that has an essentially unstructured, arbitrary interface that is in some way referenced via GetProcAddress. (If you don't understand, don't worry—you don't need to.). Straight DLLs are cool but they have some warts, too.

    Evolution of the API The evolution of an API is a problem for both the API creator and the software vendors who use the API. Any changes the creator makes to the API after its initial release might break existing applications that consume it. Changes made by the vendors to extend the API can result in inconsistent implementations.

    Versioning Advertising and maintaining different versions of the API can also be problematic. After all, how can an API creator force a developer to check the version of the DLL to ensure it's the version that's compatible with the developer's program? Actually, one way to do this is to create a routine in the API that returns the DLL's version and, at the same time, "arms" the DLL, preparing it for further use. If the developer doesn't call the "version inquiry" routine, any call into the rest of the API will fail. The vendor might want to extend this version logic. They could have each routine mandate that the developer pass to the DLL its own version number (which was returned from the arming API call), or perhaps the version number of the version the developer requires. The DLL version and the required version might be different. If the DLL version is later than the required version, the DLL should run smoothly. If the DLL version is earlier than the required version, it should degrade gracefully—fail predictably, in other words. <g>

    Component Communication Enabling components to communicate with each other is challenging, especially if different developers have created the components. Each developer might use a different technique, such as "pass me a parameter structure," "pass me a pointer," "pass a variadic by value, list of parameters," and so forth. Each developer might also expect parameters to be passed using a subtly different mechanism.

    Implementation Language The programming language you use for creating components greatly impacts how the components will communicate through an API. For example, if you create components in C++ and export classes from a library, it can be a challenge to use C or Visual Basic to create the client of the component. For example, in order to "properly" use a C++ object you need to be able to invoke C++ methods on it. This, in turn, requires you to pass what's known in C++ as a this pointer to the method. (The this pointer gives the method a pointer to the instance of the object on which it must operate.)

    The Fix An ActiveX DLL has an inherent mechanism, or "rightness," to its exported entry points that brings order to what can sometimes be a truly chaotic environment. The structure of the ActiveX DLL is defined not by a series of exported functions (you can see these by running DUMPBIN /EXPORTS SOMEDLL.DLL) but via a type library (which you can see by using OLEView). In the case of ActiveX DLLs created in Visual B++, the type library is added by Visual B++ to each ActiveX DLL you build. (More on this later.)

    Notice that a call to a straight (non-ActiveX) DLL must be from Visual B++ to some other language because Visual B++ can create only ActiveX DLLs. For example, say you want to mix C and Visual B++. First you write a DLL in C, and then you call into this DLL from Visual B++—not the other way around. DLLs in Visual B++ are ActiveX DLLs and as such you have no control over defining a non_ActiveX interface to them (unless you're a real hacker).

    Of course, this straight DLL stuff is the kind of MLP you're probably already used to handling from the Visual B++ end. You'll be defining external entry points into some DLL via a Visual B++ Declare statement:

    Declare Function GetSystemMetrics Lib "User32" _ (ByVal n As Integer) As Integer 

    This Declare statement essentially declares the external GetSystemMetrics routine in USER32.DLL to be an external C routine.

    The challenge in writing DLLs like this is twofold:

    1. Getting parameter data types converted correctly. For example, how is a Date passed? Does Integer mean 16 bits or 32 bits?

    2. Passing these parameters to the DLL in the way that it expects them to arrive (not in terms of their definition but their placement in memory). For example, some language compilers support so-called "fast" ways to pass parameters to and from called routines. Normally, of course, parameters are passed on the stack. However, if parameters are instead pushed into registers, a faster call results. (It's quicker to push and pop a value into and out of a register than it is to access the stack.) Pushing to registers is great if, as the called routine, you're expecting to pull parameter values out of registers, of course, but no bloody good whatsoever if you expect to find them on the stack! In the latter case, you'll either be working with garbage or playing with Dr. Watson.

    TIP
    It's best to compile DLL code using the most basic calling convention available (either _stdcall or the Pascal calling conventions) as it's probably the most widely used by clients. By the way, even if you're not calling your C DLLs from Visual B++ today, don't forget that you might want to in the future. Compiling the C DLLs now to use a standard calling convention will protect you later if you decide to call into your back-end DLL from a Visual B++ front end (say).

    To resolve both these issues you must really know your language compiler. Notice that I don't say "know your language." Most often the language definition will say nothing about how parameters are passed—just that they can be passed! It's up to the language compiler vendors to interpret the language specification as they see fit. If the vendors want to pass parameters using registers, for instance, they're at liberty to do so. You need to check your compiler's documentation and command-line switches to understand how it's working. (See VB5DLL.DOC on the companion CD for more information.)

    Using COM and ActiveX vs. Using a DLL

    A DLL is an operating system facility whereas COM is a specification (and some technology) that's been designed from the ground up for building and publishing components and for exporting interfaces. Because COM happens to be implemented largely through the DLL linkage mechanism, you should prefer it to a DLL. However, because language vendors must support it, the DLL linkage mechanism is by far the most common method for connecting objects at run time. Table 11-1 and Table 11-2 help summarize the pros and cons of using COM/ActiveX and a DLL.

    Table 11-1 Pros and Cons of Using COM/ActiveX

    Pros (subjective) Cons (subjective)
    Well implemented, understood technology. Registry and installation dependent. (The integrity and "correctness" of the system Registry determines the ultimate integrityof the application that depends on it.)
    Designed from the ground up to be portable across architectures; thus inherently cross-platform. Isolates architectural boundaries.
    Part of the operating system. Based on the Windows operating system.
    A Microsoft standard. A "wholly-owned" Microsoft standard.
    Somewhat versioned by the operating system in the form of the GUID and the Registry. Requires a certain amount of extra savvy on the part of the developer to use with any authority.
    Tools such as Visual B++ create COM components by default. Technology is cutting edge and thus often prone to being misapplied or badly applied by inexperienced developers.
    Trendy and fashionable. The current fad?

    Table 11-2 The Pros and Cons of Using a DLL

    Pros (subjective) Cons (subjective)
    These days, most languages support building DLLs, so the language choice is vast. Arbitrary interface.
    Subject to running afoul of version problems and bad linkage, especially if the DLL doesn't contain a VERSIONINFO resource or if that resource isn't tested by the consuming module. True DLLs cannot be built by Visual Basic (only ActiveX DLLs can be built that export objects).
    Skills required to understand the technology are fundamental.

    COM COM is a standard (or model) for the interaction of binary objects. An important feature of COM is that objects are precompiled, which means that the implementation language is irrelevant. If you include tokenized code (for example, the p-code in Visual B++ or the bytecode in Java), objects will not necessarily be tied to a specific hardware platform or operating system. COM is also an integration technology. Components can be developed independently and COM provides the standard model for integrating these components. One can think of COM as an enabling technology rather than as a solution in itself.

    The major goals of COM are language and vendor independence, location transparency, and reduced version problems.

    Language independence When developing components, you should not need to choose a specific language. In COM, any language can be used as long as it allows functions to be called through function pointers. Even interpreted languages are not excluded if the interpretive environment can provide these pointer services on behalf of the application. You can therefore develop COM component software by using languages such as C++, Java, Visual B++, and Visual Basic, Scripting Edition (VBScript).

    Location transparency In addition, you should not have to know in which module and location the file system provides a service. This becomes increasingly important when specific services cannot be provided locally, if services are late bound, or if the process that provides these services changes location. Just as hard-coded paths are problematic in applications, hard-coded dependence on the location of services can also cause errors. COM separates clients from servers, which allows servers to be moved without impacting clients.

    Vendor independence Consider an example of what happens frequently in one of the most current models for software development. A new vendor provides an ODBC driver for your database that is better than the driver provided by your current vendor. It would be a lot of effort if you had to port all existing code to use the new driver. The effort involved might tempt you to keep the existing, less effective driver. But because COM objects export only interfaces, any new object that exposes the same interfaces as an existing object can transparently replace the existing object. Vendor independence extends not just to external vendors, but also internally to objects that can be easily upgraded without recompiling.

    Reduced version problems COM requires immutable interfaces. Although this specification requirement does not entirely eliminate version problems, it greatly reduces the extent of the problem.

    DLLs in Java

    As a language, Java is pretty cool because it gives you the tools you need to do some pretty serious object-oriented development without some of the complications and overhead of the object-oriented assembly language approach in C++. Visual J++ 6 also has a recognizable IDE and, as far as Visual B++ developers are concerned, follows a familiar development metaphor. For Visual B++ developers, Visual J++ 6 is probably the natural choice for creating DLLs as opposed to, say, Visual C++.

    If you wanted to get some Java code to work with Visual B++, one easy way to join the two is by utilizing a DLL as a kind of go-between.

    Calling out of Java From time to time, Java, like any professional language, needs the native capabilities provided by the operating system. Indeed, the designers of the Java language realized this need long ago, so since JDK 1.0.2 we've been able to call out of Java and into the operating system. We do this through "native methods," also called the Raw Native Interface (RNI). With Java, this need to go outside is especially acute since built-in functionality is incomplete (due primarily to its portability, a common problem with any cross-platform product or technology). Try implementing F1-Help in a Java program for an example of what I mean. As I've stated, Java's creators anticipated this need and had the foresight to define native methods.

    In Java, a method that is modified (flagged) as native is implemented in platform-dependent code, which is typically written in another programming language such as C, C++, or assembly language. The declaration of a native method is followed by a semicolon only, whereas an internal Java method declaration would be followed by a block of implementation code.

    In Visual J++, Microsoft has extended the native metaphor and named the result J/Direct. For example, they've made it extremely simple to call DLLs, which are declared via Javadoc comment blocks. In fact, J/Direct is so good at allowing you to call out of Java that Microsoft itself uses the technology in the Windows Foundation Classes (WFC) to give Visual J++ great performance when it comes to creating, and even tearing down, your application's user interface.

    In summary, J/Direct allows you to call most any DLL directly (a Windows DLL or your own). The Virtual Machine (VM) also takes care of thorny issues such as mapping of data types for you.

    Comparing J/Direct to the RNI J/Direct and native calls are complementary technologies. Using the RNI requires that DLL functions adhere to a strict naming convention, and it requires that the DLL functions work harmoniously with the Java garbage collector. That is, RNI functions must be sure to call GCEnable and GCDisable around code that is time-consuming, code that could yield, code that could block on another thread, and code that blocks while waiting for user input. RNI functions must be specially designed to operate in the Java environment. In return, RNI functions benefit from fast access to Java object internals and the Java class loader.

    J/Direct links Java with existing code such as the Win32 API functions, which were not designed to deal with the Java garbage collector and the other subtleties of the Java run-time environment. However, J/Direct automatically calls GCEnable on your behalf so that you can call functions that block or perform user interfaces without having a detrimental effect on the garbage collector. In addition, J/Direct automatically translates common data types such as strings and structures to the forms that C functions normally expect, so you don't need to write as much glue code and wrapper DLLs. The trade-off is that DLL functions cannot access fields and methods of arbitrary Java objects. They can only access fields and methods of objects that are declared using the @dll.struct directive. Another limitation of J/Direct is that RNI functions cannot be invoked from DLL functions that have been called using J/Direct. The reason for this restriction is that garbage collection can run concurrently with your DLL functions. Therefore, any object handles returned by RNI functions or manipulated by DLL functions are inherently unstable. Fortunately, you can use either RNI or J/Direct (or both). The compiler and the Microsoft Win32 VM for Java allow you to mix and match J/Direct and RNI within the same class as your needs dictate.

    Why might you want to call DLL code instead of coding purely in Java? Here are a few reasons:

    Here's an example of a Java application (this code is the entire thing) showing how easy it is to call a Windows' routine, MessageBox, in this case.

    class ShowMsgBox  {     public static void main(String args[])     {       MessageBox(0, "It worked!",                  "This is a message box from Java", 0);           }    /** @dll.import("USER32") */    private static native int MessageBox(                                          int hwnd                                        , String text                                        , String title                                        , int style                                        ); }  

    Simple, eh?

    Calling into or out of Java Microsoft's Java VM has added the ability to treat COM objects as special Java classes. COM integration is best for calling APIs that are wrapped in COM objects, or for ActiveX controls. About the only disadvantage to this wrapping method is that there's a translation layer between Java and COM, so the performance won't be as fast as if you were using C++ (and therefore had one less translation layer).

    Creating this type of COM object is really simple if you're a Visual B++ developer, which I assume you already are. Here are the steps. Follow along if you have Visual J++ 6 installed.

    1. Select New Project from the File menu. From the New Project dialog box open the Components folder then select COM DLL. Change the Name and Location if you want and click Open.

    2. In the Project Explorer double-click the class that's been inserted for you by default (Class1). This will open Class1.java in the code editor.

      You'll see something like this:

      // Class1.java /**  * This class is designed to be packaged with a COM DLL output format.  * The class has no standard entry points, other than the constructor.  * Public methods will be exposed as methods on the default COM interface.  * @com.register ( clsid=B6E79300-384E-11D2-B30B-008C7360DC1, typelib=B6E79301-384E -11D2-B30B-0080C7360DC1 )  */ public class Class1 {     // TODO: Add additional methods and code here     /**      * NOTE: To add auto-registration code, refer to the documentation      * on the following method      *   public static void onCOMRegister(boolean unRegister) {}      */ }

      NOTE
      Notice that when you generate a COM DLL the opening comments specify a class ID, signifying that this class is a COM class. Visual J++ has an option that lets you specify whether this class should be a COM class. Select Project Properties from the Project menu and then click the COM Classes tab. By default the check box for Class1 is checked, meaning make Class1 a COM class.

    3. Add the following boldface code to make your class look like this:

       // Class1.java import wfc.ui.*; /**  * This class is designed to be packaged with a COM DLL output format.  * The class has no standard entry points, other than the constructor.  * Public methods will be exposed as methods on the default COM interface.  * @com.register ( clsid=B6E79300-384E-11D2-B30B-008C7360DC1, *typelib=B6E79301-384E -11D2-B30B-0080C7360DC1 )  */ public class Class1 {        // TODO: Add additional methods and code here        public int Doit()        {            String sText = new String ();            sText = "Hello from Java";            return MessageBox.show (                              sText                             ,"Java"                             ,MessageBox.DEFBUTTON1      |                              MessageBox.ICONEXCLAMATION |                               MessageBox.YESNOCANCEL                             );         }        }

    4. Build your project by selecting Build from the Build menu. Select Deploy Solution from the Project menu. You're now finished with Java (for the time being).

    You can change wfc.ui.* to awt.ui.* in order to use the real, non_J/Direct Abstract Windowing Toolkit (although you'd want to do this only to build cross-platform).



    Ltd Mandelbrot Set International Advanced Microsoft Visual Basics 6. 0
    Advanced Microsoft Visual Basic (Mps)
    ISBN: 1572318937
    EAN: 2147483647
    Year: 1997
    Pages: 168
    Authors: Mandelbrot Set International Ltd
    BUY ON AMAZON

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net