common.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 10k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*****************************************************************************
  2.  *
  3.  * common.c - Shared stuff that operates on all classes
  4.  *
  5.  * WARNING!  The Common services work only if you pass in the
  6.  * "primary object".  This is vacuous if you don't use multiple
  7.  * inheritance, since there's only one object in the first place.
  8.  *
  9.  * If you use multiple inheritance, make sure you pass the pointer
  10.  * to the object that you use as IUnknown.
  11.  *
  12.  * The exceptions are the Forward_* functions, which work on
  13.  * pointers to non-primary interfaces.  They forward the call to the
  14.  * primary interface.
  15.  *
  16.  *****************************************************************************/
  17. #include "fnd.h"
  18. /*****************************************************************************
  19.  *
  20.  * The sqiffle for this file.
  21.  *
  22.  *****************************************************************************/
  23. #define sqfl sqflCommon
  24. /*****************************************************************************
  25.  *
  26.  *  USAGE FOR OLE OBJECTS
  27.  *
  28.  * Suppose you want to implement an object called CObj that supports
  29.  * the interfaces Foo, Bar, and Baz.  Suppose that you opt for
  30.  * Foo as the primary interface.
  31.  *
  32.  * >> NAMING CONVENTION <<
  33.  *
  34.  *     COM objects begin with the letter "C".
  35.  *
  36.  * (1) Declare the primary and secondary vtbls.
  37.  *
  38.  * Primary_Interface(CObj, IFoo);
  39.  * Secondary_Interface(CObj, IBar);
  40.  * Secondary_Interface(CObj, IBaz);
  41.  *
  42.  * (3) Declare the object itself.
  43.  *
  44.  * typedef struct CObj {
  45.  *     IFoo  foo;     // Primary must come first
  46.  *     IBar bar;
  47.  *     IBaz baz;
  48.  *     ... other fields ...
  49.  * } CObj;
  50.  *
  51.  * (4) Implement the methods.
  52.  *
  53.  *     You may *not* reimplement the AddRef and Release methods!
  54.  *     although you can subclass them.
  55.  *
  56.  * (5) To allocate an object of the appropriate type, write
  57.  *
  58.  * hres = Common_New(CObj, ppvOut);
  59.  *
  60.  *     or, if the object is variable-sized,
  61.  *
  62.  * hres = Common_NewCb(cb, CObj, ppvOut);
  63.  *
  64.  *     If the object supports multiple interfaces, you also need to
  65.  *     initialize all the secondary interfaces.
  66.  *
  67.  * CObj *pco = *ppvOut;
  68.  * pco->bar = Secondary_Vtbl(CObj, IBar);
  69.  * pco->baz = Secondary_Vtbl(CObj, IBaz);
  70.  *
  71.  * (6) Define the vtbls.
  72.  *
  73.  * #pragma BEGIN_CONST_DATA
  74.  *
  75.  * // The macros will declare QueryInterface, AddRef and Release
  76.  * // so don't list them again
  77.  *
  78.  * Primary_Interface_Begin(CObj, IFoo)
  79.  *     CObj_FooMethod1,
  80.  *     CObj_FooMethod2,
  81.  *     CObj_FooMethod3,
  82.  *     CObj_FooMethod4,
  83.  * Primary_Interface_End(Obj, IFoo)
  84.  *
  85.  * Secondary_Interface_Begin(CObj, IBar, bar)
  86.  *     CObj_Bar_BarMethod1,
  87.  *     CObj_Bar_BarMethod2,
  88.  * Secondary_Interface_Begin(CObj, IBar, bar)
  89.  *
  90.  * Secondary_Interface_Begin(CObj, IBaz, baz)
  91.  *     CObj_Baz_BazMethod1,
  92.  *     CObj_Baz_BazMethod2,
  93.  *     CObj_Baz_BazMethod3,
  94.  * Secondary_Interface_Begin(CObj, IBaz, baz)
  95.  *
  96.  *****************************************************************************/
  97. /*****************************************************************************
  98.  *
  99.  *  USAGE FOR NON-OLE OBJECTS
  100.  *
  101.  * All objects are COM objects, even if they are never given out.
  102.  * In the simplest case, it just derives from IUnknown.
  103.  *
  104.  * Suppose you want to implement an object called Obj which is
  105.  * used only internally.
  106.  *
  107.  * (1) Declare the vtbl.
  108.  *
  109.  * Simple_Interface(Obj);
  110.  *
  111.  * (3) Declare the object itself.
  112.  *
  113.  * typedef struct Obj {
  114.  *     IUnknown unk;
  115.  *     ... other fields ...
  116.  * } Obj;
  117.  *
  118.  * (4) Implement the methods.
  119.  *
  120.  *     You may *not* override the QueryInterface, AddRef or
  121.  *     Release methods!
  122.  *
  123.  * (5) Allocating an object of the appropriate type is the same
  124.  *     as with OLE objects.
  125.  *
  126.  * (6) Define the "vtbl".
  127.  *
  128.  * #pragma BEGIN_CONST_DATA
  129.  *
  130.  * Simple_Interface_Begin(Obj)
  131.  * Simple_Interface_End(Obj)
  132.  *
  133.  *     That's right, nothing goes between the Begin and the End.
  134.  *
  135.  *****************************************************************************/
  136. /*****************************************************************************
  137.  *
  138.  * CommonInfo
  139.  *
  140.  * Information tracked for all common objects.
  141.  *
  142.  * A common object looks like this:
  143.  *
  144.  *   riid
  145.  *              cRef   FinalizeProc
  146.  * pFoo -> lpVtbl -> QueryInterface
  147.  * data   Common_AddRef
  148.  * data   Common_Release
  149.  * ...   ...
  150.  *
  151.  * Essentially, we use the otherwise-unused space above the
  152.  * pointers to record our bookkeeping information.
  153.  *
  154.  * cRef      = object reference count
  155.  * riid      = object iid
  156.  * FinalizeProc = Finalization procedure
  157.  *
  158.  * For secondary interfaces, it looks like this:
  159.  *
  160.  *                 offset to primary interface
  161.  * pFoo -> lpVtbl -> Forward_QueryInterface
  162.  *   Forward_AddRef
  163.  *   Forward_Release
  164.  *   ...
  165.  *
  166.  *****************************************************************************/
  167. typedef struct CommonInfoN {
  168.   D(ULONG cin_dwSig;)
  169.     ULONG cin_cRef;
  170. } CommonInfoN, CIN, *PCIN;
  171. typedef struct CommonInfoP {
  172.     PREVTBL *cip_prevtbl;
  173. } CommonInfoP, CIP, *PCIP;
  174. typedef struct CommonInfoP2 {
  175.     PREVTBL2 *cip2_prevtbl2;
  176. } CommonInfoP2, CIP2, *PCIP2;
  177. typedef union CommonInfo {
  178.     CIN cin[1];
  179.     CIP cip[1];
  180.     CIP2 cip2[1];
  181. } CommonInfo, CI, *PCI;
  182. #define ci_dwSig cin[-1].cin_dwSig
  183. #define ci_cRef cin[-1].cin_cRef
  184. #define ci_rgfp cip[0].cip_prevtbl
  185. #define ci_riid cip[0].cip_prevtbl[-1].riid
  186. #define ci_Finalize cip[0].cip_prevtbl[-1].FinalizeProc
  187. #define ci_lib cip2[0].cip2_prevtbl2[-1].lib
  188. #ifdef DEBUG
  189. #define ci_Start ci_dwSig
  190. #else
  191. #define ci_Start ci_cRef
  192. #endif
  193. #define ci_dwSignature 0x38162378 /* typed by my cat */
  194. /*****************************************************************************
  195.  *
  196.  * Common_QueryInterface (from IUnknown)
  197.  *
  198.  * Use this for objects that support only one interface.
  199.  *
  200.  *****************************************************************************/
  201. STDMETHODIMP
  202. Common_QueryInterface(PV pv, REFIID riid, PPV ppvObj)
  203. {
  204.     PCI pci = pv;
  205.     HRESULT hres;
  206.     EnterProc(Common_QueryInterface, (_ "pG", pv, riid));
  207.     AssertF(pci->ci_dwSig == ci_dwSignature);
  208.     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, pci->ci_riid)) {
  209. *ppvObj = pv;
  210. Common_AddRef(pv);
  211. hres = NOERROR;
  212.     } else {
  213. *ppvObj = NULL;
  214. hres = ResultFromScode(E_NOINTERFACE);
  215.     }
  216.     ExitOleProcPpv(ppvObj);
  217.     return hres;
  218. }
  219. /*****************************************************************************
  220.  *
  221.  * Common_AddRef (from IUnknown)
  222.  *
  223.  * Increment the object refcount and the dll refcount.
  224.  *
  225.  *****************************************************************************/
  226. STDMETHODIMP_(ULONG)
  227. _Common_AddRef(PV pv)
  228. {
  229.     PCI pci = pv;
  230.     AssertF(pci->ci_dwSig == ci_dwSignature);
  231.     InterlockedIncrement((LPLONG)&g_cRef);
  232.     return ++pci->ci_cRef;
  233. }
  234. /*****************************************************************************
  235.  *
  236.  * Common_Finalize (from Common_Release)
  237.  *
  238.  * By default, no finalization is necessary.
  239.  *
  240.  *****************************************************************************/
  241. void EXTERNAL
  242. Common_Finalize(PV pv)
  243. {
  244.     SquirtSqflPtszV(sqfl, TEXT("Common_Finalize(%08x)"), pv);
  245. }
  246. /*****************************************************************************
  247.  *
  248.  * Common_Release (from IUnknown)
  249.  *
  250.  * Decrement the object refcount and the dll refcount.
  251.  *
  252.  * If the object refcount drops to zero, finalize the object
  253.  * and free it.
  254.  *
  255.  * The finalization handler lives ahead of the object vtbl.
  256.  *
  257.  *****************************************************************************/
  258. STDMETHODIMP_(ULONG)
  259. _Common_Release(PV pv)
  260. {
  261.     PCI pci = pv;
  262.     ULONG ulRc;
  263.     AssertF(pci->ci_dwSig == ci_dwSignature);
  264.     InterlockedDecrement((LPLONG)&g_cRef);
  265.     ulRc = --pci->ci_cRef;
  266.     if (ulRc == 0) {
  267. pci->ci_Finalize(pv);
  268. FreePv(&pci->ci_Start);
  269.     }
  270.     return ulRc;
  271. }
  272. /*****************************************************************************
  273.  *
  274.  * Forward_QueryInterface (from IUnknown)
  275.  *
  276.  * Move to the main object and try again.
  277.  *
  278.  *****************************************************************************/
  279. STDMETHODIMP
  280. Forward_QueryInterface(PV pv, REFIID riid, PPV ppvObj)
  281. {
  282.     PCI pci = pv;
  283.     LPUNKNOWN punk = pvAddPvCb(pv, 0 - pci->ci_lib);
  284.     return Common_QueryInterface(punk, riid, ppvObj);
  285. }
  286. /*****************************************************************************
  287.  *
  288.  * Forward_AddRef (from IUnknown)
  289.  *
  290.  * Move to the main object and try again.
  291.  *
  292.  *****************************************************************************/
  293. STDMETHODIMP_(ULONG)
  294. Forward_AddRef(PV pv)
  295. {
  296.     PCI pci = pv;
  297.     LPUNKNOWN punk = pvAddPvCb(pv, 0 - pci->ci_lib);
  298.     return Common_AddRef(punk);
  299. }
  300. /*****************************************************************************
  301.  *
  302.  * Forward_Release (from IUnknown)
  303.  *
  304.  * Move to the main object and try again.
  305.  *
  306.  *****************************************************************************/
  307. STDMETHODIMP_(ULONG)
  308. Forward_Release(PV pv)
  309. {
  310.     PCI pci = pv;
  311.     LPUNKNOWN punk = pvAddPvCb(pv, 0 - pci->ci_lib);
  312.     return Common_Release(punk);
  313. }
  314. /*****************************************************************************
  315.  *
  316.  * _Common_New
  317.  *
  318.  * Create a new object with refcount 1 and the specific vtbl.
  319.  * All other fields are zero-initialized.
  320.  *
  321.  *****************************************************************************/
  322. STDMETHODIMP
  323. _Common_New(ULONG cb, PV vtbl, PPV ppvObj)
  324. {
  325.     HRESULT hres;
  326.     EnterProc(Common_New, (_ "u", cb));
  327.     SquirtSqflPtszV(sqfl, TEXT("Common_New()"));
  328.     hres = AllocCbPpv(cb + sizeof(CIN), ppvObj);
  329.     if (SUCCEEDED(hres)) {
  330. PCI pci = pvAddPvCb(*ppvObj, sizeof(CIN));
  331.       D(pci->ci_dwSig = ci_dwSignature);
  332. pci->ci_rgfp = (PV)vtbl;
  333. *ppvObj = pci;
  334. Common_AddRef(pci);
  335. hres = NOERROR;
  336.     }
  337.     ExitOleProcPpv(ppvObj);
  338.     return hres;
  339. }
  340. /*****************************************************************************
  341.  *
  342.  * Invoke_Release
  343.  *
  344.  * Release the object (if there is one) and wipe out the back-pointer.
  345.  * Note that we wipe out the value before calling the release, in order
  346.  * to ameliorate various weird callback conditions.
  347.  *
  348.  *****************************************************************************/
  349. void EXTERNAL
  350. Invoke_Release(PV pv)
  351. {
  352.     LPUNKNOWN punk = pvExchangePpvPv(pv, 0);
  353.     if (punk) {
  354. punk->lpVtbl->Release(punk);
  355.     }
  356. }