[Home]Boost.Build V2/MIDL HOWTO

BOOST WIKI | Boost.Build V2 | RecentChanges | Preferences | Page List | Links List

How to build a COM server using BBv2?

BBv2 provides ability to build COM servers using the MSVC package. The ATL project wizard from Microsoft Visual Studio supports three types of projects:

  1. In-process server consisting of the COM server dynamic library itself and the proxy dynamic library;
  2. In-process server having the COM server and the proxy merged into one dynamic library;
  3. Out-of-process server (an executable).

Examples below show how you can build all three kinds of projects using BBv2. In fact all examples were converted from Microsoft Visual Studio projects with minimal changes in structure. Helper code also remains intact. So in this HOWTO we will focus on BBv2 specific things only.

Note: you can download source code of all examples using this link: [How to build a COM server using BBv2.zip]

Each of three kinds of projects uses Microsoft Interface Definition Language (MIDL) to define COM objects and interfaces. The definitions are stored as .idl file(s). An .idl file is processed by MIDL compiler (midl.exe) which turns the file into several .h and .c files and generates the type library (.tlb). The produced files are later used when building both the COM server and the proxy dynamic libraries.

In-process COM server

Compiling of in-process COM server requires the next steps:

  1. Processing .idl;
  2. Building of COM library itself;
  3. Building of the proxy library.

The following rule should be used for building an .idl file:

---- jamfile.v2 ----
mstypelib example-typelib
    :
        example.idl 
    ;
----

The rule generates 5 files:

  1. example-typelib.tlb - the type library itself;
  2. example-typelib.h - contains definitions of interfaces;
  3. example-typelib_i.c - contains the IIDs and CLSIDs;
  4. example-typelib_dlldata.c - defines entry points of the proxy library;
  5. example-typelib_proxy.c - contains proxy/stub code and definitions.

An in-process server library uses only first three of them. The type library is included to resources:

---- example.rc ----
1 TYPELIB "example-typelib.tlb"
----

example-typelib.h is included wherever the interfaces, IIDs or CLSIDs are used in the code. example-typelib_i.c should be simply compiled into the server's library. A good way to do it is including it to the main source file.

A typical in-process server project should look very similar to the following:

---- jamfile.v2 ----
lib example
    :
        example.cpp 
        example.rc
    :
        <link>shared
        <def-file>example.def

        <implicit-dependency>example-typelib

        <define>WIN32
        <define>_WIN32_WINNT=0x0500
    ;
----

Note the implicit-dependency requirement. It ensures that BBv2 will add the build directory to the include directories list and so the generated files will be found successfully. The <define> requirements are also important because the generated files include standard RPC headers requiring presence of these defines.

The rest of the sources generated by the MIDL compiler is used to build the proxy dynamic library. See the example below:

---- example_proxy.c ----
#undef USE_STUBLESS_PROXY
#define USE_STUBLESS_PROXY

#undef REGISTER_PROXY_DLL
#define REGISTER_PROXY_DLL

// for Win2000, change it to 0x0400 for NT4 or Win95 with DCOM
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500

#pragma comment(lib, "rpcns4.lib") 
#pragma comment(lib, "rpcrt4.lib") 
#pragma comment(lib, "oleaut32.lib") 

#include "example-typelib_dlldata.c" 
#include "example-typelib_proxy.c" 
#include "example-typelib_i.c"
----

---- jamfile.v2 ----
lib exampleps
    :
        example_proxy.c
    :
        <link>shared
        <def-file>pilot.coreps.def

        <implicit-dependency>example-typelib

        <define>WIN32
        <define>_WIN32_WINNT=0x0500
    ; 
----

As you can see example_proxy.c not also includes required files but also defines mandatory directives and makes the compiler links to required libraries.

In-process COM server merged with proxy/stub code

Merging proxy/stub code into the COM server library benefits by reducing number of .dll files per COM server to only one. Only few changes comparing to the previous configuration required to build such a project:

---- example_proxy.c ----
#ifdef _MERGE_PROXYSTUB

#undef USE_STUBLESS_PROXY
#define USE_STUBLESS_PROXY

#undef REGISTER_PROXY_DLL
#define REGISTER_PROXY_DLL

// for Win2000, change it to 0x0400 for NT4 or Win95 with DCOM
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500

#pragma comment(lib, "rpcns4.lib") 
#pragma comment(lib, "rpcrt4.lib") 
#pragma comment(lib, "oleaut32.lib") 

#define ENTRY_PREFIX Prx

#include "example-typelib_dlldata.c" 
#include "example-typelib_proxy.c" 
#include "example-typelib_i.c"

#endif
----

---- example_proxy.h ----
#ifdef _MERGE_PROXYSTUB

extern "C" 
{
    BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, 
        LPVOID lpReserved);
    STDAPI PrxDllCanUnloadNow(void);
    STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
    STDAPI PrxDllRegisterServer(void);
    STDAPI PrxDllUnregisterServer(void);
}

#endif

Comparing BBv2 and Visual Studio projects you can notice that example_proxy.c and example_proxy.h shown above are just renamed dlldatax.c and dlldatax.h correspondingly. Also compatibility with Visual Studio is the reason why the _MERGE_PROXYSTUB directive should be defined to build the project successfully.

---- jamfile.v2 ----
mstypelib example-typelib
    :
        example.idl 
    ;

lib example
    :
        example.cpp 
        example_proxy.c
        example.rc
    :
        <link>shared
        <def-file>example.def

        <implicit-dependency>example-typelib

        <define>WIN32
        <define>_WIN32_WINNT=0x0500
        <define>_MERGE_PROXYSTUB
    ;
----

Out-of-process COM server

Out-of-process COM server is built in a very same way as in-process server does. Basically the only difference is using exe rule instead of lib to build an executable.

---- jamfile.v2 ----
exe example
    :
        example.cpp 
        example.rc
    :
        <user-interface>gui

        <implicit-dependency>example-typelib

        <define>WIN32
        <define>_WIN32_WINNT=0x0500
    ;
----

Q&A

Q1: Why should I use a separate rule to process an .idl file?

A1: The sources produced by MIDL compiler are used by both a COM server library and a proxy library. If you add .idl as a sources file of both libraries BBv2 will process the same .idl file twice - once for each library.

Q2: I'm using the 'merged' project configuration. Can I add .idl to the list of sources?

A2: Yes, you can do it but it is not supported feature. You won't be able to use example_proxy.c wrapper for generated files so you will have to move all definitions to Jamfile.v2 and link with the libraries mentioned in the file.

Q3: I'm converting a Visual Studio project and I get the compiler error 'Cannot open include file example.h'.

A3: BBv2 and Visual Studio project use different file names for files generated by the MIDL compiler. See the following table:

BBv2 file nameVisual Studio file name
example-typelib.tlbexample.tlb
example-typelib.hexample.h
example-typelib_i.cexample_i.c
example-typelib_dlldata.cdlldata.c
example-typelib_proxy.cexample_p.c

Q4: I'm converting a Visual Studio project and I get the linker error 'unresolved external symbol _LIBID_exampleLib'.

A4: Include example-typelib_i.c to one of the source files.


BOOST WIKI | Boost.Build V2 | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited September 20, 2008 9:27 am (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers