Structure

Summary

PURPOSE

IDL files serve two (and only two) purposes only:

  1. Providing marshalling information to the COM remoting layer.
  2. Providing information about component capabilities for development tools and COM+ runtime.

IDL STRUCTURE

OVERALL STRUCTURE

An IDL file is typically divided into two parts:

  1. Definitions inside the library block.
  2. Definitions outside the library block.

INSIDE LIBRARY BLOCK

// IDL: library block requires only the uuid attribute

[
    uuid(A8A71511-D4B8-11D4-8053-00D0B79F36F8),
    version( 1.0 )
]
library AtomLib
{
    // Interfaces inside the library block should have [oleuatomation] (or [dual] for IDispatch interfaces)
    // attributes to enable the Universal Marshaler
    [
        uuid(51C3382C-D4D1-11d4-8053-00D0B79F36F8),
        oleautomation,
        ...
    ]
    interface IAtom : IUnknown
    {
        ...
    }
    ...
};

OUTSIDE LIBRARY BLOCK

Interfaces whose methods require data types that are not automation compatible  must be declared outside the library block and run with the /Oicf MIDL compiler  switch (in VC++, this equivalent to checking the stubl-ess Proxies check box in the  MIDL tab of Project Settings). Therefore, declare an interface outside the library block  only if its methods deal with non-automation compatible data types. This means that  proxy/stub DLL must be built and registered.

BUILDING A PROXY/STUB DLL

INTERFACE DEFINITIONS, TYPE LIBRARIES, AND OLEAUTOMATION ATTRIBUTE

Interfaces declared outside the library block will not appear in the type library. No interface information will be available to development environments like VB. To force  an interface defined outside the library block to appear in the type library, add a  reference to it in the library section.

// IDL: Forcing an 'outside the library block' interface to appear in the type library

[ ... ]
interface INeutron : IUnknown
{
    ...
};

[ ... ]
library AtomLib
{
    ...
    interface INeutron;     // Reference to INeutron
    
    [
        oleautomation,
        ...
    ]
    interface IAtom : IUnknown
    {
        oleautomation,
        ...
    }
    ...
};

The following table summarizes interface location and interaction with oleautomation:

Interface location [oleautomation]/ [dual] defined [oleautomation] / [dual]  not defined
Inside library  block
  • Interface uses Universal Marshaler
  • Interface appears in type library
  • AVOID. NO INTERCEPTION CODE GENERATED!
Outside library block
  • Interface uses Universal Marshaler
  • Interface does not appear in type  library (unless referenced, perhaps in  the coclass section)
  • Interface does not use Universal Marshaler. Need to  build proxy/stub DLL.
  • Interface does not appear in type library (unless referenced,  perhaps in the coclass section)


LOCAL ATTRIBUTE

IMPORTING OTHER FILES

// IDL: using import within interface definitions

[ ... ]
interface INeutron : IUnknown
{
    import "atom.idl";
    HRESULT AddAtom( [in] IAtom* pAtom );
};

[ ... ]
interface IElectorn : IUnknown
{
    import "atom.idl";
    HRESULT AddAtom( [in] IAtom* pAtom );
};

IMPORTING FILES IN THE LIBRARY BLOCK

COCLASSES

SAMPLE IDL STRUCTURE

/****************************************************************** 
Structure of a model IDL file
******************************************************************/

// Use 'import' to bring in data types defined in external files
import "oaidl.idl";
import "ocidl.idl";


/*******************************************************************
Outside the library block. Interfaces will use Proxy/Stub DLL as 
long as /Oicf MIDL flag is defined. No type library information will 
be generated, unless the interface is referenced in the library block .
*******************************************************************/

[
    uuid(51C3382C-D4D1-11d4-8053-00D0B79F36F9),
    object,
    helpstring("Some meaningful description please"),
    pointer_default(unique)
]
interface INeutorn : IUnknown
{
    // Use 'import' to import externally-defined types used by this interface
   
import "atom.idl"

    HRESULT AddAtom( [in] IAtom* pAtom );
};

[
    uuid(51C3382C-D4D1-11d4-8053-00D0B79F36FA),
    object,
    helpstring("Another meaningful description please"),
    pointer_default(unique)
]
interface IPositron : IUnknown
{
    // Use 'import' to import externally-defined types used by this interface
   
import "atom.idl"

    HRESULT RemoveAtom( [in] IAtom* pAtom );
};


/**************************************************************************
Library block. MIDL will generate a .tlb file. If registered, IAtom will be 
marshaled with the Universal Marshaler. Development tools can also query for
capabilities of the component.

Recall that 'import' statements should not be placed in the library block
**************************************************************************/
[
    uuid(A8A71511-D4B8-11D4-8053-00D0B79F36F8),
    version (33.3)
]
library AtomLib
{
    // Importing stdole2.tlb should be the first statement in the library block. stdole32.tlb is an older 
    // version and should not really be added
    importlib( "stdole2.tlb" );

    // Force INeutron, a non-automation compatible, to appear in the type library to enable development tools 
    // like VB to get information on it
   
interface INeutron;

    // Interfaces inside the library block should have [oleuatomation] or [dual] attributes (if IDispatch-derived) 
    // to use the Universal Marshaler
   
[
        uuid(51C3382C-D4D1-11d4-8053-00D0B79F36F8),
        object,
        oleautomation,
        helpstring("Another meaningful description please"),
        pointer_default( unique )
    ]
    interface IAtom : IUnknown
    {
        HRESULT Explode( [out, retval] long *pTeraJoules );
    }

    // Always define a default interface for VB. If not defined, MIDL will make the first interface the default one.
   
coclass Atom
    {
        [default] interface IAtom;
        interface INeutorn;
        interface IPositron;
    }
};