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.
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? 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!
MLP in Windows: 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.
Why do all this 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.
Dynamic linking mechanism, to use MLP
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.)