BBv2 provides ability to build COM servers using the MSVC package. The ATL project wizard from Microsoft Visual Studio supports three types of projects:
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.
Compiling of in-process COM server requires the next steps:
The following rule should be used for building an .idl file:
---- jamfile.v2 ---- mstypelib example-typelib : example.idl ; ----
The rule generates 5 files:
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.
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 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 ; ----
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 name | Visual Studio file name |
example-typelib.tlb | example.tlb |
example-typelib.h | example.h |
example-typelib_i.c | example_i.c |
example-typelib_dlldata.c | dlldata.c |
example-typelib_proxy.c | example_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.