Page #68 (Chapter 5. COM Programming Model)

< BACK  NEXT >
[oR]

Attribute-Based Programming

Before we get deeper into the COM+ programming model, let s answer one important question, Why should I use COM+ services when I can provide the same functionality in my code?

Sure you can. You are a competent Jedi programmer and the Force is with you. However, an even more important question one must ask is, Is it worth doing it?

Consider a simple scenario. You have developed a component that is not thread-safe (thread-safety issues are covered in the next chapter). To protect the internal state of the component, you wish to serialize access to the com-ponent, that is, set it up so that only one client can access it at any given time. To achieve this, you can use Win32 APIs that provide resource locking. Using these APIs, you would:

  1. Lock the component when a client request comes in, so that no other client can access it.

  2. Carry out the task requested by the client.

  3. Release ownership of the component by unlocking it.

The locking and unlocking APIs need to be called within each interface method of the component. Therein lies some problems.

Problem #1: The more code you have to write and maintain, the more development costs you incur.

Problem #2: The more methods you have in your component, the more chances you have of making a human mistake. You may forget to call the resource-locking APIs in a method or two. Worse, you may call the API to lock the resource but forget to call the API to unlock it when returning from a method. This would deny access to your component throughout its process lifetime.

In general, having the platform provide a service is preferable to writing it yourself for the following reasons:

  1. It reduces development cost. You can focus on your business needs instead of focusing on infrastructural issues.

  2. It reduces the amount of code you have to write, thus reducing the chances of making a coding mistake. For example, if the platform provides the serialization mechanism, it would require zero lines of code in your application, virtually eliminating the chance of writing buggy lines of serialization-related code.

  3. It usually reduces the number of page faults within your application, as many applications are sharing the same infrastructural code.

  4. By decoupling the infrastructural functionality from the code, the platform vendor has more freedom to improve the underlying implementation without breaking your code. For example, the next release of the platform may have improved the speed/performance of the serialization logic. Your component can benefit from this improvement without requiring any code changes.

What if the platform implementation itself is buggy?

As the platform is providing an infrastructure that is potentially shared by many applications, it is very likely that the platform will have gone through more testing than the average piece of application code. Bugs will be reduced over time, resulting in a very stable platform code.

How do we decouple the functionality from the code?

To make it convenient for developers, COM+ requires that a COM class be declared using out-of-band attributes instead of in-band explicit code. Recall from Chapter 2 that a similar technique was used for defining interfaces using IDL. This formalization of declarative programming using attributed classes is fundamental to the COM+ programming model.

Obviously, the attributes for the class have to be stored somewhere so that COM+ infrastructure can access them and provide the needed services to the instances of the class. Let s investigate this further.

The COM+ Catalog

COM+ stores all the configuration information of a component in a persistent storage referred to as the COM+ Catalog. To manage this catalog, COM+ provides a component appropriately called the Catalog Manager.

In designing the catalog, due consideration was given to ensure easy migration of component DLLs that were based on classic COM. This required that the Catalog Manager control the Windows registry key HKEY_CLASSES_ROOT. Recall from Chapter 3 that classic COM mandates that a component DLL export two functions, DllRegisterServer and DllUnregisterServer. The first function is expected to add certain entries under the Windows registry key HKEY_CLASSES_ROOT and the second function is expected to clean them up.

What are the entries that are needed under the Windows registry key? We will answer this in the next section. Let s first answer another question where should we store the newer attributes needed for a configured component?

The Windows registry database is already cluttered with all kinds of data COM as well as non-COM related. Therefore, it makes more sense to use a separate database that stores only COM+ related attributes. This auxiliary configuration database is currently referred to as RegDB.

The interaction of the Catalog Manager with both the databases, RegDB and Windows registry, is depicted in Figure 5.1.

Figure 5.1. The COM+ Catalog Manager.
graphics/05fig01.gif

At activation time, CoCreateInstance inspects the catalog to determine which (if any) additional services the component needs and ensures that the newly created object receives the services it requested.

Only those components that are explicitly installed into the catalog can avail COM+ services. These components are called configured components. If a component bypasses the Catalog Manager to register itself, it is called a non-configured or a legacy component.

Configuring a Component

There are two ways to configure a component:

  1. Explicitly program against the Catalog Manager interfaces.

  2. Use a visual tool called the Component Services Snap-in that comes with Windows 2000.

We will explore the first option in Chapter 12. For now, let s examine the second option.

Figure 5.2 shows a snapshot of the Component Services Snap-in.

Figure 5.2. Component Services Snap-in.
graphics/05fig02.gif

The main administrative unit of COM+ is called an application. A COM+ application is a collection of components that work together and share certain configuration settings. These attributes are applied across all the components within an application.

Configuration attributes are not just limited to the application level. Components within an application, their interfaces, and their interface meth-ods all have specific attributes associated with them, and can be configured individually.

To enforce some form of access control, an application can also define a list of user roles. A user role is a symbolic category of users, as defined by the developer of the application, for the purpose of determining access permissions to the application s resources. We will cover user roles in Chapter 7 when we discuss security.

Typically, a software vendor creates one or more applications during installation. When an application is installed, the system automatically applies certain default attribute settings to the application (and the components underneath). The installation program can change some of these settings programmatically. However, using the Component Services Snap-in, the administrator can modify some of these settings, at any time, thus enabling the administrator to fine-tune the application s execution environment.

When an application is installed, it can be configured to run in the same address space as the client. Such an application is called a library application.

While a library application makes sense from a performance point of view, it also implies that an ill-written or a malicious component may corrupt the address space of its client. Likewise, a crash in the client code may adversely affect the server. To protect the client and the server from each other, the application can be specified to run in its own process address space. An application marked to run in a separate address space is called a server application.

graphics/01icon01.gif

Classic COM supports two types of servers a DLL-based server and an EXE-based server. Under COM+, however, only a DLL-based server can avail COM+ Services. EXE-based servers are still supported, but they have to run as non-configured components. An EXE-based ser ver can avail COM+ Services indirectly by accessing a configured component.


When the client activates a component using CoCreateInstance for example, the COM+ library inspects the catalog to determine the services requested by the component at the application level, as well as at the underneath levels, and ensures that the new object receives the services it requested.

If the requested component belongs to a server application, COM+ creates a surrogate process and loads the component in the surrogate process. As we will see later, COM+ launches an executable called DllHost.exe to run the surrogate process.

Note that under COM+ 1.0 a component cannot belong to more than one application. Otherwise, COM+ cannot resolve the resulting attribute ambiguities.

graphics/01icon01.gif

A future release of COM+ will support the notion of specifying multiple CLSIDs for a COM class. In effect, the same binary can be treated as multiple components, each of which can be configured individually.

The release will also support the notion of public and private components. Under COM+ 1.0, a component is public in the sense that any component from any application can access the component. In the future release, if a component is marked as private, only those component that belong to the same application can access the component.


Table 5.1 shows the attributes that are applicable to an application. The table also indicates if an attribute is applicable to a server-type application, a library-type application, or both.

Table 5.1. Application Attributes

Attribute

Available Choices

Library, Server, or Both

Description

Text up to 500 characters long

Both

Authorization (Access Check)

None, Process Level, Process + Component Level

Both

Authentication

Enable, Disable

Library

Authentication Level

None, Connect, Call, Packet, Packet Integrity, Packet Privacy

Server

Impersonation Level

Anonymous, Identity, Impersonate, Delegate

Server

Security Identity

Interactive user, Specific user

Server

Queuing

Non-queued, Queued, Queued + Listener

Server

Process Shutdown

Never, n minutes after idle

Server

Debugger

Command to launch the debugger

Server

Change Permission

Attributes can/cannot be changed

Both

Delete Permission

Application can/cannot be deleted

Both

Compensating Resource Manager (CRM)

Enable, Disable

Server

Enable 3GB Support

Enable, Disable

Server

Attributes that are related to security, queuing, and CRM require an indepth study and will be covered in later chapters. Here is an explanation of the other attributes:

  • Process Shutdown: If a server application is used frequently, it is desirable to let the application run even when it is idle, that is, no client is currently using the application. The motivation is simple if the application runs all the time, any new client will be served immediately. The drawback, however, is that an idle application still wastes some CPU resources and may hold some other system resources. An engineering trade-off is to set the application to shut down if it stays idle for a specified period.

  • Support for 3GB Memory: By default, a per-process address limit is 2G under Windows OS on 32-bit processors (such as Intel Pentium class processors). For applications that are I/O intensive, such as database management systems, the use of a larger process space can provide considerable performance benefits as time-intensive I/O access to media is reduced. If 3GB support is enabled, the OS reduces the potential RAM allocated to Windows NT kernel from 2GB to 1GB, and provides the extra RAM to the application. This feature, of course, is meaningful only for computers that have more than 2GB of physical RAM.

  • Debugger Support: Debugging a library application is straightforward as the DLL runs in-process with the client application a developer can start debugging the client application and step into the component DLL code. A server application, on the other hand, runs in a separate process space (the surrogate process) than the client application. Though there is a way to attach to a running process and debug it, chances are you will miss the initialization logic by the time you attach to the process. COM+ facilitates debugging a server application. If the debugger support option is enabled and a debugger path is specified, COM+ spawns the debugger and attaches the server process to the debugger.

    graphics/01icon01.gif

    Once COM+ spawns the debugger, the debugger doesn t automatically proceed with the program execution. This gives you a chance to set the break points in your code.


  • Change Permission: The developer of an application knows what settings are best for the application and will set them accordingly during installation. To ensure that no one can change the settings accidentally, the designer can turn the change-permission flag off. If this permission is turned off, the administrators of the application have to explicitly turn the flag on before they can tweak any other attributes.

  • Delete Permission: Some applications, once installed, are deemed very important for the overall functioning of the system. To ensure that no one can accidentally delete the application, its developers, or an administrator, can turn this flag off. In this case, one has to explicitly turn the permission on to be able to delete the application.

Attributes can also be specified at the component, interface, and interface method level. These attributes are primarily related to transactions, security, queuing, etc., and will be discussed in later chapters.

Component Initialization

Quite often an object that is being activated needs to be initialized with some administratively specified values. For example, if a component requires connecting to a database, the administrator of the component may need to specify the exact DSN for the database (in case of ODBC connection), or the machine/user-name where the database server is running (in case of OLE DB connection). To facilitate this customization for a component, the Component Services Snap-in provides an option for the administrator to specify an initialization string for the component. During activation time, COM+ passes this string to the object.

If the component requires multiple values to be specified, all the values have to be combined into a single initialization string, perhaps separated by commas. The format of the initialization string is dictated (and documented) by the component vendor.

How is the initialization string passed to the object?

A component that wishes to receive an initialization string is required to implement a standard interface, IObjectConstruct. The following is its definition:

 IObjectConstruct : IUnknown  {   HRESULT Construct([in] IDispatch *pCtorObj);  }; 

When the object is activated, COM+ calls IObjectConstruct::Construct method that the object implements and passes the string in the form of a pointer to an interface IObjectConstructString. The following is the definition of IObjectConstructString interface:

 IObjectConstructString : IDispatch  {   [propget] HRESULT ConstructString([retval][out] BSTR *pVal);  } 

The object can obtain the initialization string by calling IObjectConstructString::ConstructString method, as illustrated in the following code snippet:

 class CMyServer : ...  {   ...  private:    CComBSTR m_bsInitString;  };  STDMETHODIMP CMyServer::Construct(IDispatch* pDisp)  {   CComPtr<IObjectConstructString> spConstructString;    HRESULT hr = pDisp->QueryInterface(&spConstructString);    _ASSERT (SUCCEEDED(hr));    hr = spConstructString->get_ConstructString(&m_bsInitString);    _ASSERT (SUCCEEDED(hr));    return hr;  } 

You may be wondering why IObjectConstruct::Construct method doesn t just specify BSTR as a parameter. This would certainly simplify server-side programming. I guess in the future releases of COM+, Microsoft intends to support additional interfaces on the object that is passed as a parameter to IObjectConstruct::Construct method. Passing a generic IDispatch pointer as a parameter gives them this flexibility without breaking the existing code base.

Developer-Specified Attributes

Many attributes, such as those that are security related, are best chosen at deployment time and are thus configurable through the Catalog Manager, either through an installation program or manually by an administrator. However, there are certain attributes, such as those related to transaction and concurrency, that only a developer can correctly determine. Such attributes are best specified as static resources or data inside the component DLL. The Component Services Snap-in, for example, does not provide any user interface to change such attributes.

Attributes under Windows Registry

As with classic COM components, COM+ requires that a component DLL export two functions DllRegisterServer and DllUnregisterServer. When a component DLL is added to an application under the Catalog Manager, the Catalog Manager automatically invokes DllRegisterServer, giving the component a chance to add the needed entries to the Windows registry. When a component is removed, the Catalog Manager invokes DllUnregisterServer, letting the component clean up its registry entries.

Though the developer can add any kind of information to the Windows registry, there are a few entries, as follows, that are important for COM+:

  • HKEY_CLASSES_ROOT\CLSID\{<CLSID>}\InprocServer32: The default value of this registry subkey must be the complete file path to the DLL serving the component as identified by its CLSID.

  • HKEY_CLASSES_ROOT\CLSID\{<CLSID>}\InprocServer32\ThreadingModel: This registry value indicates the type of apartment (apartments are covered in Chapter 6) the component can live in. The possible choices are apartment, free, both, or neutral. [1]

    [1] Technically, it is okay to leave this entry blank. In this case, COM uses a threading model called Main Thread Apartment. However, this is a legacy case and should not be used.

Though a CLSID can identify a class uniquely, it is hard for humans to remember. To identify an object, a human-readable version of CLSID is preferred. This identifier is referred to as the programmatic identifier or PROGID. A PROGID is typically represented as <vendor>.<component>.<version> as in Word.Application.8. A CLSID can also have a version-independent PROGID.

  • HKEY_CLASSES_ROOT\CLSID\{<CLSID>}\ProgID: The default value of this registry subkey specifies the PROGID for the component.

A PROGID makes it easy to identify a component. However, instance creation still requires a CLSID. Programming languages such as VB hide this by letting you instantiate an object using the PROGID. Behind the scenes, VB obtains the CLSID for the given PROGID using an API CLSIDFromProgID.

  • HKEY_CLASSES_ROOT\<ProgID>\CLSID: The default value of this registry subkey specifies the CLSID of the component. This entry helps CLSIDFromProgID map a PROGID back to its CLSID.

The above-mentioned entries should be programmatically added to the registry when DllRegisterServer is invoked. It is up to the developer to define a technique for accessing this data within the program code. The technique that ATL uses is to define the registry entries in a specific format in a file and bind the content of this file as a static resource into the component s DLL (see Chapter 3).

Type Library-Based Attributes. The SDK lets some attributes be defined in the library section of the IDL. The following IDL example specifies a transaction setting called TRANSACTION_REQUIRED on the component class AccountMgr.

   [     uuid(C9CF273D-EDED-4BD1-9DE6-559559BF001D),      version(1.0),      helpstring("AccountMgmt 1.0 Type Library")    ]    library ACCOUNTMGMTLib    {     importlib("stdole32.tlb");      importlib("stdole2.tlb");    [     uuid(0AC21FA4-DB2A-474F-A501-F9C9A062A63E),      helpstring("AccountMgr Class"),      TRANSACTION_REQUIRED    ]    coclass AccountMgr    {     [default] interface IAccountMgr;    };  }; 

Recall from Chapter 2 that attributes defined under the library section get saved into the type library when the IDL file is compiled. This type library can be stored either as a stand-alone file or within the component DLL as a static resource. In the former case, when the component DLL is added to an application through the Catalog Manager, the type library file should also be added to the application.

At this point, it should be reasonably clear how a component is configured at development and deployment time. Now let s look at how COM+ ensures that the services requested by a component are available to the component s objects throughout their lifetime.


< BACK  NEXT >


COM+ Programming. A Practical Guide Using Visual C++ and ATL
COM+ Programming. A Practical Guide Using Visual C++ and ATL
ISBN: 130886742
EAN: N/A
Year: 2000
Pages: 129

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