1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
/* A simple COM component, as per the book */
#include <stdio.h>
#include <stddef.h>
#include "comcomp.h"
typedef struct { unsigned char data[16]; } IID;
typedef int HRESULT;
typedef unsigned long ULONG;
#define IsEqualIID(a,b) (memcmp(a, b, sizeof(IID)) == 0)
#define InterlockedIncrement(p) (++(*(p)))
#define InterlockedDecrement(p) (--(*(p)))
#define S_OK 0
#define E_NOINTERFACE (-1)
IID IID_IUnknown = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80 } };
IID IID_IX = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x81 } };
IID IID_IY = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x82 } };
struct CA {
struct IXVtbl * vtbl_ix;
struct IYVtbl * vtbl_ix;
int refcount;
int ident;
};
#define CA_of_IX(i) ((struct CA *) (i))
#define CA_of_IY(i) ((struct CA *) (((void **) (i)) - 1))
#define IX_of_CA(i) ((struct IX *) (i))
#define IY_of_CA(i) ((struct IY *) (((void **) (i)) + 1))
ULONG CA_AddRef(struct CA * this)
{
ULONG res = InterlockedIncrement(&this->refcount);
printf("%d: AddRef: new refcount is %d\n", this->ident, res);
return res;
}
ULONG CA_Release(struct CA * this) {
ULONG res = InterlockedDecrement(&this->refcount);
printf("%d: Release: new refcount is %d\n", this->ident, res);
if (res == 0) {
printf("%d: destroying component.\n", this->ident);
free(this);
}
return res;
}
HRESULT CA_QueryInterface(struct CA * this, IID * iid, void ** res)
{
if (IsEqualIID(iid, &IID_IUnknown)) {
printf("%d: QueryInterface: return IUnknown pointer.\n", this->ident);
*res = IX_of_CA(this);
} else if (IsEqualIID(iid, &IID_IX)) {
printf("%d: QueryInterface: return IX pointer.\n", ident);
*res = IX_of_CA(this);
} else if (IsEqualIID(iid, &IID_IY)) {
printf("%d: QueryInterface: return IY pointer.\n", ident);
*res = IY_of_CA(this);
} else {
printf("%d: QueryInterface: interface not supported.\n", ident);
*res = NULL;
return E_NOINTERFACE;
}
CA_AddRef(this);
return S_OK;
}
HRESULT IX_QueryInterface(struct IX * this, IID * iid, void ** res)
{ return CA_QueryInterface(CA_of_IX(this), iid, res); }
ULONG IX_AddRef(struct IX * this)
{ return CA_AddRef(CA_of_IX(this)); }
ULONG IX_Release(struct IX * this)
{ return CA_Release(CA_of_IX(this)); }
void IX_F(struct IX * this, int x)
{
printf("%d: F(%d) called.\n", this->ident, x);
}
HRESULT IY_QueryInterface(struct IY * this, IID * iid, void ** res)
{ return CA_QueryInterface(CA_of_IY(this), iid, res); }
ULONG IY_AddRef(struct IY * this)
{ return CA_AddRef(CA_of_IY(this)); }
ULONG IY_Release(struct IY * this)
{ return CA_Release(CA_of_IY(this)); }
int IY_G(struct IY * this, int x)
{
int res = 3 * x + 1;
printf("%d: G(%d) called, returning %d.\n", this->ident, x, res);
return res;
}
struct IXVtbl IX_table = { IX_QueryInterface, IX_AddRef, IX_Release, IX_F };
struct IYVtbl IY_table = { IY_QueryInterface, IY_AddRef, IY_Release, IY_G };
struct CA * make_CA()
{
struct CA * c = malloc(sizeof(struct CA));
c->vtbl_ix = &IX_table;
c->vtbl_iy = &IY_table;
c->refcount = 0;
c->ident = ++CA_ident;
return c;
}
static void test_component(struct IUnknown * c)
{
struct IX * cix;
struct IY * ciy;
int res;
// Test IX interface
if (c->lpVtbl->QueryInterface(c, &IID_IX, (void **) &cix) == S_OK) {
printf("test: got IX interface.\n");
printf("test: calling F(12) on it.\n");
cix->lpVtbl->F(cix, 12);
printf("test: releasing the IX interface.\n");
res = cix->lpVtbl->Release(cix);
printf("test: return of Release() is %d.\n", res);
}
// Test IY interface
if (c->lpVtbl->QueryInterface(c, &IID_IY, (void **) &ciy) == S_OK) {
printf("test: got IY interface.\n");
printf("test: calling G(3) on it.\n");
res = ciy->lpVtbl->G(ciy, 3);
printf("test: return value is %d.\n", res);
printf("test: releasing the IY interface.\n");
res = ciy->lpVtbl->Release(ciy);
printf("test: return of Release() is %d.\n", res);
}
}
void test_ix(struct IX * c)
{
test_component((struct IUnknown *) c);
}
void test_iy(struct IY * c)
{
test_component((struct IUnknown *) c);
}
extern "C"
int main(int argc, char ** argv)
{
struct IUnknown * i = create_instance();
test_component(i);
i->Release();
return 0;
}
#endif
|