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 File 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)
// {F29F85E0-4FF9-1068-AB91-08002B27B3D9}
DEFINE_GUID(FMTID_SummaryInformation, 
0XF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 
                      0x2b, 0x27, 0xB3, 0xD9);

void DisplayAuthorTitle(LPCOLESTR pwszFileName)
{
// open the file
    IStorage *pstg = 0;
    HRESULT hr = StgOpenStorage(pwszFileName,
                                0,
                                 STGM_READWRITE
                                 | STGM_DIRECT
                                 | STGM_SHARE_EXCLUSIVE,
                                 0,0,
                                 &pstg);

    if (SUCCEEDED(hr))
    {
// access the property set manager for the root storage
        IPropertySetStorage *ppss = 0;
        hr = pstg->QueryInterface(IID_IPropertySetStorage, 
                                  (void**)&ppss);
        if (SUCCEEDED(hr))
        {
// open the Summary Information property set 
            IPropertyStorage *pps = 0;
            hr = ppss->Open(FMTID_SummaryInformation,
                            STGM_DIRECT
                            | STGM_READ
                            | STGM_SHARE_EXCLUSIVE,
                            &pps);
            if (SUCCEEDED(hr))
            {
// indicate which properties should be read
                PROPSPEC rgps[2];
                rgps[0].ulKind = PRSPEC_PROPID;
                rgps[0].propid = PID_AUTHOR;
                rgps[1].ulKind = PRSPEC_PROPID;
                rgps[1].propid = PID_TITLE;
                PROPVARIANT rgValues[2];

// read the properties into rgValues
                hr = pps->ReadMultiple(2, rgps, rgValues);
                if (hr = = S_OK)
                {
// display the values
                    LPSTR pszAuthor = rgValues[0].pszVal;
                    LPSTR pszTitle =  rgValues[1].pszVal;
                    if (rgValues[0].vt != VT_LPSTR) 
                        pszAuthor = "Self-authored";
                    if (rgValues[1].vt != VT_LPSTR) 
                        pszTitle = "Anonymous Document";
                    ::MessageBox(0, pszTitle ,pszAuthor, MB_OK);
// free the allocated resources in the variant array
                    FreePropVariantArray(2, rgValues);
                }
                else
                    Error("ReadMultiple", hr);
                pps->Release();
            }
            else
                Error("Create Property Set", hr);
            ppss->Release();
        }
        else
            Error("QI for IPropertySetStorage", hr);
        pstg->Release();
    }
    else
        Error("StgCreateDocfile", hr);

}