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)