DMA Interface and Process Model

DMA Interface Model

The interface mechanism of DMA is a strict, portable subset of Microsoft’s COM (Component Object Model). You can use the Microsoft publication "The Component Object Model Specification", Version 0.9, October 24, 1995 (or any later version) as a reference (http://www.microsoft.com/com).

The DMA Architecture uses only the basic encapsulation mechanism of COM for local, memory resident objects. (This is sometimes referred to as the "binary interface standard".) This mechanism gives the DMA API a language independent, binary component architecture. The binary interface standard is a tractable subset of COM, and it is relatively easy to understand and implement. The DMA Architecture has no dependency on DCOM, IDL, MIDL, ODL, DCE, or any other remote procedure call mechanism or wire protocol. The network aspect is left open, and is transparent to the DMA API. The DMA Architecture has no dependency on any aspect of OLE, including persistent storage.

COM Elements Used By DMA

GUID

The DMA Architecture and COM use GUID's (Globally Unique IDentifiers) to uniquely identify COM interfaces. These GUID’s are 16 byte quantities. The 128 bit pattern that a GUID represents is virtually guaranteed to be unique over all space and time, but no central administration authority is required to achieve this uniqueness. In other words, every GUID ever generated by any computer is different from every other GUID generated by that computer or any other computer. COM's GUID's are actually DCE UIID's (Universally Unique IDentifiers). Multiple algorithms for generating GUID's exist, and these algorithms are publicly available. There are utilities and entry points available on Microsoft and UNIX platforms to generate GUID's. A GUID is represented as a C typedef struct, and can be statically initialized in program header files.

NOTE: The DMA API data type DmaId is a GUID. The DMA API also uses DmaId's to uniquely identify things that have nothing to do with COM. For example, the DMA API uses GUID's to uniquely identify properties, property classes, query operators, collating sequences, etc.

Object and Interface Model

The DMA Architecture uses the basic object and interface model of COM. COM object instances have internal state in the local memory of the process and support multiple interfaces. Each interface contains only signatures of pointers to functions and supporting type declarations -- no variables. All DMA interfaces are COM interfaces. Each COM interface is assigned a unique, invariant GUID.

A COM interface definition maps well to a C++ pure virtual class. A COM interface can also be described in C or C++ by declaring a typedef for a pointer to a C struct that has fields which are pointers to functions.

A COM interface contract is the interface definition plus documentation describing the semantics of the methods. A COM interface contract is specified only once, is independent of object type, and cannot be changed once it is published. Many different types of objects can implement and provide the contract of a COM interface.

The COM specification provides for single inheritance of COM interfaces. That is, a COM interface can inherit the contracts of other COM interfaces in a well defined, ordered linear sequence. However, COM does not provide for inheriting the implementation of interfaces, only the definitions and contracts of the interfaces. A COM interface that inherits another COM interface inherits the entire contract of that interface, and must provide all of the functionality of the inherited contract to its clients. There is no selective inheritance of only some of the methods of the inherited interface, and it is not permissible to change the contract of the interface being inherited.

If a COM interface B inherits COM interface A, then A comes before B in the interface inheritance ordering, and all the methods of A plus all the methods of B are provided by interface B. The interface being inherited (in this example, interface A) is called a "base interface".

COM single-interface-inheritance must be distinguished from several other types of inheritance:

IUnknown Interface

The IUnknown interface was defined by Microsoft, and, as per the COM specification, is the ultimate base interface for all COM interfaces. Thus, the IUnknown interface is first in the COM interface inheritance ordering of every COM interface, and the methods of the IUnknown interface are available in every COM interface.

Hence, all DMA objects support the IUnknown interface, and the methods of the IUnknown interface are available in every DMA interface, as required by the COM specification.

The QueryInterface method of the IUnknown interface enables a client of a COM object (and, therefore of a DMA object) to obtain access to any interface of the object of which the client has knowledge. The methods of the IUnknown interface are also used in controlling the lifetime of the object according to the COM reference counting rules as per the COM specification.

Memory Management Rules

The DMA Architecture adopts the memory management rules for reference counting on COM objects (to manage their life cycle), and for the ownership responsibilities of input, output, and in/out parameters to methods.

DMA employs the standard IMalloc interface to allocate local task memory dynamically. The DMA System Manager provides a default allocator. However, the DMA client has the ability to override the default allocator and substitute one of its own choosing.

Error Handling

The DMA Architecture follows COM in disallowing setjmp/longjmp and all exception throw/catch mechanisms across a COM interface boundary. Such mechanisms conflict with transparent remoting of DMA interfaces and are compiler and language dependent.

Error Result Codes

DMA follows the COM convention that virtually all methods return a 32 bit integer value called the result code, which indicates the completion status of the method call. These values conform to the COM HRESULT scheme as described in http://www.microsoft.com/oledev/olecom/Ch03.htm#Error. DMA however does not employ the HRESULT typedef in any of its header files. Instead DMA uses the type DmaRC, which should be treated as a synonym for HRESULT.

Two types of result codes exist:

  1. Error codes, and
  2. all other result codes.

Error codes indicate that the method failed completely and cannot deliver any useful results. The COM convention is that a method which returns an error code must return NULL values for any output pointer parameters.

All non error result codes indicate some degree of successful operation, with anything other than unqualified success (DMARC_OK) being considered a warning of incomplete success. When a warning code is returned, output parameters should deliver useful values which allow the application to determine the extent to which the operation was incomplete.

An error result code is distinguished from a warning or success code by the fact that the most significant bit in the value will be set. The DMA header files provide convenience macros to test for an error result code.

The HRESULT scheme separates result codes into a number of different categories, identified by facility codes that are encoded into the high order part of the HRESULT value. Microsoft reserves the sole right to define facility codes and to define the result codes belonging to every facility except one: FACILITY_ITF. Anyone may define result codes belonging to FACILITY_ITF. However, no mechanism exists to prevent two or more definitions using the same value for different purposes. It is therefore necessary that result codes belonging to FACILITY_ITF only be interpreted relative to the particular interface which returned the code, and that FACILITY_ITF result codes not be propagated across boundaries between interface families. DMA defines result codes in FACILITY_ITF for the DMA family of interfaces.

The COM convention is that any result code, in any facility, may be returned by any COM-defined interface method. COM-defined methods usually include, as part of their specification, a list of "particularly useful" error codes, but, in accordance with the HRESULT scheme, the list is never exhaustive. DMA honors the COM conventions for all result codes, except for those belonging to FACILITY_ITF. For FACILITY_ITF result codes, DMA imposes the following additional rules:

It should be noted that the preceding two rules are imposed upon DMA implementations, and that the list of permitted result codes may be added to in subsequent revisions of the DMA specification. These rules give no guarantee to the DMA application as to what result codes can be expected (since the application may encounter an implementation which was constructed against a later version of the specification than it was). Therefore, DMA compliant applications must adhere to rules given in the COM specification with regard to treatment of unrecognized result codes.

The DMA header files do not reproduce any definitions for any of the standard COM result codes. (For example, there is no symbolic constant definition for E_NOINTERFACE.) However, for a few of the standard COM result codes, especially those which are required by the IUnknown interface, an alias is defined (in the form of a "DMARC_" symbolic constant). This is indicated in the description of the result codes given in the result codes reference section. When such result codes are listed as a possible return of a DMA method, the listing is done in the same spirit as in the COM specification.

Some methods list two sets of permitted result codes, with the second set described as "Deferred". A deferred result code is one which may be returned by that method and may also be returned by the ExecuteChange or ExecuteChanges calls which subsequently enacts the effect of the method on the persistent store. Such result codes are not also listed for ExecuteChange or ExecuteChanges.

A number of DMA error codes are sufficiently general that DMA permits them to be returned by practically any DMA method. The specification does not systematically list these for every method. They should be presumed as possible result codes for every method. The "global" error codes are as follows:

DMARC_DISCONNECTED

DMARC_LOST_CONNECTION

DMARC_NETWORK_ERROR

Transparent Remote Access

The DMA Architecture follows COM in disallowing anything that would stand in the way of making method calls transparently remoteable.

The DMA Architecture is silent on the network RPC and protocol technologies used, and so allows a variety of technologies.

COM Elements Not Used By DMA

COM elements not used by the DMA Architecture include the following:

Additional Requirements on DMA Objects

Property Classes

All DMA objects have exactly one associated DMA property class. The object's (DMA property) class is used to describe the type of DMA object. Each type of DMA object has a set of interfaces that it must support, and a set of interfaces (which may be empty) that it may optionally support.

Required interfaces

In addition to the IUnknown interface (which must be supported by all COM objects), DMA requires all DMA objects to support the IdmaProperties and IdmaObject interfaces. The IdmaProperties interface provides access to the properties of the DMA object.

Object Generation

The first DMA object is obtained by calling an entry point procedure in a dynamically linked library. From then on, all DMA objects are obtained by invoking a method on a DMA object that is already in hand.

DMA Process Model

Objects Are Local to the Process

The object instance state is local to the process. On some platforms, the procedure pointers to the methods are only valid for the current process. DMA objects allocated in one process cannot be accessed by a different process.

On platforms that support threads, all threads have access to the local memory of the process, so all threads of a process can share access to the DMA objects of the process.

Thread Safety

DMA requires that object instances be safe under unrestricted threading (wherein multiple threads of a process can run both user and OS code concurrently). This requirement means that all methods of all interfaces of DMA objects must perform locking adequate to prevent destructive interference when multiple threads call methods on the same object concurrently. It is sufficient that DMA objects be serially reusable.

Serial reusability can be accomplished by single threading all access to the object via its methods. However, in one or two instances, it is desirable, but not required, to allow a second thread of the current process to call a method while the first thread is in the middle of executing another method on the same object. For example, it is desirable that TerminateResults be callable by a second thread while the first thread is blocked in GetNextResultRow during retrieval of query results. This type of implementation would allow long running queries to be canceled by a second thread responsive to user input while the first thread is blocked waiting for more result rows.

Callbacks

Certain potentially long running methods take an optional callback parameter. The method is allowed, but not required, to call the callback procedure at intervals during the operation. Callback procedures, when supported, may be used to facilitate the client's reporting on the progress of the operation or to cancel the operation.