Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Importing Type Libraries

0.00/5 (No votes)
23 Feb 2003 1  
Using alternatives to importing type libraries and COM objects can improve the portability of your source code.

Introduction

In a discussion about an articled posted on CodeProject entitled, "Importing contacts from Outlook", I pointed out that using file references for importing type libraries was not usually a good idea. You shouldn't assume that everyone has their projects or type libraries in the same path or even on the same drive. Using simple alternatives that any COM developer should already be familiar with, you can improve the portability of your source code.

Requirements

To import type libraries using alternatives to file references, you will need the C/C++ compiler, version 13.00. This compiler ships with Microsoft Visual C++ .NET, Microsoft Visual Studio .NET, and the Microsoft Platform SDK.

About Type Libraries

Before jumping into alternatives for importing type libraries, you might wonder what a type library (typelib) is. As defined in the MSDN, a type library is "[a] file or component within another file that contains type information about exposed objects. Type libraries are created using the MIDL compiler, and can be accessed through the ITypeLib interface." This means that information about interfaces, structures, and enumerations and all their members can be obtained without actually referring to the object that implements these things. This is important when developing COM clients because you usually don't know in which directory - or computer - the implementation library resides, which is one goal and feature of COM: reusability and extensibility.

Since you typically don't know where the implementation class is, you must know more information about it. Early-bound automation clients use this information to cache member IDs at compile-time and use that information to call methods directly. Late-bound automation clients use this information during design-time but call the methods based on their IDs at run-time through the power of the IDispatch interface. For more information about this subject, see the documentation for the IDispatch interface.

Now that you have some idea what type libraries are, you may wonder why and how you should use them. The "how" will be answered by the following sections and is the scope of this tutorial. The "why" is because you typically must know at design- and compile-time what members are available for use. Unless you're writing a completely autonomous client that discovers all type information at run-time through IDispatch and knows what to do with more interfaces exposed, you'll need to know what to call, even in late-bound environments like Visual Basic, in which case you "reference" libraries. The compilers will take care of a lot of detail for you if you take advantage of them.

Referencing Type Libraries

As with most COM objects, you can refer to typelibs using several methods. They are identified by globally unique identifiers (GUIDs), or more specifically LIBIDs. Unlike COM objects, however, typelibs typically only have one LIBID for all versions of the typelib. This alone improves portability, especially for late-bound clients or other implementation classes. Similar techniques can be used to import specific COM objects as well, using either their class identifier (CLSID) or their program ID, both version-independent and version-dependent identifiers.

You can still reference typelibs by their file path using both relative and absolute paths, but you should usually only do this when it's a typelib you or your company is developing and may not want registered on the system during design-time.

Importing Type Libraries

Now that you know you can reference typelibs using their LIBID, you must know how to leverage that information. In the article previously mentioned, the author needed to import the typelibs for Office and Outlook. You can use oleview.exe (provided in the Platform SDK) to find information about interfaces, such as the LIBID and versions of the typelib present on your system. In most case, typelibs are backwards-compatible but ensuring that a client machine has the minimum or correct version of the COM libraries is recommended and often necessary.

These LIBIDs can be found in your registry under HKEY_CLASSES_ROOT\TypeLib or using oleview.exe. Using oleview.exe yields the following information about the Office and Outlook typelibs on my system:

OleView.exe Screen Shots - Type Libraries

To import these type libraries without namespaces that we must declare with using and with named GUIDs for easy reference (see the MSDN for more attributes), we would type the following:

#import "libid:2DF8D04C-5BFA-101B-BDE5-00AA0044DE52" named_guids no_namespace
#import "libid:00062FFF-0000-0000-C000-000000000046" named_guids no_namespace

This information you can see in the right pane. The GUID - in the form {12341234-1234-1234-1234-123412341234} - is the LIBID and the decimal below it is the version in the format major.minor. Again, the LIBID will typically stay the same for a typelib, but the version will most often change. As you can see from the screen shot, Outlook XP's typelib uses a version of 9.1. If you wanted to modify the code above to use a specific typelib version so that only code compiled against the Outlook XP typelib, you would change the following:

#import "libid:00062FFF-0000-0000-C000-000000000046" version(9.1) named_guids no_namespace

Using this method, you can still control the typelib version used by your application but still don't have to worry about file paths. This is especially handy when working in development teams without a common workstation image. You can even specify language ID to specify which typelib locale to use. If you don't specify a version number, the most recent typelib version is used. In this case, specify the lcid attribute along with a hexadecimal representation of the language ID. For example, en-US (U.S. English) would be "409". This is "1033" in decimal form. If you don't specify a locale ID or only one locale is available, the first or only locale is used.

The information about typelibs can also be used with the less-portable alternative, which is using relative or absolute paths. Both techniques offer advantages over the other, and present disadvantages when porting source code to different systems. Using file references is a good idea, however, when you know that the directory structure of your project layout is consistent throughout your development team and you don't want to register any libraries until it's time to test or deploy. You can see an example of such a situation in my article entitled, "Embedding .NET Controls in Java", or from the example below:

#import "C:\Program Files\Microsoft Office\Office10\msoutl.old" named_guids

This can limit us to specific versions, although keep in mind that a typelib doesn't have to be registered to extract information from it. In development situations that call for file references, you could always include the typelib with your project - perhaps even in source control systems like Visual SourceSafe or CVS - to make sure all members of your development team have the same version.

Referencing COM Objects

What if you don't need to reference the entire typelib and just want a particular control out of the typelib? Using similar alternatives - along with another alternative - and help. COM objects are also identified by GUIDs, specifically known as class IDs or CLSIDs; however, these CLSIDs typically change from version to version of the object. To combat the situation, you can use the object's program ID, or ProgID. ProgIDs can be both version-dependent and version-independent, which means that you can either specify a specific version or use the latest version (or whichever version is referenced).

A version-dependent ProgID typically takes the form AppID.ClassID.Major[.Minor]. For example, if you wanted to reference the Outlook Application object (the object from which all application-specific methods typically originate), you could use the version-dependent ProgID, Outlook.Application.10. If you knew that your method calls are compatible with many versions of Outlook - perhaps even all since Outlook isn't that old - you could use the version-independent ProgID Outlook.Application. These ProgIDs can be found in your registry directly under HKEY_CLASSES_ROOT, or using oleview.exe, which yields the result:

OleView.exe Screen Shots - Program IDs

You can see both the version-independent and version-dependent ProgIDs in the right pane. The registry stores this information in separate keys and usually points the version-independent at the latest version-dependent ProgID, but this may not always be the case since a number of factors could mistakenly - or intentionally - change this behavior. This is a rare occurrence, however.

Importing COM Objects

Now that you know the ProgID of the object you want to import, you need only modify the previous statements to use a ProgID instead of a LIBID:

#import "progid:Outlook.Application" named_guids no_namespace

A version-independent ProgID is used above. If you want to specify that the Outlook 10 typelib should be imported, you can use either the version-dependent ProgID or the typelib version attribute. Remember that these might not agree, however. You should remember that the typelib version as we learned before was 9.1, not 10. When using ProgIDs, I recommend that you stick with version-dependent ProgIDs instead of using the version attribute; it can get a bit confusing. Using a version-dependent ProgID would look like:

#import "progid:Outlook.Application.10" named_guids no_namepace

Attributes

Throughout the article, I've been mainly consistent with the #import attributes I've used. These are to my preference and different situations call for different measures. For much more information about the attributes available and what they do, see the MSDN.

One such variation of the code examples above is more common, with is to eliminate no_namespace. When you do this, you allow your code to group #import statements in a single file while limiting the scope of calls throughout your source code. If I were to drop the no_namespace attribute, I would have to use the using directive like in the following code:

#import "progid:Outlook.Application" named_guids
using namespace Outlook;

// Or we can use it explicitly...

CComPtr<Outlook::_ContactItem> spContactItem;

See the MSDN for more information about the using declaration and the using directive.

Example

Because this tutorial was inspired by discussions on Deepesh Dhapola's article, "Importing contacts from Outlook", and because I used the Office and Outlook typelib and COM object references through this tutorial, I invite you to download his sample source and change the following lines in OutlookContactsDlg.cpp:

// #import "E:\Program Files\Common Files\Microsoft Shared\Office10\mso.dll" \

//    named_guids

// #import "E:\Microsoft Office\Office10\MSOUTL.OLB" \

//    no_namespace exclude("_IRecipientControl", "_DRecipientControl")


#import "libid:2DF8D04C-5BFA-101B-BDE5-00AA0044DE52" named_guids
#import "libid:00062FFF-0000-0000-C000-000000000046" \
    no_namespace exclude("_IRecipientControl", "_DRecipientControl")

Now, just in case your E: drive (if you have one) is a CD-RW like mine, you shouldn't have any problems compiling the sample so long as you have the typelib registered which doesn't mean the application has to be installed.

Summary

Using file references shouldn't be thrown out altogether. File references are typically necessary when a development team is developing both automation serves and clients, especially when dealing with newer versions of an existing project. However, I hope this tutorial has given you alternatives to use to make your source code more portable from machine to machine for the majority of times when you're using pre-existing typelibs to extend your own application, or to even extend existing functionality. Importing typelibs helps reduce your code through reusable code and makes your development job often easier. Make your job even easier still by considering these alternatives to importing typelibs and COM objects that next time your developing for COM.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here