Building a Proxy/Stub DLL

Completed IDL files must be compiled with the IDL compiler, MIDL.EXE. The IDL compiler takes each IDL file and generates proxy/stub code (IDLNAME_P.C), an interface header file (IDLNAME.H), and an interface identifier file (IDLNAME_I.C). The header files contain both C and C++ class definitions.

By default, MIDL.EXE generates names based on your IDL file’s name. However, you can use the following command line switches to override the default:

Command line switch

Description

-header

Specifies the name of the interface header file.

-proxy

Specifies the name of the proxy source file.

-iid

Specifies the name of the interface identifier file.

After a successful compile of the IDL file, the generated files are run through the standard C/C++ compile and link steps. These source files implement helper functions for marshaling and an implementation of DllGetClassObject for the proxy/stub libraries, among other things. Note that the RPC4RT.LIB library includes an implementation of the DllGetClassObject function. In this provided implementation, the CLSID of the proxy/stub has to be the same as the IID of your custom interface. If you want to use a CLSID that differs from the IID then you must provide your own implementation of the DllGetClassObject function.

The following diagram shows all the pieces involved in a build of a custom proxy/stub DLL. The IDL file, ITF.IDL, is fed into the IDL compiler. Three files are generated: ITF_P.C, ITF.H, and ITF_I.C. These three files are compiled and linked and the result is PROXSTUB.DLL.

Build Process for Proxy/Stub DLL.

It is important to remember that an IDL file is more than just a fancy header file for interfaces &emdash; it allows you to use your interfaces cross-machine, cross-process or even cross-thread.

IDL is a programming language for remoting. This means that all attributes should be verified before releasing IDL files for custom interfaces to customers.

Even if your interface will never be used out-of-process, it may be used cross-thread. The worst problem for an unchecked IDL file can arise for in-process servers that do not support multiple single-threaded apartments). A server that does not specify a threading model is implicitly single-threaded. Everything marked single threaded is forced over to the thread that first called CoInitializeor CoInitializeEx. If some other thread was the one that activated the object, all the interfaces on that single threaded server must be remoted back to the activating thread, which can result in a return of REGDB_E_IID_NOTREG in response to a call to QueryInterface). Unless you can absolutely assert that your interface is both in-process only, and always going to be called on the same thread, you will get remoted at some time.

Even if you create a proxy DLL, it is a good idea to test it by remoting your interfaces to avoid small errors. For example, “ [in] char * pszString" means send a pointer to a single character. To send a pointer to a character string, you need to have "[in, string] char * pszString". Both generate the same header. Remoting your interfaces helps you avoid these problems.

Finally, with the advent of distributed OLE, it is crucial that IDL files are correct before you send them out, because the world is bigger and faster these days. If you made a mistake in your IDL, and the interface is not remoted correctly the first time you ship, then you are faced with the problem of trying to figure out how to fix it, which can be very difficult. If you upgrade one machine to the correct proxy/stub, it won't interoperate with one that has the old proxy/stub. You either have to revise your interface with a new IID and leave the old one in for backwards compatibility, or you have to convert every client and every server machine everywhere at the same time.

The same considerations apply to those writing ODL files. IDL and ODL files just use different compilers to accomplish the same thing. In fact, with SUR and MIDL 3.0, the same tool does both, and the distinction vanishes (.IDL is to .ODL as CPP is to .CXX)