CARVIEW |
Select Language
HTTP/2 302
server: nginx
date: Thu, 07 Aug 2025 02:45:57 GMT
content-type: text/plain; charset=utf-8
content-length: 0
x-archive-redirect-reason: found capture at 20071214231912
location: https://web.archive.org/web/20071214231912/https://www.oreilly.com/catalog/compluspvb/toc.html
server-timing: captures_list;dur=0.572504, exclusion.robots;dur=0.022572, exclusion.robots.policy;dur=0.010598, esindex;dur=0.011897, cdx.remote;dur=32.600384, LoadShardBlock;dur=559.274513, PetaboxLoader3.datanode;dur=547.670487
x-app-server: wwwb-app216
x-ts: 302
x-tr: 618
server-timing: TR;dur=0,Tw;dur=0,Tc;dur=0
set-cookie: wb-p-SERVER=wwwb-app216; path=/
x-location: All
x-rl: 0
x-na: 0
x-page-cache: MISS
server-timing: MISS
x-nid: DigitalOcean
referrer-policy: no-referrer-when-downgrade
permissions-policy: interest-cohort=()
HTTP/2 200
server: nginx
date: Thu, 07 Aug 2025 02:45:58 GMT
content-type: text/html
x-archive-orig-date: Fri, 14 Dec 2007 23:19:12 GMT
x-archive-orig-server: Apache
x-archive-orig-p3p: policyref="https://www.oreillynet.com/w3c/p3p.xml",CP="CAO DSP COR CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa CONo OUR DELa PUBi OTRa IND PHY ONL UNI PUR COM NAV INT DEM CNT STA PRE"
x-archive-orig-last-modified: Thu, 13 Dec 2007 08:11:44 GMT
x-archive-orig-accept-ranges: bytes
x-archive-orig-content-length: 290253
x-archive-orig-x-cache: MISS from oregano.bp
x-archive-orig-x-cache-lookup: MISS from oregano.bp:3128
x-archive-orig-via: 1.0 oregano.bp:3128 (squid/2.6.STABLE12)
x-archive-orig-connection: close
x-archive-guessed-content-type: text/html
x-archive-guessed-charset: iso-8859-1
memento-datetime: Fri, 14 Dec 2007 23:19:12 GMT
link: ; rel="original", ; rel="timemap"; type="application/link-format", ; rel="timegate", ; rel="first memento"; datetime="Wed, 27 Jun 2001 16:20:51 GMT", ; rel="prev memento"; datetime="Sat, 17 Nov 2007 01:16:34 GMT", ; rel="memento"; datetime="Fri, 14 Dec 2007 23:19:12 GMT", ; rel="next memento"; datetime="Tue, 15 Jan 2008 06:55:34 GMT", ; rel="last memento"; datetime="Tue, 22 Nov 2011 06:35:42 GMT"
content-security-policy: default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: archive.org web.archive.org web-static.archive.org wayback-api.archive.org athena.archive.org analytics.archive.org pragma.archivelab.org wwwb-events.archive.org
x-archive-src: 51_1_20071214193633_crawl106-c/51_1_20071214231801_crawl100.arc.gz
server-timing: captures_list;dur=0.521056, exclusion.robots;dur=0.021357, exclusion.robots.policy;dur=0.009600, esindex;dur=0.013132, cdx.remote;dur=33.387115, LoadShardBlock;dur=372.106597, PetaboxLoader3.datanode;dur=314.945769, PetaboxLoader3.resolve;dur=174.393354, load_resource;dur=245.757313
x-app-server: wwwb-app216
x-ts: 200
x-tr: 779
server-timing: TR;dur=0,Tw;dur=0,Tc;dur=0
x-location: All
x-rl: 0
x-na: 0
x-page-cache: MISS
server-timing: MISS
x-nid: DigitalOcean
referrer-policy: no-referrer-when-downgrade
permissions-policy: interest-cohort=()
content-encoding: gzip
O'Reilly Media | COM+ Programming with Visual Basic
Buy this Book
Table of Contents
- Chapter 1: COM+ Internals
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAs Visual Basic developers, you and I love the fact that VB lets us create full applications in a relatively short amount of time. There is no doubt that, compared to other languages on the market, Visual Basic stands out as perhaps the leading rapid application development (RAD) language. One of the things that make Visual Basic so easy to use is that VB hides a lot of the details of the technology from us. In Visual Basic, for example, you could live a happy and fruitful life without knowing what a message loop is or learning anything about the types of messages that the OS sends to each window. (If you do not know how things are done at this level, then you are proof that the Visual Basic team has done its job correctly.)COM+ is also an architecture that the Visual Basic team has decided to hide from you. The problem is that almost every aspect of what you can or cannot do with Visual Basic classes is governed by the rules of COM. You may ponder the fact that every "public" class you have in an ActiveX DLL or ActiveX EXE is a COM component, and you may decide that item of information is just an interesting piece of trivia. According to this view, in the real world it matters not whether you are writing COM components or Widgets—the only thing that matters is that they work correctly and that they deliver what they have promised. This is an interesting thought, because the real question then becomes: what do we gain from COM+? It seems fitting then to take some time to define the term and analyze some of the claims it has made.COM+ is an interesting term. What makes COM+ a particularly interesting term is that it is used very frequently, yet very few people know what the term actually means. Most people think COM+ is the next version of COM. (The term COM refers to the Component Object Model—a specification Microsoft introduced in 1992.) Actually, COM has changed very little from its Windows NT 4.0 cycle to the introduction of COM+ in Windows 2000. It is fair to say that COM+ is actually more the next version of a Microsoft product named Microsoft Transaction Server (MTS), and it is even more exact to say that COM+ is actually the integration of the MTS service model with the COM APIs. To understand what all this means, let's talk about COM first, then MTS, then see why these two models were merged in COM+.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - What Is COM+?
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterCOM+ is an interesting term. What makes COM+ a particularly interesting term is that it is used very frequently, yet very few people know what the term actually means. Most people think COM+ is the next version of COM. (The term COM refers to the Component Object Model—a specification Microsoft introduced in 1992.) Actually, COM has changed very little from its Windows NT 4.0 cycle to the introduction of COM+ in Windows 2000. It is fair to say that COM+ is actually more the next version of a Microsoft product named Microsoft Transaction Server (MTS), and it is even more exact to say that COM+ is actually the integration of the MTS service model with the COM APIs. To understand what all this means, let's talk about COM first, then MTS, then see why these two models were merged in COM+.As I mentioned earlier, COM stands for the Component Object Model. COM is one of those terms that sound old; in fact, the first specification came out around 1992. However, COM is still heavily used today; without COM there would be no COM+. In fact, without COM, VB classes and components would behave very differently.COM is a specification, and it is also to some extent the implementation of the specification. The goals of COM are the following:
- Interoperability between different languages
-
Components from one language should communicate with components from another language. Also, a client program written in one language should be able to use a component written in a different language.
- A standard for versioning
-
Versioning is a big word, but it means that existing client programs should work with newer versions of the component. Actually, the versioning scheme dictates that new versions of the client should work with old versions of the component as well. They may decide to display a message telling the user to upgrade the component, but the program should not crash.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - COM and COM+
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this book, you are going to learn how COM technology works and how to interact with the services. The reason we refer to things as COM in the first half of the book instead of COM+ is that, in reality, COM+ is COM with a few enhancements. At the end of the day, what you are really writing are COM components that work in COM+ applications. The book also shows you how some of the most interesting services work internally. This leads us to another question—in the world of Visual Basic, why do we need to know how things work internally?Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Knowing the Internals
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf we are VB developers and the goal of VB is to hide the COM+ architecture, why do we need to know things at a low level? Well, it turns out that VB is good about hiding 90% of the technology. The problem is that the other 10% makes life very difficult. A number of topics can be mastered only if you understand how the architecture works internally. It becomes a lot easier to solve those problems if you have a good grasp of the architecture than if you don't; in fact, in some cases, it becomes possible for you to solve those problems, whereas it remains impossible without some knowledge of the internals.It would be easy for me to just tell you to stay away from this or that feature or to turn on this option in x situation and to turn it off in y situation (and in fact a lot of authors do just that). I felt that, as a VB developer, I'd had enough of not knowing why some things work the way they do; life gets a lot easier when you know exactly what's happening. It turns out that with some knowledge of the internals, you can also stretch VB farther than you could imagine. Let's take a look at some of the topics in the troublesome 10% of COM/COM+ technology.One of the most frustrating things in Visual Basic is versioning. The problem with versioning is that VB tries to hide too much from you. You may have had, for example, the situation in which you recompile your ActiveX DLL or ActiveX EXE and then find that the client program using it stops working. Some developers end up rebuilding every component and every client every time a little change is made. However, it turns out that one of the reasons VB uses COM as its core technology is to prevent the situation in which you have to distribute everything again to the client.The problem is that VB components use COM interfaces to group their methods, and these interfaces have a globally unique identifier (GUID) number assigned to them. The client uses GUIDs to tell COM what interface and what component it wants to create. C++ developers have full control of how the GUIDs are generated and when they are changed—they work with GUIDs directly. VB developers do not look at GUIDs directly; the compiler and debugger generate the numbers automatically as needed. By default, the compiler assigns a new GUID each time you compile the project. When you compile the client using that interface, the client code becomes dependent on the GUID for that interface. Since the default in VB is to generate new ones, each time you re-compile the component's project, you end up with a new GUID, and the existing clients stop working.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Introduction to .NET
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBy the time this book hits the streets, you likely will have heard about a new technology coming from Microsoft called Microsoft .NET (.NET for short). The question in a lot of developer's minds is "How does .NET interact with COM+?" Well, the bad news is that .NET has very little to do with COM. Microsoft has decided in many ways to abandon the existing COM architecture for developing components and is investing instead in a brand new technology called .NET. That does not mean that COM+ is dead; in fact, for the first version of .NET, if you are planning on using COM+ services, it makes a lot more sense to develop COM+ components than .NET components. Also, the current versions of the OS and the upcoming version, Windows XP, are all built to use COM+ natively. It will be a couple of years before the COM+ services are changed to .NET services.However, Microsoft is making it possible to use .NET components in COM+ through a COM callable wrapper. The idea is that the .NET execution engine, the software responsible for loading and executing .NET components, will also act as a COM server. Thus, .NET components will use the same principles as MTS in which the calls to them from COM clients will go through yet another impostor object that will do the job of translating calls from COM (now referred to as unmanaged space) to .NET (referred to as managed space). It is possible through wrappers for .NET components to make calls to COM components and for COM components to make calls to .NET components. In Chapter 11, you will learn the details of this brand new architecture and how to make the two architectures interoperate.All the major compilers (VB included) have been rewritten to emit a high-level form of assembly language called Intermediate Language (or IL). This means that VB will no longer compile code to native code that the processor can understand. Instead, VB compiles code to IL, and a Just-in-Time compiler at runtime (or at deployment time) changes the IL code to native code. The concept is similar to the way Java programs execute. Because the compilers have been changed to emit IL, a number of features have been added or changed to conform to the IL specification. In many ways, VB.NET is a brand new language—with a lot of exciting enhancements. In Chapter 11 you will also learn about IL, the .NET architecture, and the new features in VB.NET.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 2: Interface-Based Programming
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, you will learn the basics of interface-based programming. Although this may seem like review to some Visual Basic developers, the truth is that—from my experience teaching at various companies—very few developers understand how interfaces work in Visual Basic, and those who do, do not employ interface programming in their projects.Interfaces are the primary building blocks of COM+. What's more, even if it may have been possible to avoid interface-based programming with Visual Basic altogether in previous versions of COM and Windows, this is no longer possible with COM+ and Windows 2000. To take advantage of the new features of COM+, you must understand interface-based programming and write your code in such a way that it utilizes interfaces as much as possible. Interface-based programming is not only necessary to take advantage of new features in COM+, but it also provides us with a mechanism for upgrading our components. Furthermore, interface-based programming makes it possible for us to use a feature in object-oriented programming known as polymorphism. Polymorphism is a loaded term in the object-oriented world. One definition is that multiple classes may have the same method with the same signature (input and output parameters) but have slightly different semantics. For example, classes like CChecking and CSavings may each have a MakeDeposit method, and even though the overall intent of the methods may be the same (to add money to the account's balance), it may be that each implementation is slightly different. With polymorphism, it is possible to write a global function that takes as a parameter either of these classes and calls the appropriate implementation of the MakeDeposit method depending on the object type that the caller sent in. Another definition is that a component can act as if it were a collection of multiple components. If you create an instance of the component, it may be used with a function that works with type A components, or it may be used with another function that expects B components. A component that can act as many different components is said to beAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Why Interface-Based Programming?
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the "good old days" of Basic programming, software was built using line numbers, GoTos, GoSubs, and Returns. A program would normally start at line 100 and continue linearly through lines of code numbered at intervals of 10. Many times, a portion of the code needed to be used from more than one place in the program. In those instances, programmers would place the code in line 1000, for example, and call it from wherever it was needed by issuing the command
GoSub 1000
. The code at line 1000 would then execute and, after it was done, it would issue theReturn
command. So programmers would end up with code such as the following:100 REM This is my GWBasic program 110 Dim A As Integer, VL As Integer, VH As Integer, bC As Integer 120 Print "Welcome to Widgets USA Order System" 130 Print "Select from the menu options below..." 140 Print "1. Enter Order" 150 Print "2. List Orders" 160 Print "3. Delete Order" 170 Print "carview.php?tsp=" 180 Input "Enter number 1-3",A 190 REM Let's check that the input was valid 200 VL = 1 : VH = 3: Gosub 1000 210 If bC = 1 Then Goto 500 220 Print "Incorrect menu option, please try again" 230 Goto 180 500 REM Continue executing program 999 END 1000 REM This piece of code checks that we have a valid entry 1010 If A >=VL or A<=VH Then bC=1 Else bC = 0 1020 Return
Lines 1000 through 1020 check the validity of a menu entry. They assume that VL was set to the lowest valid entry and VH was set to the highest valid entry prior to executing the code. The code also assumes that the entry number the user selected is stored in the A variable. This piece of code returnsbC = 1
if the entry was valid orbC = 0
if the entry was invalid.Except for the very few developers who are still using DOS and GWBASIC and refuse to upgrade their 286 machines, the majority of Basic developers would agree that the preceding code listing is very difficult to maintain and upgrade. Suppose, for example, that you were asked to pull the code that verifies the validity of a menu choice from the program and insert it into another project. You cannot use the code in lines 1000 through 1020 without also importing the line that declares the necessary variables (line 110). You also need to make sure the values of VL and VH are set before calling the code (line 200), not to mention that the user's menu choice must be stored in variable A (line 180). Then, you must make sure that the menu-display code uses the variable bC to determine whether to continue with the program or ask the user to reenter his choice (line 210). All this, and this is only a 19-line program!Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Defining Interfaces in Visual Basic
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWhat keeps us from upgrading the CAccount class is that the client has a dependency on the first version of the public members of the class. There is no problem with changing private members, since they're completely transparent to the client, but you cannot change public members. There is a one-to-one relationship between the class itself and the public members of the class. If the public members were not part of the CAccount class, then the client would not have dependencies on the class, and the class could be changed without problems. Therefore, we must dissociate the public member declarations from their implementation. To do this, a new entity known as an interface is built. The simplest definition of an interface is that it is a class with public properties and methods but without any code. The class serves as a definition of methods, a protocol that a client will use to communicate with the class. In Chapter 3, you are going to learn a more concrete definition. However, for now it is sufficient to think of an interface as a class with declarations but without code. For example, let's return to the CAccount class. Instead of adding public members directly to this class, let's create a second class and call it
IAccount
. TheIAccount
class will have the following code:' Class IAccount Public Property Get Balance( ) As Currency End Property Public Sub MakeDeposit(ByVal Amount As Currency) End Sub
As you can see from the definition, there are no private members defined for the class, only public members: the Balance property and the MakeDeposit method. This class defines an interface. Just as a class module defines a template for creating objects, an interface is a template for creating other class modules. The interface class is not meant to be a creatable entity, which is why it is a good idea to change the Instancing property of the class to2 - PublicNotCreatable
. (The Instancing property is available only when creating an ActiveX EXE, ActiveX DLL, or ActiveX Control project).Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Using a Class Through an Interface
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow, let's look at how the client may use the class through the interface. The first step is for the client to declare a variable of the type of the interface as follows:
Dim Acct As IAccount
What exactly happens when you declare a variable such as in the preceding line of code? Visual Basic allocates some memory (4 bytes) to hold a memory address for the object. VB does not actually create the object in memory until it is told to do so. However, it does allocate a container known as Acct to hold the memory address of the object once it is created. The Acct container will hold the memory address &H00000000 (that is, a null pointer) when the variable is declared. Figure 2-3 shows a representation of the Acct memory variable.Figure 2-3: Memory representation of the Acct variableIf you are an experienced C++ developer, you may find it interesting to examine the layout of VB objects in memory. VB provides several undocumented functions to enable you to obtain the memory address of an object. These functions are: VarPtr, ObjPtr, and StrPtr. VarPtr returns the address of a variable. ObjPtr returns the address of an object. Therefore, if Acct were the variable, you could ask VB to report the address of the variable itself with the VarPtr function, or you could ask VB to report the address of the object that Acct is pointing to with ObjPtr. The function StrPtr returns the address of a string. Again, you could ask VB to report the address of the variable that points to a string or the address of the memory where the string buffer is allocated.Remember that the classIAccount
does not implement the functions Balance and MakeDeposit. It simply provides a definition for the functions. Therefore, we must set the Acct variable to point to an object that implements the functions ofAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Polymorphism I (Multiple Components—Single Interface)
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe term polymorphism refers to many different things in object-oriented lingo. One aspect of polymorphism is that two classes may share a single interface but implement the methods in the interface slightly differently. To illustrate this meaning of polymorphism, let's suppose we add a CSavings class to the project:
' Class CSavings Option Explicit Implements IAccount Private m_cBalance As Currency Private m_dInterest As Double Private Property Get IAccount_Balance( ) As Currency IAccount_Balance = m_cBalance End Property Private Sub IAccount_MakeDeposit(ByVal Amount As Currency) m_cBalance = m_cBalance + Amount + (Amount * m_dInterest) End Sub
Notice that the preceding code is very similar to that of the CChecking class, except that the MakeDeposit subroutine actually adds some interest to the Amount sent it (this is a very good savings account). This shows that the definition of the interface tells the implementer nothing about how the code for the function is to be written. Each class may have a different interpretation of the MakeDeposit routine. (Later, you will see that this is especially good for polymorphism.) The only requirement is that they have similar semantics—in other words, that the two implementations do roughly the same thing with slight variations; MakeDeposit in CSavings does not remove money from an account, for example.At this point, our project has two implementation classes, CChecking and CSavings, and one interface class,IAccount
. Both the CChecking class and the CSavings classes implement theIAccount
interface. What may not be readily apparent is that to use the CSavings class, all you need to do is change the line that creates an instance of the object, as follows:Dim Acct As IAccount Set Acct = New CSavings Dim balance As Currency balance = Acct.Balance
The client code is identical except that instead of creating an instance of the CChecking class, the code creates an instance of the CSavings class. Both of these classes implement theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Polymorphism II (Single Component—Multiple Interfaces)
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe second meaning of the term polymorphism is the ability of a component to act as many different types of components. It can do this by implementing multiple interfaces. To illustrate, let's define a second interface called
ISaveToDisk
. The purpose of this second interface is to save the balance information to a file. To define this new interface, you would add another class to your project and name itISaveToDisk
. Then you would change the instancing property of this class to2 -
PublicNotCreatable
and add a function to your class without any code, as follows:' Class ISaveToDisk Option Explicit Public Sub Save( ) End Sub
Once the interface is defined, you must implement it. Suppose for the sake of argument that only the CChecking class implemented the interface. In other words, only instances of CChecking could save the balance to disk (no wonder the bank can afford to give such generous interest on savings accounts). The CChecking class would then be modified as follows:' Class CChecking Option Explicit Implements IAccount Implements ISaveToDisk Private m_cBalance As Currency Private Property Get IAccount_Balance( ) As Currency IAccount_Balance = m_cBalance End Property Private Sub IAccount_MakeDeposit(ByVal Amount As Currency) m_cBalance = m_cBalance + Amount End Sub Private Sub ISaveToDisk_Save( ) 'the implementation of this function is left as an exercise 'for the reader End Sub
Suppose that management has asked you to modify the ReportBalance function to save the balance of the account if it supports the ISaveToDisk interface. Because the function accepts any class that implements IAccount, there is no guarantee that the developer using the function will send in a class that supports both the IAccount interface and the ISaveToDisk interface. VB provides an operator—TypeOf...Is—to test whether the object supports an interface. You use the TypeOf...Is operator in an If statement as follows:If TypeOf [object] Is [interface] Then End If
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Review
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterI made the point at the beginning of the chapter that interface-based programming provides us with a mechanism to upgrade classes. To use interface-based programming, you must first define an interface in the server code. We refer to the entity that provides the class or interface definition as the server. (Do not worry at this time about how the server is packaged—you will learn more about that in later chapters.) To define an interface, you must add a class to your project and add public properties and methods (subroutines or functions) without any code. Remember that the interface is not meant to be a creatable class; it is only meant to provide the definition of functions. This is why it is a good idea to mark its instancing property as
PublicNotCreatable
.Once you have defined the interface, you must implement it in a class. To do so, you simply create a new class and use theImplements
statement. Once you have used theImplements
statement, the code window will list the interface class as an object in the object drop-down list. Select it and then select each function of the interface in the function list drop-down. Once you have added each property and function in the interface to your implementation class, then you write code for each of the methods of the interface. This is all that needs to be done by the server.To use the implementation class through the interface definition, you declare a variable of the interface type, then set the variable to a new instance of the implementation class. You can also use theTypeOf
...Is
operator to find out if a class supports a certain interface.If you need to change a method definition in an interface, you simply create a new version of the interface, Interface2
. Then, you implement both the old version of the interface and the new version of the interface.This book is a lot about what happens underneath—what VB is really doing behind the scenes. Therefore, in the next chapter, you are going to look beyond the high-level mechanism of interface-based programming and find out exactly how interfaces work internally and why it is that we can switch from one interface to another.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 3: How Interfaces Work Internally
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the last chapter, you learned the benefit of interfaces at the user level. You learned why we need interfaces conceptually and how to define and use them. In this chapter, you are going to learn what interfaces really are at the memory level. In so doing, you are going to learn some of the core rules of COM. You are going to see the problems that existed before COM and how the COM rules make it possible to overcome those problems.This chapter is not for the weak of heart. If you do not want to know how interfaces work internally, feel free to skip this chapter for now and revisit it later.Let's try to imagine life before COM and also life without classes. That would mean that you have user-defined types (UDTs) that represent components and code modules that have global functions. This is not much different than life with VB 3. Also, imagine that the latest version of VB did allow you to create DLLs.Now suppose that you are designing a banking application. Understanding the benefit of separating code that will be shared among several applications, you define a UDT inside the DLL to represent an account:
Enum AccountTypeConstants Checking = 1 Savings = 2 End Enum Type Account AccountType As AccountTypeConstants Active As Boolean Balance As Currency End Type
The UDT has three data members: AccountType, Active, and Balance. The AccountType member in the structure refers to an enumerated type,AccountTypeConstants
, defined above the UDT. To use this UDT, all that a user has to do is use theDim
statement and then set the members of the UDT, as shown in the following code fragment:Dim Acct As Account Acct.AccountType = Checking Acct.Active = True Acct.Balance = 1000
Notice that to use a UDT, you do not have to include theNew
keyword. This is because VB allocates the memory for the UDT at the time that it encounters theDim
statement.How much memory does VB allocate? You can use theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Life Without Interfaces
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterLet's try to imagine life before COM and also life without classes. That would mean that you have user-defined types (UDTs) that represent components and code modules that have global functions. This is not much different than life with VB 3. Also, imagine that the latest version of VB did allow you to create DLLs.Now suppose that you are designing a banking application. Understanding the benefit of separating code that will be shared among several applications, you define a UDT inside the DLL to represent an account:
Enum AccountTypeConstants Checking = 1 Savings = 2 End Enum Type Account AccountType As AccountTypeConstants Active As Boolean Balance As Currency End Type
The UDT has three data members: AccountType, Active, and Balance. The AccountType member in the structure refers to an enumerated type,AccountTypeConstants
, defined above the UDT. To use this UDT, all that a user has to do is use theDim
statement and then set the members of the UDT, as shown in the following code fragment:Dim Acct As Account Acct.AccountType = Checking Acct.Active = True Acct.Balance = 1000
Notice that to use a UDT, you do not have to include theNew
keyword. This is because VB allocates the memory for the UDT at the time that it encounters theDim
statement.How much memory does VB allocate? You can use the Len function in VB to find out how much memory VB allocated for the structure. In this caseLen(Acct)
returns 14 bytes. The 14 bytes come from 4 bytes for the AccountType member, 2 bytes for the Active member, and 8 bytes for the Balance member. However, because of VB's 4-byte alignment, we need to adjust the Active member to 4 bytes (each member needs to occupy memory in multiples of 4 bytes). This means that the structure really requires 16 bytes of memory. In fact, VB's LenB function returns the exact number of bytes (16) that the UDT requires.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Memory Layout of Interfaces
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterYou know that the interface is just a group of functions, but what is it really in terms of memory? Well, to understand interfaces, you have to know how a client binds to functions in a DLL.Whenever you load a program, the code for the program is mapped into virtual memory. The program uses a CPU register known as the instruction pointer that tells it in essence what line of code to execute next (in reality it stores the memory location of what machine instruction to execute next). Whenever the program encounters a call to a function or a subroutine, the machine code simply tells the instruction pointer to jump to the place in memory where the function resides.Thus, any time you make a method call, all that you are doing is changing the instruction pointer to point to a different piece of code. This is often referred to as making a "jump." The address of the next instruction after the jump instruction (the address that would have come next if we had not made the jump, often called the return address) is saved. When the program is done executing the functions, it issues a "return." The return simply sets the instruction pointer to the return address. (Granted, this is a simplified view, but this is in essence what happens.)DLLs contain a number of exported functions. Since making method calls is simply jumping to a particular place in memory, this means the client code needs to know where the code for the functions in the DLL resides. However, the code for these functions is not available to the client code at compile time; only the definition of the functions is available.Since the code is not available, it is impossible for the compiler to know where exactly in memory the code for the function resides. What the compiler does instead of writing the exact jump address at compile time is to build an import table. The import table is an array of memory addresses to the functions in the DLL. The import table has an exact location in memory at compile time. The compiler then generates code to use the addresses in the import table whenever your code makes a call to one of the imported functions. In essence, this means that if the DLL has a function likeAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - COM as a Binary Standard
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe rules of COM state that for a client to communicate with a COM object, the COM server must allocate the memory for the object, and all access to the object must occur through a COM interface. COM is said to be a binary standard because it further defines the memory layout of interfaces. An interface is a pointer to a lookup table of functions. The pointer is known as a vptr, and the lookup table of functions is known as a vtable. Thankfully, we do not work with interfaces at the vptr and vtable level. If you were working in C (not C++), you would have to code a vptr and a vtable by hand, because the language does not offer any natural mappings of these structures to high-level language features. C++ and Visual Basic, however, do map interfaces to classes.When a C++ developer marks a function as virtual in a class and creates an instance of the class or creates an instance of a class that derives from a class with virtual functions, the C++ compiler creates a virtual function table (vtable) to represent the virtual functions of the class. Remember, the vtable is an array of pointers to functions. To each class that has virtual functions or derives from a class that has virtual functions, the C++ compiler adds a hidden data member known as a vtable pointer (or vptr). This hidden member is a long integer (4 bytes) that stores the address of the vtable array that corresponds to the class. The first 4 bytes of an object in memory will therefore be the vptr.An interface in C++ is a class that has only pure virtual functions. Pure virtual functions are virtual functions that do not have an implementation. A class that has pure virtual functions cannot be created directly—it must be implemented in another class. A C++ developer normally creates a concrete class to implement the interfaces class. The standard mechanism for doing so is to derive the concrete classes from the interface classes you wish to implement.Figure 3-3 shows you the relationship between a C++ class, a vtable, a vptr, and a member variable in memory for a class that uses multiple inheritance to implement interfaces. Notice from Figure 3-3 that the first 8 bytes in the memory representation of the object store the addresses of two vtables containing pointers to the functions of each interface.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Type Libraries
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIt's time to leave the pre-COM era behind. Let's look at the server and client code the way that it exists today using COM. It makes sense at this point to look at each line of a client program and study what VB is doing for us.Suppose that we start with the CChecking class defined in the following code:
' Class CChecking Option Explicit Private m_cBalance As Currency Public Property Get Balance( ) As Currency Balance = m_cBalance End Property Public Sub MakeDeposit(ByVal Amount As Currency) m_cBalance = m_cBalance + Amount End Sub
The VB client code to use this class is the following:Dim Acct As CChecking Set Acct = New CChecking Call Acct.MakeDeposit(5000) Set Acct = Nothing
In the preceding client code, VB first allocates 4 bytes of memory to hold the address of an object. It does this in the declaration of Acct:Dim Acct As
CChecking
. In the next line, VB does a couple of things. Although it appears that theNew
keyword causes VB to allocate the memory for the object on the client side, you have learned that this is not the case with the COM mechanism (in fact, this is not a good technique when it comes to upgrading objects where there might be two different definitions, one in the client and one in the server). Therefore, this code causes the server to allocate memory for the object. At that point, VB creates a vtable for the CChecking class. The entries in the vtable are pointers to the public functions of the class. The memory layout of the_CChecking
interface contains the vptr in the first 4 bytes, which tells the object where in memory the vtable exists. The memory address of the object itself is saved in the 4 bytes allocated for the Acct variable. At this point, the Acct variable points to the_CChecking
interface in memory. The VB compiler knows that the Acct variable refers to a COM object and that, therefore, the variable points to a vptr to a vtable.When the client code executes theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - COM Standard Interfaces: IUnknown and IDispatch
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far you have seen how interfaces are represented in memory and what an object like CChecking looks like in memory when it has a single interface, the default interface. Let's shift now to the case in which a developer adds functionality to the CChecking class by defining another interface,
IAccount
, and implementing the interface in the object. The following code shows how a developer might do this:' Class IAccount Option Explicit Public Property Get Balance( ) As Currency End Property Public Sub MakeDeposit(ByVal Amount As Currency) End Sub ' Class CChecking Option Explicit Implements IAccount Private m_cBalance As Currency Private Property Get IAccount_Balance( ) As Currency Balance = m_cBalance End Property Private Sub IAccount_MakeDeposit(ByVal Amount As Currency) m_cBalance = m_cBalance + Amount End Sub
The client code using this code would look like the following:Dim Acct As IAccount Set Acct = new CChecking Call Acct.MakeDeposit(5000) Set Acct = Nothing
What VB does in this case is a little different. When the object is allocated in memory on the server side, VB builds two vtables. One vtable contains the public members of the_CChecking
default interface. As it is right now, there are no public functions in CChecking. Nonetheless, if there were, then they would be part of a vtable. When VB sees theImplements
statement in the server code, VB allocates a separate vtable to contain the public functions for theIAccount
interface. This is the vtable that has the Balance and MakeDeposit function entries. The addresses of the functions in this vtable point (in essence) to the implementation code in the CChecking class. There are now two vptrs floating around in memory: one for the_CChecking
vtable and one for theIAccount
vtable. Now it is not so simple to map the client variable to the correct vtable. It takes a little teamwork.It appears from studying the memory layout of VB objects that when VB allocates memory for the CChecking class, it creates two subobjects, one whose layout starts with a vptr to theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf your head is spinning, it is because this is difficult stuff. The good news is that VB does almost everything for you automatically.In this chapter you learned the memory layout of interfaces. The main thing to remember is the memory layout of an interface is the same in every language: a memory address known as a vptr points to a vtable. A vtable is nothing more than an array of pointers to functions. Each vtable begins with pointers to functions of the
IUnknown
interface. In fact, the true definition of a COM object is an object that implements theIUnknown
interface.IUnknown
enables us to do two main tasks. First, it gives us a mechanism by which we can accomplish polymorphism (through QueryInterface). Second, it gives us two methods (AddRef and Release) by which we can do reference counting.Some clients are not able to use just any interface directly. For these clients, Microsoft provides a special interface known asIDispatch
.IDispatch
enables a client to ask the server to execute a method on its behalf using its name. A client usingIDispatch
first asks for a DispID for a certain method using the GetIDsOfNames function. Then, it calls the Invoke function to execute the method. VB automatically adds support forIDispatch
to every COM object. In fact, every interface created in VB is a dual interface. A dual interface is one that is derived fromIDispatch
, instead of directly fromIUnknown
.In the next chapter, you will learn how VB COM objects are packaged. We are also going to fill in some of the holes of how clients communicate with servers in COM.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 4: In-Process Servers
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the last chapter, you learned about the memory layout of VB COM objects. In particular, you learned how VB allocates memory for objects with multiple interfaces. You also learned how VB enables you to request different portions of this memory using the QueryInterface method of the
IUnknown
interface (henceforth referred to as QI ). Most important was the idea that all interfaces are created equal. In other words, the memory layout of an interface in any language is basically the same—it is a virtual table pointer (vptr) pointing to a virtual table (vtable). A vtable is nothing more than an array of pointers to the addresses of functions in memory. COM rules state that the first three functions in the vtable of a COM interface must be the methods ofIUnknown
: QueryInterface, AddRef, and Release. You learned from Chapter 3 that Visual Basic built a little object to manage theIUnknown
implementation for the entire object. You also learned some of the COM rules for allocating memory in the last chapter. One rule discussed in the chapter was that memory for COM objects must be allocated by the server code. You also learned that the server provides the definitions of its COM objects for the client through a file called a type library.In this chapter, you will learn the whole story of activation for ActiveX DLLs. The term activation refers to the process that occurs at the API level from the time the client requests a new server object to the time it can use this object. For example, consider the following code:Dim Account As IAccount Set Account = New CChecking Call Account.MakeDeposit(5000)
In this chapter, we are going to focus on what happens in the second line of code:Set Account = New CChecking
. However, before we go into too much detail on the activation process, let's see how it is that COM components are packaged and used from a client application at a high level.To many of you, this will be review. Nonetheless, let's take a minute for a high-level examination of the process of building a COM server and using it from a client program at a high level.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Client-Server Communication: A High-Level View
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterTo many of you, this will be review. Nonetheless, let's take a minute for a high-level examination of the process of building a COM server and using it from a client program at a high level.Using the same classes as in the last chapter, let's build a COM server and use it from the client. The first step in building the server is to decide on the packaging. The packaging comes in three flavors: ActiveX EXE, ActiveX DLL, and ActiveX OCX. This book does not discuss ActiveX OCXs, although for all practical purposes they are the same as ActiveX DLLs except that the COM components they export can be inserted into ActiveX containers (such as the VB Form object). In this chapter, we will focus on the ActiveX DLLs. You will learn about ActiveX EXEs and the COM remoting architecture in the next chapter.If you have not already done so, start Visual Basic 6. When you see the New Project dialog box, double-click on the ActiveX DLL entry. You should now have a project called Project1 with a single class module called Class1. Change the name of the class module to
IAccount
, and add the following code:Option Explicit Public Property Get Balance( ) As Currency End Property Public Sub MakeDeposit(ByVal Amount As Currency) End Sub
You may recall from Chapter 2 that this class serves as an interface definition. Because it is meant to be an interface and not a standalone class, change the Instancing property to2 - PublicNotCreatable
. Add a second class module to your project using the Project → Add Class Module menu option. Change the name of the class to CChecking and enter the following code in the module:Option Explicit Implements IAccount Private m_balance As Currency Private Property Get IAccount_Balance( ) As Currency IAccount_Balance = m_balance End Property Private Sub IAccount_MakeDeposit(ByVal Amount As Currency) m_balance = m_balance + Amount End Sub
If you are unsure why there is a line that readsImplements IAccount
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Client-Server Communication: A Low-Level View
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterLet's begin by examining what is required for a client to be able to create a COM object that lives in a DLL. (In Chapter 5, you will see that the process is slightly different for ActiveX EXEs.) But first you must learn the true name of a COM component.As we noted in Section 3.5 in Chapter 3, the official name for classes and interfaces is not the string name you assign to the class or interface while developing in VB. You may recall that QI enables developers to ask an object for a particular interface implementation. It also enables developers to find out if an object in fact supports an interface. The first parameter in QI is the interface "name." It is an
input
parameter. The second parameter is anout
parameter returned by the object with a pointer to the vptr of the requested interface.The nameIAccount
is not unique enough for QI to work for every interface ever defined. Think about how many companies writing COM-based banking applications may use the nameIAccount
for their primary interface definition. QueryInterface would not know if you were asking for company A'sIAccount
or company B'sIAccount
. Therefore, Microsoft decided to use another mechanism for naming interfaces. Instead of using the string name, COM identifies each interface by a number—a very big number known as a globally unique identifier, or GUID.A GUID is a 128-bit number. An example of a GUID is 36B1C83C-62D0-4199-AF2E-A7A73505EA65—the registry is full of them. In fact, most of COM's registry keys can be found in four locations:HKEY_CLASSES_ROOT
,HKEY_CLASSES_ROOT\CLSID
,HKEY_CLASSES_ROOT\TypeLib
, andHKEY_CLASSES_ROOT\Interface
. If you look at the registry with Regedit.exe, you will notice that the registry hierarchy is divided into four main trees. Microsoft has suggested that theHKEY_CLASSES_ROOT
tree in the registry (normally abbreviated asHKCR
) should be used for storing information about COM components. Microsoft provides an API function calledAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 5: Out-of-Process Servers and COM's Remoting Architecture
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the last chapter, you learned about in-process activation. You learned what information is stored in the type library and what the client has to do to use vtable binding. We have also been talking about what constitutes an interface. An interface stored in a VB variable is simply the address of a vptr to a vtable. In the last chapter, you also learned about the process by which COM loads DLLs into memory. We discussed that when you call
New
, VB translates theNew
command into a call to CoCreateInstanceEx, the function responsible for creating instances of a class.In this chapter, you will learn about COM's remoting layer. You will also learn about apartments. Apartment architecture enables components that are thread safe to talk to components that are not thread safe.EXEs load in their own address space. While there are tricks for sharing memory between two executables, for the most part, every executable loads in its own protected memory space. The memory space is 4 GB. This doesn't mean that by installing Windows your machine receives 4 GB of RAM. Most of us mortals have far less physical memory than that. However, the operating system simulates that each process runs in a memory space of 4 GB. In reality, the OS uses a swap file to map virtual memory to physical memory. The details of how the memory mapper works are beyond the scope of this book. However, it is sufficient for us to know that the memory of one process is protected from another process. This means that if you launch an executable twice so that there are two running instances of it, they do not share memory. In other words, if your code uses global variables, each executable has its own copy of those global variables.It is possible to have a COM server live in an executable. You do this in VB by creating an ActiveX EXE project. An ActiveX EXE is a COM server like an ActiveX DLL, but because it is an executable instead of a DLL, there are a few differences in the way they work:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - ActiveX EXEs
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEXEs load in their own address space. While there are tricks for sharing memory between two executables, for the most part, every executable loads in its own protected memory space. The memory space is 4 GB. This doesn't mean that by installing Windows your machine receives 4 GB of RAM. Most of us mortals have far less physical memory than that. However, the operating system simulates that each process runs in a memory space of 4 GB. In reality, the OS uses a swap file to map virtual memory to physical memory. The details of how the memory mapper works are beyond the scope of this book. However, it is sufficient for us to know that the memory of one process is protected from another process. This means that if you launch an executable twice so that there are two running instances of it, they do not share memory. In other words, if your code uses global variables, each executable has its own copy of those global variables.It is possible to have a COM server live in an executable. You do this in VB by creating an ActiveX EXE project. An ActiveX EXE is a COM server like an ActiveX DLL, but because it is an executable instead of a DLL, there are a few differences in the way they work:
-
By putting components in an ActiveX EXE, you are declaring that the client program and the server process will live in different address spaces. The fact that the server and the client do not share an address space means that potential defects in the ActiveX EXE (i.e., bugs) will not make the client crash. More importantly, if the client program crashes, it will not make the ActiveX EXE crash, unless it manages to bring down the OS, which is very difficult to do in VB.
-
In the case of a DLL, variables in the DLL cannot be shared among different client programs. Why? The answer is that, as we mentioned earlier, a DLL does not run in its own address space. Each instance of the client program will load its own copy of the variables in the DLL. In the case of an executable, each client will use components that live in the same executable. Therefore, each instance of a COM object can share state through global variables (with certain exceptions to be discussed later).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! -
- Threads
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEvery process in the operating system begins executing code with a single thread. The OS does not really see processes when it is time to run code—it sees threads. When the operating system starts a process (an executable), the code for that executable begins with a thread. The first thread (the one that every process gets when it is launched) is called the main thread. A process continues to live as long as the main thread lives. The OS assigns each thread a unique thread ID. Any process can reach a thread (if it has the right permissions) by using its ThreadId. In the same fashion, the OS also assigns each process a process ID, or PID.Every thread defines an execution sequence. The OS demands that each thread be attached to a procedure called the thread procedure, or ThreadProc. The main subroutines's thread procedure is main in console applications or winmain in Windows applications. In Visual Basic, the code for the winmain procedure executes the VB procedure
Sub Main
, if there is one. In fact, as you will see later,Sub
Main
is a procedure that Visual Basic runs for every thread that it launches.Threads are kernel objects, which means that the code in kernel.dll is responsible for creating, destroying, and managing threads for the system.The OS does not wait for each thread to be done with its task. The OS has a scheduler that gives each thread a certain amount of time to run based on the thread priority. Each thread receives a portion of time, known as a quanta, to execute code. When its time has expired, the system then suspends the thread and gives another thread a chance to run. In fact, the OS code itself runs in a thread, so the OS sets up a hardware interrupt that occurs regularly and allows the OS to take over. Because each thread must share physical memory and CPU registers, the OS has to save a thread's state information, then load the registers and memory with information for another thread. This switch of information is called a thread switch.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Remoting and Location Transparency
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBefore COM there was RPC, a protocol defined by the Open Software Foundation and known as Remote Procedure Calls (RPC) for a Distributed Computing Environment (DCE). Microsoft implemented this protocol in Windows NT as MS RPC. RPC is a binary protocol meant to run on top of any other network protocol, such as IP or UDP.MS RPC uses the concept of interfaces. A developer defines an interface using the Interface Definition Language (IDL). The developer also generates code for two stubs (in RPC terminology, both the sender and the receiver are known as stubs). The stub on the client side basically looks like the interface. In other words, it has methods with the same signatures and names as the methods and signatures on the server side. However, the methods in the client stub do not do the real work. They take the parameters of a call and build a byte stream according to the format dictated by RPC. Network Data Representation (NDR) is used to convert the parameters into a representation that can be understood by a number of operating systems. Information is also added about the destination of the byte stream. On the receiving side, an RPC service listens for RPC data on a well-known port. The port number depends on the protocol the server can accept. The service listens for requests, then interprets the byte stream to figure out to which server stub information should be forwarded. The RPC listening service dispatches a thread to communicate with the stub on the server side. The server-side stub receives the information and unpackages it using NDR once again. The server-side stub builds a parameter list and calls the function specified in the byte stream. The client thread is blocked for the duration of the call. When the server stub executes the call and the call finishes, it sends the client a response message. The response message will contain the return parameters from the call. The client stub is then unblocked. The result is that the client believes it is making a call locally when it is in fact making a call with a remote server.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Pinging Mechanism
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAnother function of the SCM is to handle the pinging mechanism. It is easy for a client to know when a server is no longer available due to a crash. If a client tries to make a call to a server object that is no longer available through an interface proxy, the COM interceptor will generate an error. It is not so easy for the server to know if the client has crashed. The local SCM sends the remote SCM a ping every two minutes. The ping contains information about active clients. Each ping does not list all the clients in the machine, but rather the change in the number of clients from one ping to the next. If the server realizes that the client is no longer connected, it releases the outstanding references for that client. If the server misses three pings from the client, as in the case when the client's machine has been disconnected from the network, the server will automatically release all the references from any clients from the missing machine. In other words, if a client crashes, six minutes later the server finds out and releases the client's references to its objects. There is no way to change the ping interval or the number of pings that must be sent before the resources are reclaimed.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, you learned about out-of-process servers. The first thing you learned was that like DLLs, EXEs have to perform four main tasks: registration, unregistration, proper termination, and object creation (exposing their class objects using class factories). Registration and unregistration are done with command-line parameters:
/RegServer
and/UnregServer
. To expose its class objects, the SCM uses the command-line switch-Embedding
. The-Embedding
switch tells the ActiveX EXE to register its class objects with the system's class table. The SCM then searches the class table for the class objects. If the class table does not have a class object that meets the client's request, the SCM launches the executable.COM objects live in apartments. VB COM objects live in single-threaded apartments (STAs). Whenever communication occurs between apartments, it happens through a proxy and a stub. Communication through proxies and stubs is much slower than direct communication. To use an object from another apartment, we must export the object's interface from one apartment and import it into the client's apartment. To export the object's interface means to marshal it. Marshaling the interface creates a stub. To create the stub, the universal marshaler needs to have access to the server's type library. This is also the case when the object needs to be imported into the client's apartment. In this case, the universal marshaler needs to build a proxy from the type library. This means that both the client's machine and the server machine must have the type library registered. In the case of a VB client program using CreateObject with a remote parameter, you must also register the ProgID. Remember that the ProgID is the string name of the class (project name + "." + class name).Communication between a client and an object that lives in a different machine is done through ORPC. The ORPC protocol is built on top of RPC. When you specify to create an object remotely, the SCM does not search the registry for anInprocServer32
key or aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 6: Versioning
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf you know the phrase binary compatibility, you and I share the same pain. If you have never heard these words, then this chapter will spare you from the pain. This chapter is about versioning your COM components. Whenever I teach a course at a company, there is always a student who wants to know COM's versioning scheme. People often have the idea that COM has a great versioning story. The truth is that COM's versioning mechanism is very simple—once you have published an interface, you are not allowed to change it ever again. That's it! If you never change interfaces that you have published, then you do not have a problem with versioning.The reality, however, is that often we cannot live with an interface after it has been released without modifications. At the very least, we would like to extend the interface to add new functions. The truth is that COM interfaces cannot be changed, period, not even to add functionality. To understand why, let's first discuss the goal of COM's rigid versioning rule. Then we'll discuss the different kinds of client programs and what each of them requires in terms of versioning. After that, we'll talk about why it is difficult to version things in Visual Basic. Once we have discussed the problems, I will show you the mechanism that Visual Basic offers for versioning. Although I am a big fan of Visual Basic in general, I am not fond of VB's versioning scheme. Therefore, at the end of the chapter, I will show you a better way to version your interfaces using the Interface Definition Language (IDL).Many of the rules of COM have to do with solving the problems faced by the designers of COM. One problem was locating COM servers (DLLs and EXEs). In the days of VB Version 1 through Version 3, Visual Basic developers used a specialized form of DLLs known as VBXs. VBXs were renamed DLLs that had, aside from DllMain, specialized entry point and termination functions. VBX controls were essentially window controls. The main problem with VBXs was that their window message loop functions required five parameters instead of the four parameters that all standard window message loops had. The extra parameter was a VB-assigned handle to the control. Therefore, every message that was sent to one of these specialized windows had not only the window handle (that every window object must have) but also the VB handle that the developer needed to use for the control to interact with the environment. It was a fairly good system if the VBX was going to be used only with VB, but it had almost zero extensibility because it required other programming environments to change the way they interacted with window objects. A major problem with VBXs (and with DLLs in general) was difficulty assuring that the correct versions of all components were shipped with an application.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Goal of COM Versioning
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterMany of the rules of COM have to do with solving the problems faced by the designers of COM. One problem was locating COM servers (DLLs and EXEs). In the days of VB Version 1 through Version 3, Visual Basic developers used a specialized form of DLLs known as VBXs. VBXs were renamed DLLs that had, aside from DllMain, specialized entry point and termination functions. VBX controls were essentially window controls. The main problem with VBXs was that their window message loop functions required five parameters instead of the four parameters that all standard window message loops had. The extra parameter was a VB-assigned handle to the control. Therefore, every message that was sent to one of these specialized windows had not only the window handle (that every window object must have) but also the VB handle that the developer needed to use for the control to interact with the environment. It was a fairly good system if the VBX was going to be used only with VB, but it had almost zero extensibility because it required other programming environments to change the way they interacted with window objects. A major problem with VBXs (and with DLLs in general) was difficulty assuring that the correct versions of all components were shipped with an application.If you were ever involved in the distribution of Visual Basic applications in Visual Basic 3, you know that half of your technical support problems were related to what people refer to as DLL Hell. DLL Hell is concerned with these two issues: do we have all the DLLs the application needs, and do we have the right versions?The problem with finding the DLLs stemmed from the absence of clear guidelines for where to put DLLs and VBXs. Microsoft had theirs in the Windows\System directory. Some vendors preferred putting things in the Windows directory, and some vendors had components in their installation directory. Sometimes an application needed to ship a later version of a component that was shared by multiple applications from different vendors. Often this caused a major problem, because indubitably one of the older applications from a different vendor would stop working. An even bigger problem was that a single machine could contain multiple copies of a DLL or VBX. Vendor A would release an application and install VBX Z in theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Client Requirements
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterVtable-bound clients are clients that can talk to an interface directly. They include Visual Basic client programs in which you
Dim
a variable as an interface type (or as a class—VB interprets this as a request to use the default interface), Visual C++ clients, Delphi clients, and VBA clients (such as Word and Excel scripts). Scripting clients are clients that do not use interfaces directly. They include ASP scripts, client-side VBScript or JScript, Windows Script Host scripts, and so on. The requirements for these two types of clients are different. The former group has more stringent requirements than the latter.Let's begin with the easy group—the scripting clients. Scripting client code looks like the following:Dim Checking Set Checking = Server.CreateObject("BankServer.Checking") Call Checking.MakeDeposit(500)
But it may also look like the following:<object id="Acct" classid=clsid:C5D33E92-591E-4D3B-B796-1918DA093531></object> <SCRIPT Language=VBScript> Call Acct.MakeDeposit(500) </SCRIPT>
If you examine the first example, you will notice some things that need to stay the same in the next version of the component for the code to continue to work unchanged. One thing that must stay the same is the ProgID,BankServer.Checking
. Remember that the ProgID comes from the project name plus the class name. The second dependency is the name of the function MakeDeposit. How about the parameter types? The only datatype that scripting clients let you use is the Variant. The Variant type is similar to a UDT, with data members to store the different types that the Variant supports and one data member that tells the code what type is currently being stored in the Variant. The following VB UDT represents roughly (and in part) what the Variant type looks like:Enum VariantTypeConstants VT_I2=2, VT_I4=3, VT_I8=20, VT_BSTR=8, VT_BOOL=11, VT_UNKNOWN=13, VT_DISPATCH=9 'There are many other type constants supported in the VARIANT type End Enum Type VARIANT vt As VariantTypeConstants lVal As Long bVal As Byte iVal As Integer fltVal As Single dblVal As Double boolVal As Boolean bstrVal As String punkVal As IUnknown pdispVal As Object 'There are many other types supported in the VARIANT UDT. End Type
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - COM's Versioning Story
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterCOM's versioning solution for vtable-bound clients is that every interface receives an IID and that interfaces are immutable once they are published. Once you publish the interface, you must keep it the same—no changes whatsoever. If you change an interface, then according to the COM rules you must assign it a different IID. If you assign a new IID to the interface, then you must decide what happens when a client requests an old IID. You have a choice in this case. You may decide that old clients must continue to run, in which case you do not touch the old interface. You simply create a new interface with the old methods plus your changes, and you implement both the old interface and the new interface in the component. For example, let's say that the first version of the
IAccount
interface is defined as follows:'interface IAccount version 1 Public Sub MakeDeposit(ByVal Amount As Long) End Sub
Then the code for version 1 of theCChecking
class may be the following:'class CChecking Implements IAccount Private m_Balance As Long Private Sub IAccount_MakeDeposit(ByVal Amount As Long) m_Balance = m_Balance + Amount End Sub
Let's say that later you must change Amount to be a Double instead of a Long. Then you would define a new interface:'Interface IAccount2 (IAccount version 2) Public Sub MakeDeposit(ByVal Amount As Double) End Sub
Now that there is a new interface, the new version of CChecking would support both interfaces, as follows:'class CChecking version 2 Implements IAccount Implements IAccount2 Private m_Balance As Double Private Sub IAccount_MakeDeposit(ByVal Amount As Long) Call IAccount2_MakeDeposit(Amount) End Sub Private Sub IAccount2_MakeDeposit(ByVal Amount As Double) m_Balance = m_Balance + Amount End Sub
Notice that the implementation of the old interface simply forwards the calls to the new implementation.What if it does not make sense to support theIAccount
interface any longer? Then you have two options. You can continue to implement the old interface but return an error with a nice description informing the user that she must obtain a new version of the interface. The second option—dropping support for the old interface altogether—is very risky. However, you must have foresight. Before you write the first version of the client program, you must be aware that the interface you are using may be dropped in later releases. That means that you must code the client program with special logic from the start. For example, all VB interfaces have something in common—they are dual interfaces. That means that they have support forAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - How Visual Basic Versions Your COM Objects
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe good thing about VB is that it does almost everything for you; the bad thing about VB is that it does almost everything for you. What I mean is that sometimes it would be easier if the developers of VB let you take control of certain features. There are many times that I wish the toolbar had a button called Manual Mode that would let me take out the autopilot. Versioning is one of those categories in which VB's help actually makes it harder for you.The problem is that you never deal with GUIDs directly in VB. They are generated for you automatically when you compile your program or when you run your program in the debugger. Because of the nature of GUIDs (the fact that they are guaranteed to be unique), you must tell VB when it is appropriate to generate a new GUID or when it must keep the GUIDs the same. If VB were to change some crucial GUIDs, such as the IID of an interface, any client programs that depend on the GUID would stop working.Visual Basic has three options that enable you to control how it generates GUIDs. (Remember that GUID generation occurs when you compile your server or when you run your server code in the debugger.) These three options produce four different configurations. You will find the three settings in the Project → Properties dialog box, under the Component tab, as shown in Figure 6-1.Figure 6-1: Version configurationsThe three settings are Binary Compatibility, Project Compatibility, or No Compatibility. However, when you choose Binary Compatibility, you may end up with two different configurations: Binary Identical or Binary Compatible.If your clients use vtable binding, then they expect all interface IIDs to remain the same. Binary Compatibility tells VB to keep all the GUIDs the same. This includes LIBIDs, CLSIDs, and IIDs. Notice that this is notAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Using IDL
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf you believe, as I do, that VB's versioning scheme is more trouble than it is worth, a better way to gain complete control over GUIDs is to define your interfaces with the Interface Definition Language (IDL). Defining your interfaces in IDL has several advantages:
-
You eliminate the overhead of having a class for each interface in a VB project.
-
You have complete control over when GUIDs change and why.
-
If you use IDL and use CreateObject in your client code (for reasons that will be obvious shortly), then you can set the versioning setting in VB to anything you wish and it will not affect whether the clients work or not.
The only disadvantage in using IDL is that you have to learn how to use it, and for some reason VB developers shy away from it.You learned about IDL in Chapter 4. IDL is not a full language in the sense that it does not allow you to write loops or have if...then...else statements and so on. IDL is a syntax language for defining interfaces. IDL enables you to build standalone type library files. Once you define your interface in IDL, you can compile it with MIDL, the Microsoft IDL compiler. MIDL can produce a variety of files, including header files for C++ clients, proxy-stub code for standard marshalers, and, most importantly for us, a standalone type library file. It would be impossible for me to show you every aspect of IDL in this section of the chapter, so I am going to show you the essentials for building a type library in IDL.In Chapter 4, you learned that you can reverse-engineer a type library and obtain the source for the type library in IDL using OLE/COM Object Viewer. In addition to showing you the source for a type library, COM Viewer lets you save the source to a text file.By far the easiest way to generate IDL is to start with a prototype project in Visual Basic. The prototype project can contain the definition of all the interfaces in your project. You can then compile the project and use COM Viewer to extract the IDL. When you are satisfied, you can then forget about the prototype and manage the interfaces through the IDL source code. The best part about it is that everything that you can define in Visual Basic can be represented in IDL; the VB compiler would stop you from compiling something that would be illegal in IDL syntax.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! -
- Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, you learned how to version your COM servers. The degree of versioning has to do, to a certain extent, with the type of client you are developing. It is easier to develop for scripting clients because they do not use interfaces directly. That means that you can change your interfaces without breaking existing client code. You can, for example, add optional parameters to methods. You also do not have to worry about versioning settings in your VB project, unless your scripting code uses the
<OBJECT>
tag with theCLSID
property. Then you must ensure that all CLSIDs remain the same.When vtable-bound clients use your components, you have to be careful that interface definitions do not change. The COM specification says that once an interface has been published, it must not be changed. A change to the interface means that you must change the IID for the interface—in other words, you must rename it.Visual Basic automatically generates GUIDs for you each time you compile and each time you run your project in the debugger. For this reason, you must tell VB when you wish to keep GUIDs the same and which GUIDs to keep the same. Your options are Binary Compatibility, Project Compatibility, or No Compatibility. If you choose Binary Compatibility, you are telling VB to preserve all GUIDs. Project Compatibility tells VB to preserve only the LIBID and all CLSIDs. No Compatibility tells VB to generate brand new GUIDs for everything.You learned in this chapter that it is very easy to break Binary Compatibility and that, when you break Binary Compatibility, all IIDs (not just the one for the class that broke compatibility) change. A change to all IIDs means that all your vtable clients must be rebuilt.To take full control of versioning, it is better to use IDL to define your interfaces. IDL enables you to define an external type library. If you use an external type library plus the CreateObject function, the setting you use for versioning in your VB project does not matter.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 7: COM+ Applications
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterChapter 1 through Chapter 6 focused on what is typically known as the core COM architecture. It gave you an inside view of what interfaces look like in memory as well as how in-process servers are activated and deployed and how out-of-process servers differ. Chapter 7 through Chapter 10 are all about the COM+ architecture and services. In this chapter we move beyond the core COM architecture and begin exploring what COM+ is.The COM+ principle is based on the following idea: let Microsoft do it for you. If you think about the success of Visual Basic, a lot of it can be attributed to the vast number of third-party controls. Third-party controls offer a lot of features and enhancements that can be instantly added to your application to create rich user interfaces. With controls, another group of developers creates and maintains the functionality. Imagine how long it would take you to create an application if you had to create your own grid control or your own 3-D charting tool.Along the same lines, a number of features that would be too difficult to implement by hand are necessary in distributed business applications. These features include group-based (or role-based) security, distributed transactioning, component load balancing, automatic data replication, the creation of client setup programs, synchronization, thread pooling, sharing of resources, and so on. All of these features or services are too time consuming to add by hand, yet they are a critical component of most distributed business applications. It would be nice if all you had to do was focus on the business logic for your middle tier and then add these features later when the client requested them. That is the core idea behind COM+. Microsoft would like for you to focus on the development of your components, then for you to entrust your components to them. They offer an environment in which you can add your components and, without having to recompile your application (at least that's the hope), automatically add the features mentioned earlier with the flick of a switch. In other words, you create your banking components, and later if you wish to add something like role-based security, all you have to do is create security groups and check a checkbox that turns on security checks.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Creating a COM+ Application
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterLet's create a COM+ application to get a feel for the "big picture." COM+ applications are created with a tool that ships with Windows 2000 (in all of its flavors) called Component Services. Component Services is an add-in for the Microsoft Management Console system (MMC). All this means is that it has a very recognizable frontend and works similarly to other MMC add-ins. To run this tool, choose Start → Programs → Administration Tools → Component Services. Figure 7-1 shows the Component Services administration tool.Figure 7-1: The Component Services Administration toolAs the tree-view pane in Figure 7-1 shows, there are three main branches: Component Services, Event Viewer, and Services. The only branch of interest for our discussion is Component Services. If you expand it, you will find a Computers folder and, if you expand that folder, you will find the My Computer entry.It is possible to manage multiple Windows 2000 computers from one console. You do this by right-clicking on the Computers folder and choosing New Computer from the pop-up menu, then entering the name of the computer you wish to manage. Chances are that you will not have security privileges to make changes to the other machine's settings. (I will show you how to restrict access to other machines in Chapter 10 when we discuss security.)If you right-click on a branch and do not see the menu options I am describing in the pop-up menu, it may be because of a quirk with Component Services. Menu options are based on the item that has the focus. Therefore, you may need to click on the branch first to give it focus, then right-click to see the appropriate pop-up menu.If you expand the My Computer branch, you will find two folders: COM+ Applications and Distributed Transaction Coordinator. The Distributed Transaction Coordinator (DTC) is a piece of software that enables multiple resource managers (databases, for example) to participate in a single transaction as one unit. You will learn all about the DTC in Chapter 9. If you expand the COM+ Applications branch, you will see a number of COM+ applications. To create a new application, right-click on the COM+ Applications folder and select NewAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Services Overview
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that you know how to create a COM+ application, add your components to it, and deploy it, you may be wondering about the advantage of having a COM+ application in the first place. The advantage is that adding components to your application enables you to use a number of COM+ services. If you examine the properties of a component in the COM+ Services Administration program (right-click on the component and choose Properties), you will notice that there are a number of services, which are available at different levels: the application, component, interface, and method levels of a COM+ object. The following list briefly describes each service and indicates whether it is available to library applications—if the item does not read "server applications only," the service is available for both library applications and server applications:
- Process-level security (server applications only)
-
Helps you set up DCOM security. DCOM security affects how a client gains access to the application. Without COM+, you would have to configure DCOM security manually using dcomcnfg.exe. You will learn more about this feature in Chapter 10. (See the dialog box on the left in Figure 7-14.)
Figure 7-14: Application Security Properties- Component-level security
-
Enables you to restrict or grant access to a component's method by assigning access rights either at the component, interface, or method level based on roles. Roles are a collection of user accounts or groups. Only users in the role have access to the element to which you assign the role. You will learn more about this feature in Chapter 10. (See the dialog on the right in Figure 7-14.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - COM+ Administration Components
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIt is possible to administer a COM+ application through code. The code can be in a C++ client, a VB client, or even a VBScript or JavaScript client. To administer COM+ applications through code, you use the COM+ Administration Components. The first step in using these components in a VB client program is to reference the type library: choose Project → References and then select COM+ 1.0 Admin Type Library from the dialog box.The type library contains definitions of three coclasses: COMAdminCatalog, COMAdminCatalogCollection, and COMAdminCatalogObject. Each of these coclasses has a default interface:
ICOMAdminCatalog
,ICatalogCollection
, andICatalogObject
, respectively. COMAdminCatalog is the main component—this is the component you use to accomplish most of the administrative tasks. From COMAdminCatalog, you can request certain collections. When you ask for a collection through the GetCollection method inICOMAdminCatalog
, it returns a reference to anICatalogCollection
interface (the default interface of COMAdminCatalogCollection). You can then use theICatalogCollection
interface to navigate through the collection. To use a certain item in the collection, you call the Item method in theICatalogCollection
interface; that method returns a reference to theICatalogObject
interface. You can then use theICatalogObject
interface to set properties for an individual item in the collection.The following code fragment first deletes a COM+ application named BankServer if it already exists, then creates the application:Dim cat As ICOMAdminCatalog Set cat = New COMAdminCatalog 'connect to the catalog Dim AppColl As Object 'ICatalogCollection Set AppColl = cat.GetCollection("Applications") 'define an array of variants to use in the PopulateByKey function Dim Keys(0 To 0) As Variant Keys(0) = "{2EA3007E-7B96-450a-B37A-FFD7C621C6CA}" Call AppColl.PopulateByKey(Keys) Dim BankServerApp As ICatalogObject 'if the application already exists If AppColl.Count > 0 Then '...change deleteable property so that we can delete it Set BankServerApp = AppColl.Item(0) BankServerApp.Value("Deleteable") = True Call AppColl.SaveChanges '...delete it Call AppColl.Remove(0) Call AppColl.SaveChanges End If 'add a new application Set BankServerApp = AppColl.Add 'set the application properties BankServerApp.Value("ID") = "{2EA3007E-7B96-450a-B37A-FFD7C621C6CA}" BankServerApp.Value("Name") = "BankServer" BankServerApp.Value("Description") = "Bank Server Application" BankServerApp.Value("Activation") = COMAdminActivationLocal BankServerApp.Value("Changeable") = False BankServerApp.Value("Deleteable") = False AppColl.SaveChanges
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, you learned how to create COM+ applications using both COM+ Services and COM+ Administration Components. COM+ applications are packages that hold configuration settings for a group of components. These settings are known as services; a component that lives in a COM+ application is called a configured component. The goal of configured components is to provide functionality to your application without your having to add code. The dream is that you will be able to turn functionality on and off by simply changing a few settings in the COM+ Component Services Explorer. This may be true at some level, but the reality of the environment is that, to take advantage of some of the services, you have to code your components in certain ways. In fact, in the next chapter, you will learn how to interact with the environment. The bottom line is that for this code to work, your components expect to be running in the COM+ environment.COM+ applications fall into two main categories: server applications and library applications. Server applications run out-of-process to the client. Library applications run in the same address space as the client. You use library applications when you want to share a component among two or more applications and you want the components to run in-process to the applications.This chapter also focused on deploying the application for both server and client use. One of the main points in this chapter is that, in addition to your components, you can add standalone TLB files to a COM+ application. The reason you may want to do this is because it enables you to create client-side application proxies that do not require the DLL containing your components to be present and registered in the client machine. However, there appears to be a problem with the export process in COM+ that does not let this feature work if you add a standalone TLB file and the DLL contains an embedded TLB file as a resource. A workaround is to temporarily delete the TLB embedded in the DLL when creating the application proxy. You can do this using the VC++ IDE, viewing the DLL's resources, deleting the TLB, and saving the changes to the DLL. After creating the application proxy, you can restore the DLL to normal by recompiling it.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 8: Writing and Debugging COM+ Code
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the last chapter you learned how to create a COM+ application and how to administer it. You also learned about some of the services COM+ offers. Now, let's turn our attention to writing code for use in COM+ components to use those services. As I alluded to earlier, it is not really possible to develop components that work well inside COM+ and outside COM+. In order to take advantage of some of the COM+ services, you will want to code your components differently. Coding your components differently means that your component will expect the COM+ environment to exist.To write COM+ components that interact with the COM+ environment, you must reference the COM+ Services Type Library in your project (Project → References and then select the COM+ Services Type Library from the listbox). There are a number of interfaces, classes, user-defined types, and enumerated types in the type library. In this section you will learn about only a few of the objects. You will get a better taste for the rest of the objects and interfaces in the type library as we discuss each service throughout the book.Before you can write COM+ code, however, you must learn about the COM+ architecture.So far, you have learned how to manage applications at a high level through the Component Services Administration program or through code using the COM+ Administration Components. In this section, you will learn about how COM+ applications work internally.Server applications run within a surrogate process. You may recall from Chapter 5 that a surrogate process is a process that enables you to run in-process components in an out-of-process fashion. The name of the surrogate process is DllHost.exe. Library applications run differently. They do not need DllHost.exe because they run in the process of the client.A client creating a COM+ component has no idea whether the component is in-process, out-of-process on the same machine, out-of-process on a remote machine, configured, or nonconfigured. The client always creates the component usingAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - COM+ Architecture
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far, you have learned how to manage applications at a high level through the Component Services Administration program or through code using the COM+ Administration Components. In this section, you will learn about how COM+ applications work internally.Server applications run within a surrogate process. You may recall from Chapter 5 that a surrogate process is a process that enables you to run in-process components in an out-of-process fashion. The name of the surrogate process is DllHost.exe. Library applications run differently. They do not need DllHost.exe because they run in the process of the client.A client creating a COM+ component has no idea whether the component is in-process, out-of-process on the same machine, out-of-process on a remote machine, configured, or nonconfigured. The client always creates the component using CreateObject or
New
. The call is translated into CoCreateInstance or CoCreateInstanceEx, as you learned in Chapter 4. CoCreateInstance and CoCreateInstanceEx are API calls in OLE32.DLL.The activation process is the same as without COM+ from the client's point of view. From the server standpoint, the story is a little different. OLE32.DLL must ensure that the services you have requested are started automatically when the object is created. What's more, some services require that COM+ monitor methods before execution, after execution, or both before and after.For services to work, COM+ defines several boundaries. In Chapter 5, you learned about one of these boundaries: the apartment. The apartment is a boundary that separates objects that do not have the same threading requirements. Objects with the same threading requirements can be in the same apartment; objects with different threading requirements must live in different apartments. Other services require objects to live in different boundaries. Objects that have the same service requirements can live within the same boundary; objects that have different requirements must live outside the boundary.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Debugging COM+ Applications
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBecause the Visual Basic 6 debugger is very limited, debugging COM+ applications is not a trivial task. The biggest limitation is that the debugger cannot attach itself to a running process; it only knows how to debug code that is being interpreted and running under the VB 6 process. This means that you cannot debug COM+ server applications in Visual Basic, since these applications run inside DllHost.exe. A second limitation is that it can debug only single-threaded processes, which means that you cannot debug things like the STA thread pool. Note that you can debug all these things using the Visual C++ debugger. Therefore, one option for debugging VB COM+ code is to use the Visual C++ debugger, which is discussed as the second of the following debugging options; another option is to use trace messages by calling the Win32 OutputDebugString API.VB offers you limited debugging support for COM+ applications by simulating a COM+ library application environment. In order to offer you debugging support, VB does the job of DllHost.exe and acts as a surrogate process. Because VB treats your application as if it were a library application, debugging support is limited to features for library applications—you cannot debug server-only application features (see Chapter 7 for a complete list of server-only services). You also cannot debug the way your objects are created in different threads. This means that if you mark a component as synchronization Requires New, you cannot detect that the component has been created in a different thread. Furthermore, you also cannot test whether components are created in the STA thread pool correctly, since the VB environment does not support multithreading. However, it does enable you to test a number of features, such as role-based security and transactions.To enable debugging support, you need to tell VB that it should simulate the COM+ environment. Unfortunately, there is no option that explicitly tells VB to turn on COM+ debugging. The roundabout method is to change the MTSTransactionMode property in each of your class modules to something other thanAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 9: Transaction Services
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterPerhaps the most important feature in COM+ services is transactions. If you think about it, the predecessor to COM+ is Microsoft Transaction Server (MTS); the name implies that the main purpose of the product is to manage transactions.In this chapter, you will learn about transaction services. A lot of COM+ programming has to do with concurrent data access. In large systems, a number of clients may be using the same COM+ application, and each client may be calling the same methods and accessing and modifying the same data. To guarantee that each client can change data safely, we use transactions.A transaction in a database environment is usually defined as the movement of one or two pieces of data from one location to another in a way that guarantees their integrity. The definition of a transaction, however, is not limited to data in a database. It is also possible to involve other resources in the transaction. For example, COM+ transactions may involve MSMQ messages. (A full discussion of MSMQ—a product from Microsoft for sending and receiving messages—is beyond the scope of this book.) In order to ensure the integrity of data involved in them, transactions must meet the ACID rules. The acronym ACID stands for Atomic, Consistent, Isolated, and Durable. These terms have the following meaning:
- Atomic
-
The operation must succeed completely or be rolled back completely. In other words, it is an all or nothing operation. Atomicity is not usually the job of a client program; it is normally the job of the database system or the transaction coordinator.
- Consistent
-
Even though the data may not meet the rules of integrity for the database while a portion of the transaction is executing, by the time the transaction ends, the data must follow the rules of integrity. In other words, if the database rules state that a program may not delete a record from the database but may move it from one table to another, it is possible that at any given point the data in the database may not reflect the rule. For example, the program may add the record to the destination table and then delete it from the source table. In the first step, there may be two records that are identical, one in each of the tables. However, when the transaction succeeds, the data must meet the rules. Consistency is usually the job of the middle-tier component code. Only the middle tier can be certain of how many changes must be made to keep the database in a consistent state.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - What Is a Transaction?
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA transaction in a database environment is usually defined as the movement of one or two pieces of data from one location to another in a way that guarantees their integrity. The definition of a transaction, however, is not limited to data in a database. It is also possible to involve other resources in the transaction. For example, COM+ transactions may involve MSMQ messages. (A full discussion of MSMQ—a product from Microsoft for sending and receiving messages—is beyond the scope of this book.) In order to ensure the integrity of data involved in them, transactions must meet the ACID rules. The acronym ACID stands for Atomic, Consistent, Isolated, and Durable. These terms have the following meaning:
- Atomic
-
The operation must succeed completely or be rolled back completely. In other words, it is an all or nothing operation. Atomicity is not usually the job of a client program; it is normally the job of the database system or the transaction coordinator.
- Consistent
-
Even though the data may not meet the rules of integrity for the database while a portion of the transaction is executing, by the time the transaction ends, the data must follow the rules of integrity. In other words, if the database rules state that a program may not delete a record from the database but may move it from one table to another, it is possible that at any given point the data in the database may not reflect the rule. For example, the program may add the record to the destination table and then delete it from the source table. In the first step, there may be two records that are identical, one in each of the tables. However, when the transaction succeeds, the data must meet the rules. Consistency is usually the job of the middle-tier component code. Only the middle tier can be certain of how many changes must be made to keep the database in a consistent state.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Declarative Transactions
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAs you know, a number of COM+ features can be set through declarative attributes. One is setting transactions at the component level, known as declarative transactions. You can set the transactioning attribute of each component by using the component's Transactions tab in the Component Services administration program. The options are Disabled, Not Supported, Supported, Required, and Requires New. Through this declarative property, components decide whether they wish to participate in the outcome of the transaction. Every object that wants to participate in a transaction has one vote. All operations that the object performs occur during a transaction. At the end of the operation, all the votes are collected. Then the system either aborts the transaction or commits the transaction. You have to know when the transaction begins, when the transaction ends, what objects participate in the transaction, and how the components vote on the outcome of the transaction.Declarative transactions differ from local transactions in several ways. First, when you use declarative transactions, you do not call BeginTrans, CommitTrans, or RollbackTrans. Your code never manages the physical transaction directly. You specify the transactional requirements of your component through declarative properties. COM+ will begin the physical transaction when needed. Your code will simply vote on the outcome of the transaction. At the end, COM+ will collect all the votes and call CommitTrans or RollbackTrans on your behalf. Second, declarative transactions use distributed transactions instead of local transactions—they involve the DTC.To understand how components vote on the outcome of the transaction and how the COM+ plumbing manages the DTC transaction, you must first understand how transaction streams work.COM+ includes the concept of a transaction stream. Components in the same transaction stream participate in the outcome of the transaction. To become part of a transaction stream, a component specifies its transaction requirements through the Transactions tab of a component's Properties dialog box in the Component Services administration program. If you examine Figure 9-2, you will see the declarative attributes of a component.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, you learned how to create transactional components. You first learned what constitutes a transaction. You learned that transactions follow the ACID rules: Atomic, Consistent, Isolated, and Durable. Isolation controls how other transactions affect your transaction. Both SQL Server and Oracle let you control the degree of isolation for transactions.You also learned the difference between local transactions and distributed transactions. Local transactions involve a single resource manager. Distributed transactions involve the Distributed Transaction Coordinator (DTC). The DTC dispenses a resource known as an
ITransaction
pointer. OLEDB libraries can join a DTC transaction if they support theITransactionJoin
interface.COM+ has a service known as declarative transactions. In a declarative transaction, COM+ drives a DTC transaction. Your components are marked through declarative properties as transactional. The first component that is marked as Transaction Required or Transaction Requires New begins a new transaction stream and becomes the root of the transaction. The root of the transaction then creates secondary components. These components must be marked as Transaction Required or Transaction Supported to be part of the same transaction stream. Each component votes on the outcome of the transaction. When the root component is deactivated, the votes are collected. If no component voted to abort the transaction, the COM+ plumbing tells the DTC to begin the two-phase commit protocol. If at least one component voted to abort the transaction, then the COM+ plumbing tells the DTC to abort the transaction.Certain aspects of the DTC transaction—like its isolation level—cannot be changed through declarative properties. COM+ has a service that enables you to initiate the DTC transaction manually. This service is called BYOT.Through CRM you can involve non-distributed-transactional resources in a declarative transaction.In the next chapter, you will learn all about COM+ security, especially how security flows from a web application into a COM+ application.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 10: COM+ Security
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEveryone thinks security is necessary, but no one really wants to implement it. Developers often view security in the same light as setup programs—as a necessary evil that is put off until everything else is done. This chapter will make the transition to security easier. First, you will learn some of the terms related to security. Then you will learn how to use the COM+ features for security. The last part of the chapter discusses web-based security with IIS.Before you can understand how COM+ security works, you must understand some security terms.Windows NT and Windows 2000 are secure operating systems. In a secure operating system, resources such as files, printers, programs, and so on can be protected against unwanted access. Secure operating systems are also able to log each access attempt against one of the resources. To gain access to a resource, a principal -- that is, a person or a computer attempting to access the resource—must be authenticated. The purpose of authentication is to prove to the operating system that the principal attempting to gain access to the resource is in fact who it claims to be. Principals prove their identity by presenting a set of credentials. The software that checks the credentials and certifies that the principal is in fact who it claims to be is known as the authority. The authority is a service in Windows NT or Windows 2000 that runs under LSASS.EXE.Windows NT and Windows 2000 enable companies to set up a network using either a workgroup architecture or a domain architecture. When computers are set up in a workgroup, each machine authenticates users locally. When the authority responsible for authenticating users is the local machine, we refer to the software that authenticates the user as the local security authority. In a workgroup scenario, if Bob on machine A wants to use a file on machine B, machine B must have Bob listed as a user. The user ID in B must match the user ID in A. Furthermore, the passwords in both machines must be the same. The workgroup scenario is OK for companies with only a few machines, but what if the company grows to the point that it has a few hundred machines? Then it would be almost impossible for an administrator to ensure that every machine has a list with all the users in the company. What makes it even more difficult is the fact that a user may change her password on one machine. This would make it necessary for the user to go to each machine and ensure that the password is also changed on those as well. Because that would be an administration nightmare, a company can choose to promote one of its workstations to the role of domain controller. In a network with a domain controller, one machine does the job of authentication. Accounts are kept in a centralized security database on the domain machine. When a domain user logs into a workstation, the workstation trusts the domain controller machine to authenticate the user for the workstation.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Security Terminology
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBefore you can understand how COM+ security works, you must understand some security terms.Windows NT and Windows 2000 are secure operating systems. In a secure operating system, resources such as files, printers, programs, and so on can be protected against unwanted access. Secure operating systems are also able to log each access attempt against one of the resources. To gain access to a resource, a principal -- that is, a person or a computer attempting to access the resource—must be authenticated. The purpose of authentication is to prove to the operating system that the principal attempting to gain access to the resource is in fact who it claims to be. Principals prove their identity by presenting a set of credentials. The software that checks the credentials and certifies that the principal is in fact who it claims to be is known as the authority. The authority is a service in Windows NT or Windows 2000 that runs under LSASS.EXE.Windows NT and Windows 2000 enable companies to set up a network using either a workgroup architecture or a domain architecture. When computers are set up in a workgroup, each machine authenticates users locally. When the authority responsible for authenticating users is the local machine, we refer to the software that authenticates the user as the local security authority. In a workgroup scenario, if Bob on machine A wants to use a file on machine B, machine B must have Bob listed as a user. The user ID in B must match the user ID in A. Furthermore, the passwords in both machines must be the same. The workgroup scenario is OK for companies with only a few machines, but what if the company grows to the point that it has a few hundred machines? Then it would be almost impossible for an administrator to ensure that every machine has a list with all the users in the company. What makes it even more difficult is the fact that a user may change her password on one machine. This would make it necessary for the user to go to each machine and ensure that the password is also changed on those as well. Because that would be an administration nightmare, a company can choose to promote one of its workstations to the role of domain controller. In a network with a domain controller, one machine does the job of authentication. Accounts are kept in a centralized security database on the domain machine. When a domain user logs into a workstation, the workstation trusts the domain controller machine to authenticate the user for the workstation.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - RPC Security
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterTo truly understand COM+ security, we must take a look back at the foundation of COM, RPC. You may recall from previous chapters that the COM remoting protocol, normally referred to as the DCOM wire protocol, is built on top of MSRPC. In truth, all DCOM calls are true MSRPC calls. MSRPC is the Windows implementation of the Remote Procedure Call (RPC) specification written by the Open Software Foundation (OSF). MSRPC is a protocol, and, like all other protocols, it is a set of rules for how to format byte streams from one program to another. RPC is a protocol that is built on top of other network protocols such as TCP, UDP, SPX, and so forth. The RPC protocol enhances the existing protocols by providing the rules for how to make method calls and transmit method parameters. Even today, all COM+ calls from one machine to another are true MSRPC calls.Because all COM+ calls across the wire are really "object-oriented" MSRPC calls, COM+ security has as its foundation RPC security. If you learn a little about MSRPC security, then you will be very close to understanding COM+ security. With that in mind, let's discuss RPC security. I am not going to bore you will all the RPC commands that you must use to create an RPC server and an RPC client program. Instead, let's talk about RPC security at a higher level.In the good old days, if you wanted a client program to talk to a server program, you would write RPC code. You would first define an interface (yes, interfaces were really used in RPC long before COM existed) in IDL. You would then run the IDL source code through a compiler that would generate proxy/stub code for the interface. Suppose that your interface were called
IChecking
and your method were called MakeDeposit. MIDL would generate code for your client program that would take all the parameters for MakeDeposit and package them using a format known as Network Data Representation (NDR), then do the job of calling the appropriate RPC calls to send the buffer to the server side. The code that MIDL would generate for the server would listen for RPC requests, unpackage the buffer parameter, and make the actual call to MakeDeposit, wait for the call to complete, then take the output parameters and package them into a return buffer for the client. This was RPC.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - COM/COM+ Security
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterHow does RPC security relate to COM+ security? I made the statement earlier that every DCOM call is actually an RPC call. When you use remoting in COM+, as you learned in Chapter 5, the client talks to a server object through a proxy, and the object receives calls through the stub. Deep in the proxy/stub code is the code that makes RPC calls. As you learned in the previous section, for an RPC call to be secured, you must call the RpcBindingSetAuthInfoEx function. What COM+ provides are high-level API functions for setting the parameters of RpcBindingSetAuthInfoEx. The two most important functions (the ones we are going to discuss here) are CoInitializeSecurity and CoSetProxyBlanket.In RPC, when the client wanted to make secured calls, it had to call RpcBindingSetAuthInfoEx for each binding handle; this is the equivalent in COM+ of making a similar call once for each interface in each object. The server had even more work to do because it had to evaluate each call and decide whether the security level of the call was sufficient, and then accept or reject the call based on its evaluation.Because in COM+ the proxy/stub code wraps the RPC code, it is possible for COM+ to automate the process and minimize the work that the client and the server have to do. For example, on the client side, we can tell COM+ at program startup what level of authentication to use for all of its RPC calls. On the server side, COM+ enables us to tell it the minimum level of security that we accept at program startup. The proxy/stub code will then take care of rejecting calls that do not meet the requirement automatically. In addition to setting security information at startup, COM+ still gives us the choice of setting this information on a call-by-call basis.CoInitializeSecurity enables us to set default parameters that the proxy/stub code will use in deciding how to make calls from the client and whether to accept calls on the server. Both the server program and the client program can call this function. This function must be called before creating any COM+ components.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Internet-Based Security
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterToday most clients accessing our COM+ application do not use custom VB client applications. Instead, they use the browser as their client program. This last section discusses how IIS security integrates into COM+ security. I am not going to spend a lot of time defining how to create web applications and ASPs or how to configure your server. However, for the sake of discussion, I would like to give you a brief overview of what a web application is and how it integrates with COM+.In Windows 2000, the Microsoft web server is Internet Information Services 5.0 (IIS 5.0). IIS runs as a service in a process called InetInfo.EXE. InetInfo.EXE gives the developer the ability to create extensions and filters known as ISAPI extensions and ISAPI filters. Whenever a client sends an HTTP request to the server, it normally sends the request through TCP/IP port 80. IIS listens for HTTP requests through port 80 and has the job of sending an HTTP response. By writing filters and extensions, you can read the information in the HTTP request and customize the response to the client. The most famous ISAPI extension is ASP.DLL, which wraps the low-level functionality of ISAPI into scripting friendly interfaces.IIS enables you to define a number of web applications for a particular server. To define an application, you create what is called a virtual directory (consult the IIS documentation for details on how to create a virtual directory). Each virtual directory is a different application with its own list of ISAPI extensions and its own security settings. Whenever IIS gets a request for a document in your application, it does one of two things. If the request is for a pure HTML document, it handles it by itself. It reads the document and returns the document to the client as the response. If, on the other hand, the request is for another document type, IIS checks the list of ISAPI extensions for the application. When you assign an ISAPI extension to the application, you tell IIS to use a particular ISAPI DLL whenever it gets a request for a document with a particular file extension. In the case of ASPs, each application you create automatically hasAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe first half of this chapter reviews the terminology that relates to security. All applications run under a certain set of credentials, and this set of credentials is known as the process token. You can use this token to extract information—such as the account name and the groups the account belongs to—about the account used to start the process. By default, threads in a process do not have their own tokens. A thread may decide to use an alternate token; this is called impersonation. The thread will then do some work, and the system will reject or grant access to resources based on the new set of credentials.COM+ security is built on top of RPC security. In RPC security as well as in COM+ security, the client is the one that dictates the security settings, and the server grants or rejects calls programmatically. COM+ simplifies the process of rejecting and granting access to functions in several ways. For one thing, COM+ enables you to set the minimum level of authentication through declarative properties. Then you can further restrict access into your application by creating roles. By default, security is turned off for your application. If you turn it on, you can tell COM+ if you wish to check security only at the application level or at the application level and the component level. If a user is assigned to a role, even if the role is not assigned to a component, interface, or method, the user will be able to launch the application and create instances of the components. To grant the user access to methods, you must then assign the role to a component, an interface, or the method itself.COM+ collects information about the callers that were involved in making the call. You can obtain information about the callers through the GetSecurityCallContext function. This function returns a pointer to the
SecurityCallContext
interface. You can use this interface to retrieve information about the original caller, the direct caller, and every caller involved in the call.The last portion of the chapter was about web security. You learned that anonymous users run under the credentials of theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 11: Introduction to .NET
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAt the time I started writing this chapter, .NET had entered its Beta 1 cycle. Even though this product is only in Beta 1 (and if you have read the documentation shipped with the .NET SDK, you will see that there is at least a Beta 2 planned), I know that with the Microsoft marketing muscle, many of you may be feeling in some ways as if you are already behind for not having already converted all your applications to use .NET. The reality is that .NET is a brand new architecture; it is not the next version of COM+. What's more, all the Microsoft compilers that were written before have to be rewritten to emit code compatible with the new architecture. In many cases, the language constructs themselves have also been rewritten. Visual Basic, for example, has gone through many syntactical changes—so many that some may argue it is not the same language.In this chapter, you are first going to get an introduction to the .NET architecture, then you are going to get an overview of some of the new features in VB.NET, and after you have an understanding of how to use the features, you will learn about how to mix .NET components with COM+ components. Because I am currently using beta software, the information in this chapter is subject to change. There is no way that I can pretend that this chapter will give all the information necessary to be a .NET developer, but it is my hope that you will learn enough to satisfy your curiosity.Why are we talking about .NET and not the next version of COM or COM+? .NET in fact is a brand new architecture with few things related to the current architecture. So what is wrong with COM and why is Microsoft going in a different direction? Well, before we can point out the benefits of .NET over COM/COM+, let's talk about the architecture itself.First, how do you get .NET? .NET comes in two main parts. One of the parts is the .NET SDK. The .NET SDK team builds what was previously known as the Universal Runtime (URT) and is now called the Common Language Runtime (CLR). It is a runtime environment that includes a loader for .NET code, a verifier, certain utilities, and a number of .NET DLLs that compose what is called the .NET Common Type System. The SDK also includes four command-line compilers: one for VB.NET, one for a new language called C# (C-Sharp), a new version of the C++ compiler and linker that produces what is called managed C++ (or MC++), and one for the Intermediate Language (IL), which you will learn about shortly. A number of other language compilers are also being developed by third parties to emit .NET-compatible code, such as Cobol.NET, Component Pascal, Eiffel, and others.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The .NET Architecture
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWhy are we talking about .NET and not the next version of COM or COM+? .NET in fact is a brand new architecture with few things related to the current architecture. So what is wrong with COM and why is Microsoft going in a different direction? Well, before we can point out the benefits of .NET over COM/COM+, let's talk about the architecture itself.First, how do you get .NET? .NET comes in two main parts. One of the parts is the .NET SDK. The .NET SDK team builds what was previously known as the Universal Runtime (URT) and is now called the Common Language Runtime (CLR). It is a runtime environment that includes a loader for .NET code, a verifier, certain utilities, and a number of .NET DLLs that compose what is called the .NET Common Type System. The SDK also includes four command-line compilers: one for VB.NET, one for a new language called C# (C-Sharp), a new version of the C++ compiler and linker that produces what is called managed C++ (or MC++), and one for the Intermediate Language (IL), which you will learn about shortly. A number of other language compilers are also being developed by third parties to emit .NET-compatible code, such as Cobol.NET, Component Pascal, Eiffel, and others.The second part of .NET is called Visual Studio.NET. Visual Studio.NET is composed of the IDE that you use to write code, several programming tools, and online documentation. Visual Studio.NET uses the .NET SDK compilers to compile your program. In reality, if you like using NotePad.exe, you do not need Visual Studio.NET; you could write your VB programs in Notepad and then run the command-line compiler.One important thing to understand about .NET is that it is a lot more than its name implies. At first glance, it may seem like a technology geared toward writing Internet applications. Although this is true in some sense, it is a lot more than that. .NET is primarily an architecture for writing applications that are object-oriented in nature, and both hardware and operating system agnostic. You may have heard similar claims from another language—Java. Under the covers, .NET is very different from Java, but conceptually the two architectures have the same goal.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Developing Assemblies
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThere are two ways to create VB.NET applications. One way is to use the next version of Visual Studio, Visual Studio.NET. Visual Studio.NET is a development environment built on top of the .NET SDK. The .NET SDK is packaged separately from the Visual Studio.NET environment. The SDK includes a C# command-line compiler, a VB.NET command-line compiler, and the DLLs and EXEs necessary to run your .NET applications.I have decided that in order to make the information in this chapter last, I am not going to use the Visual Studio.NET designer. One reason is that the product has not been released yet. Another reason is that the product is not yet stable. A third reason is that, for the first time, Visual Basic has a true command-line compiler that can be used in conjunction with NMAKE and MakeFiles. You may be familiar with MakeFiles if you have ever worked with C++. MakeFiles are text files that tell NMAKE.EXE how to build your program. For all these reasons, I have decided to use the second most widely used development environment in the Windows platform, Notepad.EXE. So for the next set of examples, you will need three things: the .NET SDK downloadable from Microsoft, Notepad.EXE, and a command prompt. Let's start with a simple Hello World application to get a taste for how to use the command-line compiler.Run Notepad.EXE and enter the following text:
Public class HelloSupport Shared Public Function GetGreeting(ByVal sName As String) As String return "Hello " + sName End Function End Class
This code declares a class called HelloSupport. At first it seems strange to create a class for just one function, but in VB.NET every function is exposed through a class. Even when you declare a module with functions, the module becomes a class when it is compiled, and all of the functions in the class become shared, very much like in the preceding example.So what isShared
, anyway? Classes in VB.NET have two types of methods: instance methods and shared (or static) methods. VB 6 class methods were instance methods: you had to create an instance of the class to use them, and the method performed a task on the data for that instance only. Shared methods are new to VB.NET. They can be executed without creating an instance of the class. The only limitation is that if your class has both shared methods and instance methods, you cannot call the instance methods from within the shared methods. You can call shared methods only from within shared methods. If you need to call the instance method, then you have to create an instance of your class and make the method call just as any other function outside the class would. You also cannot use any of the member fields in the class from shared methods unless the fields are also marked as shared. In a module, the VB.NET compiler turns all functions to shared.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - VB.NET Features
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that you know the basics of running the VB compiler and the difference between private assemblies and shared assemblies, let's discuss some of the new features in VB.NET. In many ways, VB.NET is a different language. The language has been extended to have a number of object-oriented features that it did not have before, such as method inheritance, method overloading, and exception handling.In Chapter 2, you learned the difference between interface inheritance and code inheritance. VB 6 enabled you to do only one type of inheritance—interface inheritance. VB.NET adds support for the second type of inheritance, code inheritance. The way it works is that you first create a base class. In our ongoing example of a banking application, let's suppose that your design accounted for two main classes: a Checking class and a Savings class. It is likely that these two classes have functionality in common. In fact, a better design may be to create a base class named Account from which these two classes are derived. The following code shows an application that declares three classes: Account, Checking, and Savings. The Checking and Savings classes inherit all their functionality from the Account class:
Public class Account Dim m_Balance As Decimal Public Sub MakeDeposit(ByVal Amount As Decimal) m_Balance += Amount End Sub Public ReadOnly Property Balance( ) As Decimal Get return m_Balance End Get End Property End Class Public Class Checking Inherits Account End Class Public Class Savings Inherits Account End Class Public Class App Shared Sub Main( ) Dim Acct As Account = new Checking Call Acct.MakeDeposit(5000) System.Console.WriteLine(Acct.Balance) End Sub End Class
The Account class has a member variable, called m_Balance, that stores a Decimal (Decimal replaces the VB 6 Currency type). The class has a MakeDeposit method that accepts an amount in its parameter and adds the amount to the balance. The class also has a Balance property that reports the internal balance. The code then declares two subclasses, Checking and Savings, that inherit all their functionality from the Account class. The rest of the code declares the class that will host the Sub Main function. In Sub Main we are declaring a class of type Account and assigning an instance of the class Checking. Why can we assign an instance of Checking to a variable of type Account? Because inheritance establishes an "IS A" relationship between the base class and the derived class. For all purposes, a Checking class "IS AN" Account. The opposite is not true; Account classes are not Checking classes.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Mixing COM+ and .NET
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterMany of you are feeling the urge to experiment with .NET components and like the new features in Visual Basic. Most likely, you have already made an investment in COM and would like to know how to use your existing COM components in VB 6 with the new .NET components. Microsoft is very aware of this need and has built in capabilities for mixing the two.As you know from the previous sections in this chapter, code that runs in the CLR is managed code. It is in IL, and it is run by the common language runtime. The runtime has its own techniques for allocating objects and managing things like thread allocations and so forth. In the VB 6 world, code was unmanaged. The compiler translated your code to native code that the processor could run. Thus, if we are going to mix these two worlds, we must create intermediary components that enable us to travel to and from managed space into unmanaged space. Let's address the idea of using VB.NET components from your Visual Basic 6 code first.Microsoft provides a tool called tlbexp.exe with the .NET SDK that enables you to create a type library (.TLB) file from an assembly manifest but does not register it. A type library (especially an unregistered one) does not really provide the functionality of a COM server. If we were to try to use a managed DLL as a COM server, the managed DLL would have to have the functionality of an in-process COM server. For example, it would have to have the four entry points to any COM DLL: DllRegisterServer, DllUnregisterServer, DllGetClassObject, and DllCanUnloadNow. It would also have to add the necessary keys to the registry for the SCM to load the DLL. Remember that the SCM must find the CLSID followed by the
InprocServer32
key pointing to the DLL.Unfortunately for COM developers, CLR assembly DLLs do not have COM entry points, nor are they self-registering. However, Microsoft has made the CLR execution engine (MSCorEE.dll ) a full COM server. It can load your assembly at runtime and provide you with a proxy to your .NET classes. Microsoft provides another tool calledAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Using COM+ Services
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterI hesitate to write this section because many things are going to change down the road with respect to using .NET assemblies in COM+ applications. However, for the sake of completion, let's talk about how to add a .NET class to a COM+ application as of Beta 1.In the future, the MTS (now COM+) team will migrate all the COM+ services to work seamlessly with all the .NET architecture. For now, we must use a few COM interop tricks. In essence, the interaction occurs through the same mechanism explained earlier, by which you must make your .NET class look like a COM class by adding information to the registry and using MSCorEE.dll as the COM server wrapper for your assembly. However, we must also add information to the COM+ catalog. Microsoft provides another tool called RegSvcs.exe that does the job of RegAsm with the
/tlb
command-line switch, plus adds information about the class to the catalog. In addition, RegSvcs.exe is able to interpret certain attributes from the assembly, which enables you to set the declarative attributes in COM+.For Beta 1, if you want a .NET class to work with COM+ services, you must derive the class from System.ServicedComponent. Because RegSvcs is going to generate COM information for the registry, you should also manage the IIDs and CLSIDs with attributes. For example, the following VB.NET code shows an interface namedIAccount
implemented in a Checking class:<Assembly: System.Runtime.InteropServices.GuidAttribute("1D1D3D4C-52BE-46de-9100- 8F5AEB8207C0")> <Assembly: System.Runtime.CompilerServices.AssemblyKeyFileAttribute("complusservices.key")> <Assembly: Microsoft.ComServices.Description("Book - Dotnet")> <Assembly: Microsoft.ComServices.ApplicationName("Book - Dotnet")> <Assembly: Microsoft.ComServices.ApplicationID("7319F24B-6DEA-4479-8027-1E8E1816C626")> <Assembly: Microsoft.ComServices.ApplicationActivation(Microsoft.ComServices. ActivationOption.Server)> Imports System.Runtime.InteropServices Imports Microsoft.ComServices Interface <guidattribute("874A6DD2-E141-41fd-A379-E066E8E23921")> IAccount Sub MakeDeposit(ByVal Amount As Integer) ReadOnly Property Balance( ) As Integer End Interface Public Class <guidattribute("FB03ABE6-982D-436e-919C-CA1D8BE1B71A"), _ Transaction(TransactionOption.Required)> _ Checking Inherits ServicedComponent Implements IAccount Private m_Balance As Integer Private Sub MakeDepositImpl(ByVal Amount As Integer) _ Implements IAccount.MakeDeposit m_Balance += Amount End Sub Private ReadOnly Property BalanceImpl( ) As Integer Implements IAccount.Balance Get Return m_Balance End Get End Property End Class
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, you have learned the basics of the .NET architecture. You learned some of the limitations in COM and why Microsoft has created the new architecture. A number of languages are being written to support the new architecture. These languages compile to a processor-independent form of assembly language known as Intermediate Language (IL). Two of the main languages for .NET are VB.NET and C#. Both of these compilers generate IL. When you run a program written in IL, a Just-in-Time compiler converts the code into native machine code.VB.NET has a number of enhancements over VB 6. Among them are: code inheritance, method overloading, enhanced user-defined types, function pointers, parameterized constructors, and true exception handling..NET components follow a different versioning scheme than COM+. When you build an assembly that references another assembly, the client assembly's manifest contains the version number of the referenced assembly. The runtime matches the major and minor numbers in the version for the assembly. You can redirect the runtime to use a different version with a configuration file.To use an assembly from a VB 6 program, you use a tool called RegAsm.exe. Alternatively, you can use the tlbexp.exe tool to create a type library. However, RegAsm.exe does the job of adding keys to the registry to make the public classes in the assembly creatable from COM. It also builds a type library and registers it. In addition to providing you with a way to use .NET components from COM, you can use this functionality for versioning your existing COM components. To use COM components from .NET, you can use the tlbimp.exe tool to create an assembly from your type library.You can also add a .NET component to a COM+ application. In fact, it makes good sense to mix COM with .NET components, because .NET components do not have the same threading restrictions as COM+ components. To use an assembly in COM+, you must first sign it and add it to the cache. Then you must run the tool RegSvcs to register the classes in the assembly, create a type library, and add it to the catalog. There are attributes in the Microsoft.ComServices assembly that enable you to specify the declarative attributes of the COM+ application.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Return to COM+ Programming with Visual Basic
About O'Reilly | Contact | Jobs | Press Room | How to Advertise | Privacy Policy
© 2007, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.