macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Component Object Model (COM) Development on Mac OS X

by Christopher Hunt
04/16/2004

Ssssh -- don't tell anyone, especially Microsoft enterprise salesmen, but COM can now be enjoyed by Mac OS X programmers. I am being quiet about it because obviously, Apple does not want anyone to know.

Mac OS X has been able to do COM for quite some time. The thing is, no one has really broadcast this -- until now. You can write COM components that have the potential to run on both Windows and Mac OS X with no code changes. This is another reason for Mac OS X to be considered as a serious platform for enterprise applications (for those of you who like creating lists).

COM is commonplace on the Microsoft Windows platform. The majority of Windows programmers out there have had to deal with COM at some stage, given that many Windows programs communicate with each other that way.

In simplistic terms, COM provides a mechanism to share an object-oriented library as a dynamic link library. Neither the client software to the COM object, nor the server software that implements the COM object, need be written in an object-oriented language -- although it helps if they are.

Interestingly, Mac OS X's COM architecture appears to exist mainly to support Apple's Core Foundation Plugins architecture. With a little help that I am about to provide, you can now develop with Apple's COM architecture in a similar way to how you would on Windows.

A special message for Windows programmers new to Mac OS X: "Welcome home."

What Is COM Again?

This article does not intend to describe the ins and outs of COM; many others before me have beaten that path (check out this overview on Microsoft's COM home page and these documents on Google). For the purposes of getting those COM-neurons firing again, though, COM allows software components with a high potential for reuse to be shared between software programs. The object-oriented way COM software components are described means that the benefits of encapsulation, inheritance, and polymorphism can be realized with language independence.

COM also supports location transparency, where the program that calls upon the COM object need not have knowledge of its physical location; e.g. whether the COM object is managed within the same executable, in a local dynamic link library, or by a library on another machine.

In summary, COM is pretty useful and not just for Windows programmers.

How COM Applies to Mac OS X

COM has been implemented on Mac OS X as part of the Core Foundation framework. COM on OS X largely exists to support the Core Foundation Plugins architecture. As such, only in-process COM servers are supported. In English terms, this means that COM can only be implemented using dynamic link libraries on Mac OS X (on Windows, COM can also be housed within the same executable that it is used from, and housed in a dynamic link library on another machine).

In reality, the above does not present a problem. Most COM housings are implemented using dynamic link libraries on Windows.

An important difference between using COM on Mac OS X and COM on Windows is that there is no registry of COM components on the Mac. To explore this difference, you might recall that Windows provides a registry where the class and interface identifiers can be registered for use. This registration process decouples the need for a program to know which dynamic link library a COM component resides in, and also where the library is on disk. Consequently, you can just tell Windows to create an instance of a COM object using CoCreateInstance.

While you could fabricate your own registry and write a CoCreateInstance implementation, you normally load the dynamic link library into memory manually on Mac OS X. The good news is that you can also load a dynamic link library manually on Windows; i.e., you do not have to use the Windows COM registration mechanism or, if you do, you can bypass it. This means that you can load your COM component exactly the same way on Mac OS X and Windows, if you want to. I actually illustrate this later in my COM client code and provide some of the Windows Automation functions so that loading libraries can be done simply and with portability.

In summary, your Mac OS X COM components are housed in a dynamic link library that you manually load. I shall now get to the good stuff and show you how.

Your Mac OS X COM Projects

There are two Xcode projects available to you. The first one is named Sample Carbon COM Client and provides a standard console application that calls upon a COM component. The other project is named Sample Carbon COM Server and is a CFPlugin Bundle project that implements our COM component. The complete list of folders in the download are:

  • Carbon COM
  • Sample Carbon COM Client
  • Sample Carbon COM Server
  • Sample Portable COM Client
  • Sample Portable COM Interface
  • Sample Portable COM Server

Carbon COM provides Carbonized versions of the Windows interfaces for COM and Automation that we need. Sample Portable COM Client provides the source that implements our COM client in a platform-independent manner. Sample Portable COM Interface provides the COM interface definition files we need to describe our COM object. These files are shared between the client and the server and are platform independent. Sample Portable COM Server provides the source that implements our COM server in a platform-independent manner.

A COM Client Example

Here is something to get your teeth into:


// Initialise COM

CoInitialize(0);

// Build our server's complete filespec into the UTF16 
// format (Unicode) required by Automation

unsigned short* theServerSpecP = UTF16Create(
                        ".."
                        "/.."
                        "/Sample Carbon COM Server"
                        "/build"
                        "/server.bundle"
                        );

// Load our servers type lib so that we can create 
// instances of our COM interfaces

ITypeLib* theTypeLibraryP;
HRESULT theResult = LoadTypeLib(
                            theServerSpecP, 
                            &theTypeLibraryP
                            );
delete[] theServerSpecP;
theServerSpecP = 0;     // No longer required

if (SUCCEEDED(theResult))
{
    // Here's the meat of it - now we've done the hard 
    // bit by loading our type lib, we can create 
    // instances using it - this is a standard 
    // Automation thing. First we obtain an ITypeInfo 
    // instance for our PhoneDialer class. ITypeInfo 
    // 'describes' a class i.e. provides meta 
    // information.
    
    ITypeInfo* theInterfaceTypeP;
    theResult = theTypeLibraryP->GetTypeInfoOfGuid(
                                    CLSID_PhoneDialer,                
                                    &theInterfaceTypeP 
                                    );

    if (SUCCEEDED(theResult))
    {
        // Now we have our type info for IPhoneDialer, 
        // we can create instances of the interface 
        // we're interested in.
        
        IPhoneDialer* thePhoneDialerP;
        theResult = theInterfaceTypeP->CreateInstance(
                            0, 
                            IID_IPhoneDialer, 
                            reinterpret_cast>void**<(
                                &thePhoneDialerP
                                )
                            );
        if (SUCCEEDED(theResult))
        {
            // Now call on our interface to do something
            // interesting. This is what all of the 
            // effort is about!
            
            thePhoneDialerP->Dial("1234");
            
            // We're done with our interface so release
            
            thePhoneDialerP->Release();
        }
        
        // We're done with our type info now so release
        
        theInterfaceTypeP->Release();
    }

    // We're done with our type lib now so we release

    theTypeLibraryP->Release();
}

// Finish up COM

CoUninitialize();

Pages: 1, 2

Next Pagearrow