Tuesday, October 18, 2005

DLL Fundas

Excerpts from various articles related to DLLs and Registry.

DLLs Vs EXEs

Even though DLLs and applications are both executable program modules, they differ in several ways. To the end-user, the most obvious difference is that DLLs are not programs that can be directly executed. From the system's point of view, there are two fundamental differences between applications and DLLs:

• An application can have multiple instances of itself running in the system simultaneously, whereas a DLL can have only one instance.

• An application can own things such as a stack, global memory, file handles, and a message queue, but a DLL cannot.

DLL BASICS

• Each DLL has a set of classes.

• Each class has its own set-up functions and sub-routines.

• Public functions can be accessed outside of the DLL.

• Private function cannot be accessed outside of the DLL.

Use the following command to register a DLL

regsvr32 path\DLLName.dll

A message will tell you if it was successfully registered. If the registration did not work, make certain that you typed in the path and file name correctly.

To unregister

regsvr32 /u path\DLLName.dll

When a program installs a library (DLL or OCX) file the program's install routine will typically "register" the file with the system. This process tells the system the libraries in the file are available for more than one program to use. (Some DLL or OCX files are self-registering.)

COM class or Component Object Class (coclass)

(from the Platform SDK: COM / COM Class Objects and CLSIDs)

"A COM server is implemented as a COM class. A COM class is an implementation of a group of interfaces in code executed whenever you interact with a given object.

There is an important distinction between a C++ class and a COM class. In C++, a class is a type. A COM class is simply a definition of the object, and carries no type, although a C++ programmer might implement it using a C++ class. COM is designed to allow a class to be used by different applications, including applications written without knowledge of that particular class's existence. Therefore, class code for a given type of object exists either in a dynamic linked library (DLL) or in another application (EXE)."

COM object

A COM object is an instance of a COM Class at the runtime.

COM class object or Class Factory

(from the Platform SDK: COM / COM Class Objects and CLSIDs)

"The basic way to create an instance of a class (COM Class) is through a COM class object. This is simply an intermediate object that supports functions common to creating new instances (COM Object) of a given class (COM Class)."

COM component

COM component refers to a binary module, such as a DLL or an Executable. After registering, a component will expose one or more COM Class Object (or Object Factory).

Type Library

Type libraries contain the specification (metadata) for one or more COM elements, including classes, interfaces, enumerations, and more. These files are stored in a standard binary format. A type library can be a stand-alone file with the .tlb filename extension, or it can be stored as a resource in an executable file, which can have a .ocx, .dll, or .exe file name extension.

COM IDs

In COM world, you have to identify different pieces such as coclasses, interfaces, type libraries, applications, etc. These pieces must be unique in the world.

COM uses the Globally Unique IDentifier (GUID) to define these different IDs.

In an Interface Definition Language (IDL) file, you have to use the attribute uuid that stands for Universally Unique IDentifier. A UUID and a GUID are equivalent.

So, what is a GUID? A GUID is a 128-bit number, usually represented in hexadecimal, which is guaranteed "to be unique across space and time". For example, the following number is a GUID:

{60B4140E-B0A7-4540-B744-7E1A944E8C78}

COM borrows this identify system to the Distributed Computing Environment (DCE) naming scheme. The DCE RPC system uses UUIDs.

The main COM IDs are:

* LIBID: the Type Library ID, based on GUID.

* APPID: the Application ID, based on GUID.

* CLSID: the COM Class ID, based on GUID.

* IID: the Interface ID, based on GUID.

* PROGID: the Program ID, based on a text string.

Class registration and file extension informations are stored under the HKEY_LOCAL_MACHINE\Software\Classes key.

Hope this information helps you stay away from DLL Hell!

Some Resources

COM Objects and Registry in a NutShell

Monday, October 17, 2005

Designing Reusable Classes

Excerpts from the article Designing Reusable Classes.

Attributes of object-oriented languages promote reusable software. Data abstraction encourages modular systems that are easy to understand. Inheritance allows subclasses to share methods defined in superclasses, and permits programming-by-difference. Polymorphism makes it easier for a given component to work correctly in a wide range of new contexts. The combination of these features makes the design of object-oriented systems quite different from that of conventional systems.

As with any design task, designing reusable classes requires judgement, experience, and taste. However, this paper has organized many of the design techniques that are widely used within the object-oriented programming community so that new designers can acquire those skills more quickly.

An abstract class never has instances, only its subclasses have instances. The roots of class hierarchies are usually abstract classes, while the leaf classes are never abstract. Abstract classes usually do not define any instance variables. However, they define methods in terms of a few undefined methods that must be implemented by the subclasses.

A class that is not abstract is concrete. In general, it is better to inherit from an abstract class than from a concrete class. A concrete class must provide a definition for its data representation, and some subclasses will need a different representation. Since an abstract class does not have to provide a data representation, future subclasses can use any representation without fear of conflicting with the one that they inherited.

The top of a large class hierarchy should almost always be an abstract class, so the experienced programmer will then try to reorganize the class hierarchy and find the abstract class hidden in the concrete class. The result will be a new abstract class that can be reused many times in the future.

Object-oriented design starts with objects. Booch suggests that the designer start with a natural language description of the desired system and use the nouns as a starting point for the classes of objects to be designed [Booch 1986]. Each verb is an operation, either one implemented by a class (when the class is the direct object) or one used by the class (when the class is the subject). The resulting list of classes and operations can be used as the start of the design process.

It can be difficult to decide whether an operation should be implemented as a method in a class or as a separate class. Halbert and O'Brien discuss this problem at length [Halbert & O'Brien 1987]. In general, there is no absolute way to decide, but positive answers to the following questions all indicate that a new class should be created.

  1. Is the operation a meaningful abstraction?
  2. Is the operation likely to be shared by several classes?
  3. Is the operation complex?
  4. Does the operation make little use of the representation of its operands?
  5. Will relatively few users of the class want to use the operation?

It can also be difficult to decide which class should implement an operation. Operations with several arguments can frequently be implemented as methods in the classes of any of its arguments. The rules listed above can also be used to make this decision. For example, if an operation does not send messages to an object or access its instance variables then it should not be in the object's class.

Rules for Finding Abstract Classes

Rule 5: Class hierarchies should be deep and narrow.

A well developed class hierarchy should be several layers deep. A shallow class hierarchy is evidence that change is needed, but does not give any idea how to make that change.

An obvious way to make a new superclass is to find some sibling classes that implement the same message and try to migrate the method to a common superclass. Of course, the classes are likely to provide different methods for the message, but it is often possible to break a method into pieces and place some of the pieces in the superclass and some in the subclasses.

Rule 6: The top of the class hierarchy should be abstract.

Rule 7: Minimize accesses to variables.

Since one of the main differences between abstract and concrete classes is the presence of data representation, classes can be made more abstract by eliminating their dependence on their data representation. One way this can be done is to access all variables by sending messages. The data representation can be changed by redefining the accessing messages.

Rule 8: Subclasses should be specializations.

There are several different ways that inheritance can be used [Halbert & O'Brien 1987]. Specialization is the ideal that is usually described, where the elements of the subclass can all be thought of as elements of the superclass. Usually the subclass will not redefine any of the inherited methods, but will add new methods. An important special case of specialization is making concrete classes. Since an abstract class is not executable, making a subclass of an abstract class is different from making a subclass of a concrete class. The abstract class requires its subclasses to define certain operations, so making a concrete class is similar to filling in the blanks in a program template. An abstract class may define some operations in an overly general fashion, and the subclass may have to redefine them.

In the middle of a project, it may be useful for a designer to make subclasses that are not specializations of their superclasses. If the superclasses are poorly designed, it might take a great deal of work to determine the proper design of the class hierarchy. It is better to forge ahead and then to later reorganize the classes. Thus, a subclass might be more general than its superclass or might have little relationship to its superclass other than borrowing code from it.

Monday, October 10, 2005

Encapsulating Information Hiding

I came across an excellent article that helps us see the difference between Encapsulation and Information hiding; 2 OO terms that are often synonymously used. Here is the URL for the article.

Encapsulation is not information hiding

Below are excerpts from the article; things that I would like to keep in mind when I kick off a new OO implementation project.

Encapsulation is a language construct that facilitates the bundling of data with the methods operating on that data.

Information hiding is a design principle that strives to shield client classes from the internal workings of a class.

• Encapsulation facilitates, but does not guarantee, information hiding.

Encapsulation rule 1: Place data and the operations that perform on that data in the same class.

Encapsulation rule 2: Use responsibility-driven design to determine the grouping of data and operations into classes.

Information hiding rule 1: Don't expose data items.

Information hiding rule 2: Don't expose the difference between stored data and derived data.

Information hiding rule 3: Don't expose a class's internal structure.

Information hiding rule 4: Don't expose implementation details of a class.