Figure 1   Pager.idl

 ///////////////////////////////////////////////////////
//
// Pager.idl
// 
// Describes an interface to a pager
// 
//
[ 
// interface attributes
    uuid(00110011-0101-0101-0101-000111000111),
    object,
    pointer_default(unique)
]
interface IPager : IUnknown
{
// bring in the standard COM interface definitions
    import "objidl.idl";

// typedef a struct that contains two UNICODE strings
    typedef struct tagPAGE {
        [string] const wchar_t *pwszSender;
        [string] const wchar_t *pwszMessage;
    } PAGE;

// define a method that sends a PAGE with an array of 
// cCodes DWORDs to the object
    HRESULT PageSomeone([in] const PAGE *pp,
                        [in] DWORD cCodes,
                        [in, size_is(cCodes)] DWORD rgCodes[]);

// define a method that gets a string from the object
    HRESULT RecallLastPage([out, string] wchar_t **ppszMsg);

// define a method that gets upto cMaxCodes DWORDs from the object
    HRESULT RecallLastCodes([in] DWORD cMaxCodes,
                           [out] DWORD *pcActualCodes,
                           [out, size_is(cMaxCodes), 
                           length_is(*pcActualCodes)] DWORD rgCodes[]);
}

Figure 2   IDL Keywords

Attribute

Context

Meaning

uuid

interface

The IID of the interface for use by QueryInterface

object

interface

Indicates that the interface is a COM interface and not a DCE RPC function-based interface

pointer_default(ptype)

interface

Sets the default pointer attribute for pointers used in the interface

local

interface, method

A prototype should be produced for the generated header file, but does not produce a proxy/stub implementation

in

parameter

The parameter value must be sent from the caller to the object; can be combined with out

out

parameter

The parameter value must be sent from the object to the caller; can be combined with in

ref

parameter

The pointer parameter always points to valid memory (cannot be null) and never points to the same memory as any other method parameter

unique

parameter

The pointer parameter points to valid memory or is null, and never points to the same memory as any other method parameter

ptr

parameter

The pointer parameter points to valid memory or is null, and may point to the same memory as any other method parameter

size_is(cElems)

parameter

The pointer parameter is an array that has the capacity for cElems elements

length_is(cElems)

parameter

The pointer parameter is an array and the first cElems elements are valid and should be marshaled

string

parameter

The pointer parameter points to a null-terminated string, and the result of strlen or wcslen should be used to determine the number of valid bytes to be marshaled

Figure 3   Sample IDL File

 [ uuid(00000000-0000-1111-2222-012312341234), 
  object]
interface IOutside : IUnknown {
    import "objidl.idl";
    HRESULT Method1();
}
[ uuid(00000001-0000-1111-2222-012312341234), 
  object]
interface IOutside2 : IOutside {
    HRESULT Method2();
}

[ uuid(00000002-0000-1111-2222-012312341234),
  version(1.0), lcid(0), helpstring("MyLibrary") ]
library MyLibrary {
    [ uuid(00000003-0000-1111-2222-012312341234),
      object ]
    interface IInside : IUnknown {
        HRESULT Method1();
    }

    [ uuid(00000004-0000-1111-2222-012312341234) ]
    coclass Foo {
        interface IInside;
        interface IOutside;
    }
}

Figure 7   Making FJile System Calls for the Client

 STDMETHODIMP 
CoLogFileSystem::Delete(const wchar_t *pwszFile)
{
  WCHAR sz [1024]; 
  DWORD dw;
  BOOL br;
// perform FS operation while running as client
  CoImpersonateClient();
  br = DeleteFileW(pwszFileName);

// disable impersonation and append to logfile 
// while running as self
  CoRevertToSelf();

  wsprintfW(sz, L"Delete %s", pwszFile);
  wcscat(sz, br ? L"succeeded\n" : L"failed\n");
  WriteFile(m_hfileLog, sz, wcslen(sz) * 2, 
            &dw, 0);
}

Figure 8   Loading an Implementation

 BOOL LoadClassCode(HKEY hkeyClsid, DWORD dwClsCtx)
{
// buffer to hold filename of implementation
  TCHAR szServer[MAX_PATH];
// does client allow InprocServers and is there one?
  if ((dwClsCtx & CLSCTX_INPROC_SERVER) 
      && RegQueryValue(hkeyClsid,
                        "InprocServer32",
REG_SZ, szServer,
sizeof(szServer))) // Load the implementation return LoadInprocServer(szServer); // does client allow InprocHandlers and is there one? else if ((dwClsCtx & CLSCTX_INPROC_HANDLER) && RegQueryValue(hkeyClsid, "InprocHandler32",
REG_SZ, szServer,
sizeof(szServer))) // Load the implementation return LoadInprocHandler(szServer); // does client allow LocalServers and is there one? else if ((dwClsCtx & CLSCTX_LOCAL_SERVER) && RegQueryValue(hkeyClsid, "LocalServer32",
REG_SZ, szServer,
sizeof(szServer))) // Load the implementation return LoadLocalServer(szServer); else return FALSE; }

Figure 9   Launching a Server

 void CreatePagerOnLola(IPager **ppPager, 
                       IMessageSource **ppMsgSrc)
{
  IClassFactory *pcf = 0;
  HRESULT hr;
  COSERVERINFO si;
// plug in the hostname for LOLA (in UNC for this example) si.dwSize = sizeof(si); si.pszName = L"\\\\LOLA"; // initialize out parameters to NULL *ppPager = 0; *ppMsgSrc = 0; // get the Pager class factory on LOLA hr = CoGetClassObject(CLSID_Pager, CLSCTX_REMOTE_SERVER, &si, IID_IClassFactory, (void**)&pcf); if (SUCCEEDED(hr)) { // instantiate the object and bind first ptr. hr = pcf->CreateInstance(0, IID_IPager, (void**)ppPager); if (SUCCEEDED(hr)) // QueryInterface for the second interface ptr. (*ppPager)->QueryInterface( IID_IMessageSource, (void**)ppMsgSrc); pcf->Release(); } }

Figure 10   Using CoCreateInstanceEx

 void CreatePagerOnLola(IPager **ppPager, 
                       IMessageSource **ppMsgSrc)
{
  HRESULT hr;
  COSERVERINFO si;
// plug in the hostname for LOLA si.dwSize = sizeof(si); si.pszName = L"\\\\LOLA"; // initialize out parameters to NULL *ppPager = 0; *ppMsgSrc = 0; // set up MULTI_QI array to receive the resultant // pointers to the object. CoCreateInstanceEx will // QI the object once per array element using the // pIID parameter as the GUID. MULTI_QI rgmqi[2]; ZeroMemory(rgmqi, sizeof(rgmqi)); rgmqi[0].pIID = &IID_IPager; rgmqu[1].pIID = &IID_IMessageSouce; // create the instance on LOLA, initializing both // interface pointers in one pass hr = CoCreateInstanceEx(CLSID_Pager, 0, CLSCTX_REMOTE_SERVER, &si, 2, rgmqi); if (hr == S_OK) { // all of the QI's succeeded! *ppPager = (IPager*)rgmqi[0].pItf; *ppMsgSrc = (IMessageSource*)rgmqi[1].pItf; } else if (hr == CO_S_NOTALLINTERFACES) { // at least one but not all QI's succeeded if (SUCCEEDED(rgmqi[0].hr)) *ppPager = (IPager*)rgmqi[0].pItf; if (SUCCEEDED(rgmqi[1].hr)) *ppMsgSrc = (IMessageSource*)rgmqi[1].pItf; } else { // the object was not instantiated } }

Figure 11   IPropertyStorage

 interface IPropertyStorage : IUnknown
{
    HRESULT ReadMultiple(ULONG cpspec,
                        PROPSPEC rgpspec[],
                        PROPVARIANT rgpropvar[]);

    HRESULT WriteMultiple(ULONG cpspec,
                          PROPSPEC rgpspec[],
                          PROPVARIANT rgpropvar[],
                          PROPID propidNameFirst)

    HRESULT DeleteMultiple(ULONG cpspec,
                           PROPSPEC rgpspec[]);

    HRESULT ReadPropertyNames(ULONG cpropid,
                              PROPID rgpropid[],
                             LPOLESTR rgszName[]);

    HRESULT WritePropertyNames(ULONG cpropid,
                               PROPID rgpropid[],
                             LPOLESTR rgszName[]);

    HRESULT DeletePropertyNames(ULONG cpropid, 
                               PROPID rgpropid[]);

    HRESULT Commit(DWORD grfCommitFlags);

    HRESULT Revert();

    HRESULT Enum(IEnumSTATPROPSTG **ppenum);

    HRESULT SetTimes(FILETIME const *pctime,
                     FILETIME const *patime,
                     FILETIME const *pmtime);

    HRESULT SetClass(REFCLSID clsid);

    HRESULT Stat(STATPROPSETSTG *pstatpsstg);
}

Figure 12   PROPVARIANT

 typedef struct tagPROPVARIANT
{
    VARTYPE vt;
    WORD    wReserved1;
    WORD    wReserved2;
    WORD    wReserved3;
    union  {
        UCHAR               bVal;
        short               iVal;
        USHORT              uiVal;
        VARIANT_BOOL        bool;
        long                lVal;
        ULONG               ulVal;
        float               fltVal;
        SCODE               scode;
        LARGE_INTEGER       hVal;
        ULARGE_INTEGER      uhVal;
        double              dblVal;
        CY                  cyVal;
        DATE                date;
        FILETIME            filetime;
        CLSID *             puuid;
        BLOB                blob;
        CLIPDATA            *pclipdata;
        IStream *           pStream;
        IStorage *          pStorage;
        BSTR                bstrVal;
        LPSTR               pszVal;
        LPWSTR              pwszVal;
        CAUB                caub;
        CAI                 cai;
        CAUI                caui;
        CABOOL              cabool;
        CAL                 cal;
        CAUL                caul;
        CAFLT               caflt;
        CASCODE             cascode;
        CAH                 cah;
        CAUH                cauh;
        CADBL               cadbl;
        CACY                cacy;
        CADATE              cadate;
        CAFILETIME          cafiletime;
        CACLSID             cauuid;
        CACLIPDATA          caclipdata;
        CABSTR              cabstr;
        CALPSTR             calpstr;
        CALPWSTR            calpwstr;
        CAPROPVARIANT       capropvar;
    };
}PROPVARIANT;

Figure 13   DisplayAuthorTitle.cpp

 ///////////////////////////////////////////////////////
//
// DisplayAuthorTitle.cpp
// 
// Displays the author and title properties of a document
// 
//
enum {
    PID_TITLE = 2,
    PID_SUBJECT,
    PID_AUTHOR,
    PID_KEYWORDS,
    PID_COMMENTS,
    PID_TEMPLATE,
    PID_LASTAUTHOR,
    PID_REVNUMBER,
    PID_EDITTIME,
    PID_LASTPRINTED,
    PID_CREATE_DTM_RO,
    PID_LASTSAVE_DTM,
    PID_PAGECOUNT,
    PID_WORDCOUNT,
    PID_CHARCOUNT,
    PID_THUMBNAIL,
    PID_APPNAME,
    PID_SECURITYY
};
#define cPID_STANDARD (PID_APPNAME+1-2)