home *** CD-ROM | disk | FTP | other *** search
/ Chip Special: HTML & Java / Chip-Special_1997-01_HTML-a-Java.bin / javasdk / sdk-java.exe / SDKJava.cab / Samples / native_com / com / natcom.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-10  |  15.7 KB  |  758 lines

  1.  
  2. /*
  3. Copyright (c) 1996  Microsoft Corporation
  4. */
  5.  
  6. #include <windows.h>
  7. #include "natcom.h"
  8. #include <iostream.h>
  9. #include <olectl.h>
  10. #include <stdio.h>
  11.  
  12. // globals
  13.  
  14. ULONG    g_cObject = 0 ;
  15. HANDLE    g_hDllMain ;
  16.  
  17. ////////////////////////////////////////////////////////////////////////////////
  18. //
  19. //    ObjectCreated()
  20. //
  21. //    increments ref count of objects which reference this .DLL
  22. //
  23. ////
  24. VOID ObjectCreated(VOID)
  25. {
  26.     InterlockedIncrement( (LONG*)&g_cObject ) ;
  27. }
  28.  
  29. ////////////////////////////////////////////////////////////////////////////////
  30. //
  31. //    ObjectDestroyed()
  32. //
  33. //    decrements ref count of objects which reference this .dll
  34. //
  35. ////
  36. VOID ObjectDestroyed(VOID)
  37. {
  38.     InterlockedDecrement( (LONG*)&g_cObject ) ;
  39. }
  40.  
  41. ////////////////////////////////////////////////////////////////////////////////
  42. //
  43. //    CNatCom
  44. //
  45. //    contains our COM object
  46. //
  47. ////
  48. class CNatCom : public IUnknown
  49. {
  50.     ////////////////////////////////////////////////////////////////////////
  51.     //
  52.     //    CImpINatCom
  53.     //
  54.     //    implements the INatCom interface.  IUnknown delegates to
  55.     //    controlling unknown (CNatCom if not aggregated).
  56.     //
  57.     ////
  58.     class CImpINatCom : public INatCom
  59.     {
  60.         friend class CNatCom ;
  61.  
  62.         // PUBLIC ------------------------------------------------------
  63.  
  64.         public :
  65.  
  66.         ////////////////////////////////////////////////////////////////
  67.         //
  68.         //
  69.         //    CImpINatCom()
  70.         //
  71.         //    constructor;  Initialize member variables.
  72.         //
  73.         ////
  74.         CImpINatCom()
  75.         {
  76.             m_cRef = 0 ;
  77.             m_pNatCom = NULL ;
  78.             m_punkCCW = NULL ;
  79.         }
  80.  
  81.         ////////////////////////////////////////////////////////////////
  82.         //
  83.         //    ~CImpINatCom()
  84.         //
  85.         //    destructor; release CCW if we have one.
  86.         //
  87.         ////
  88.         ~CImpINatCom()
  89.         {
  90.             if (m_punkCCW)
  91.             {
  92.                 m_punkCCW->Release() ;
  93.             }
  94.         }
  95.  
  96.         ////////////////////////////////////////////////////////////////
  97.         //
  98.         //    QueryInterface()
  99.         //
  100.         //    delegating QI.
  101.         //
  102.         ////
  103.         HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
  104.         {
  105.             return m_pUnkOuter->QueryInterface(riid,ppv) ;
  106.         }
  107.  
  108.         ////////////////////////////////////////////////////////////////
  109.         //
  110.         //    AddRef()
  111.         //
  112.         ////
  113.         ULONG __stdcall AddRef(void)
  114.         {
  115.             return m_pUnkOuter->AddRef() ;
  116.         }
  117.  
  118.         ////////////////////////////////////////////////////////////////
  119.         //
  120.         //    Release()
  121.         //
  122.         //    delegating Release
  123.         //
  124.         ////
  125.         ULONG __stdcall Release(void)
  126.         {
  127.             return m_pUnkOuter->Release() ;
  128.         }
  129.  
  130.         ////////////////////////////////////////////////////////////////
  131.         //
  132.         //    MultParam()
  133.         //
  134.         //    multiplies the two passed arguments and returns the
  135.         //    value back in lVal.
  136.         //
  137.         //    parameters:
  138.         //        lMult    multiplier
  139.         //        lVal    returns value we are multiplied by
  140.         //
  141.         ////
  142.         HRESULT __stdcall MultParam(long lMult, long *lVal)
  143.         {
  144.             *lVal = *lVal * lMult ;
  145.  
  146.             return S_OK ;
  147.         }
  148.  
  149.         ////////////////////////////////////////////////////////////////
  150.         //
  151.         //    Square()
  152.         //
  153.         //    squares lVal, returning the result back in lResult.
  154.         //
  155.         //    parameters:
  156.         //        lVal        value to be squared
  157.         //        lResult     return value = lVal squared
  158.         //
  159.         ////
  160.         HRESULT __stdcall Square(long lVal, long *lResult)
  161.         {
  162.             *lResult = lVal * lVal ;
  163.  
  164.             return S_OK ;
  165.         }
  166.  
  167.         ////////////////////////////////////////////////////////////////
  168.         //
  169.         //    GetClass()
  170.         //
  171.         //    CoCreates a java-implemented object (CCW); returns the
  172.         //    pointer into the v-table to the callee; exercises one
  173.         //    method in the ccw.
  174.         //
  175.         //    parameters:
  176.         //        pjNatCom    pointer to our CCW.
  177.         //
  178.         ////
  179.         HRESULT __stdcall GetClass(jINatCom **pjNatCom)
  180.         {
  181.             HRESULT hr ;
  182.  
  183.             if (FAILED(hr = CoCreateInstance(CLSID_jCNatCom, NULL, CLSCTX_SERVER, IID_IUnknown, (void **)&m_punkCCW)))
  184.             {
  185.                 return hr ;
  186.             }
  187.  
  188.             if (FAILED(hr = m_punkCCW->QueryInterface(IID_jINatCom, (void **)&m_pNatCom)))
  189.             {
  190.                 m_punkCCW->Release() ;        // IID_IUnknown
  191.                 m_punkCCW = NULL ;
  192.  
  193.                 return hr ;
  194.             }
  195.  
  196.             // per the rules of COM we leave the refcount at 2, since
  197.             //  we're passing the pointer back to the caller.  Caller
  198.             //  must Release() the object.
  199.  
  200.             // set member variable
  201.             *pjNatCom = m_pNatCom ;
  202.  
  203.             // invoke java-implemented method
  204.             m_pNatCom->ccwHelloWorld() ;
  205.  
  206.             return S_OK ;
  207.         }
  208.  
  209.         ////////////////////////////////////////////////////////////////
  210.  
  211.         private :
  212.  
  213.         ULONG        m_cRef ;        // ref count
  214.         IUnknown    *m_pUnkOuter ;        // controlling unknown
  215.         jINatCom    *m_pNatCom ;        // ccw interface pointer
  216.         IUnknown    *m_punkCCW ;        // IUnknown of our CCW
  217.     } ;
  218.  
  219.     CImpINatCom m_CImpINatCom ;
  220.  
  221.     // PUBLIC --------------------------------------------------------------
  222.  
  223.     public :
  224.  
  225.     ////////////////////////////////////////////////////////////////////////
  226.     //
  227.     //    CNatCom()
  228.     //
  229.     //    constructor;  initializes variables, including those of
  230.     //    CImpINatCom to point to controlling unknown.
  231.     //
  232.     ////
  233.     CNatCom(IUnknown *punkOuter)
  234.     {
  235.         ObjectCreated() ;
  236.  
  237.         m_cRef = 0 ;
  238.  
  239.         // if this is non-null, we're being aggregated
  240.         if (punkOuter)
  241.         {
  242.             m_pUnkOuter = punkOuter ;
  243.             m_CImpINatCom.m_pUnkOuter = punkOuter ;
  244.         }
  245.         else
  246.         {
  247.             m_pUnkOuter = this ;
  248.             m_CImpINatCom.m_pUnkOuter = this ;
  249.         }
  250.     }
  251.  
  252.     ////////////////////////////////////////////////////////////////////////
  253.     //
  254.     //    ~CNatCom()
  255.     //
  256.     //    destructor.
  257.     //
  258.     ////
  259.     ~CNatCom()
  260.     {
  261.         ObjectDestroyed() ;
  262.     }
  263.  
  264.     ////////////////////////////////////////////////////////////////////////
  265.     //
  266.     //    QueryInterface()
  267.     //
  268.     //    non-delegating QI
  269.     //
  270.     ////
  271.     HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
  272.     {
  273.         *ppv = NULL ;
  274.         
  275.         if (riid == IID_IUnknown)
  276.         {
  277.             *ppv = this ;
  278.         }
  279.  
  280.         if (riid == IID_INatCom)
  281.         {
  282.             *ppv = &m_CImpINatCom ;
  283.         }
  284.  
  285.         if (*ppv == NULL)
  286.         {
  287.             return E_NOINTERFACE ;
  288.         }
  289.  
  290.         ((IUnknown *) *ppv)->AddRef() ;
  291.             
  292.         return NOERROR ;
  293.     }
  294.         
  295.     ////////////////////////////////////////////////////////////////////////
  296.     //
  297.     //    AddRef()
  298.     //
  299.     //    non-delegating AddRef()
  300.     //
  301.     ////
  302.     ULONG __stdcall AddRef(void)
  303.     {
  304.         InterlockedIncrement( (LONG*)&m_cRef ) ;
  305.  
  306.         return m_cRef ;
  307.     }
  308.  
  309.     ////////////////////////////////////////////////////////////////////////
  310.     //
  311.     //    Release()
  312.     //
  313.     //    non-delegating Release
  314.     //
  315.     ////
  316.     ULONG __stdcall Release(void)
  317.     {
  318.         if (!InterlockedDecrement( (LONG*)&m_cRef ))
  319.         {
  320.             delete this ;
  321.             return 0 ;
  322.         }
  323.             
  324.         return m_cRef ;
  325.     }
  326.  
  327.     // PRIVATE -------------------------------------------------------------
  328.  
  329.     private :
  330.  
  331.     ULONG        m_cRef ;        // ref count
  332.     IUnknown    *m_pUnkOuter ;        // controlling unknown
  333. } ;
  334.  
  335. // CLASS FACTORY --------------------------------------------------------------
  336.  
  337. ////////////////////////////////////////////////////////////////////////////////
  338. //
  339. //    CNatComCF
  340. //
  341. //    class factory for CNatCom
  342. //
  343. ////
  344. class CNatComCF : public IClassFactory
  345. {
  346.     public :
  347.  
  348.     ////////////////////////////////////////////////////////////////////////
  349.     //
  350.     //    CNatComCF()
  351.     //
  352.     //    constructor
  353.     //
  354.     ////
  355.     CNatComCF()
  356.     {
  357.         m_cRef = 0 ;
  358.     }
  359.  
  360.     ////////////////////////////////////////////////////////////////////////
  361.     //
  362.     //    CreateInstance()
  363.     //
  364.     //    IClassFactory CreateInstance() method implementation
  365.     //
  366.     ////
  367.     HRESULT __stdcall CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  368.     {
  369.         CNatCom *cmg ;
  370.         HRESULT hr ;
  371.  
  372.         *ppv = NULL ;
  373.  
  374.         if ((punkOuter) && (riid != IID_IUnknown))
  375.         {
  376.             return CLASS_E_NOAGGREGATION ;
  377.         }
  378.  
  379.         cmg = new CNatCom(punkOuter) ;
  380.  
  381.         hr = cmg->QueryInterface(riid, ppv) ;
  382.  
  383.         if (FAILED(hr))
  384.         {
  385.             delete cmg ;
  386.             return hr ;
  387.         }
  388.  
  389.         return S_OK ;
  390.     }
  391.  
  392.     ////////////////////////////////////////////////////////////////////////
  393.     //
  394.     //    QueryInterface()
  395.     //
  396.     //    IUnknown QueryInterface() method implementation
  397.     //
  398.     ////
  399.     HRESULT __stdcall QueryInterface(REFIID iid, void **ppv)
  400.     {
  401.         *ppv = NULL ;
  402.  
  403.         if (iid == IID_IUnknown || iid == IID_IClassFactory)
  404.             *ppv = this ;
  405.         else
  406.             return E_NOINTERFACE ;
  407.  
  408.         AddRef() ;
  409.  
  410.         return S_OK ;
  411.     }
  412.  
  413.     ////////////////////////////////////////////////////////////////////////
  414.     //
  415.     //    AddRef()
  416.     //
  417.     //    IUnknown AddRef() method implementation
  418.     //
  419.     ////
  420.     ULONG __stdcall AddRef(void)
  421.     {
  422.         return ++m_cRef ;
  423.     }
  424.  
  425.     ////////////////////////////////////////////////////////////////////////
  426.     //
  427.     //    Release()
  428.     //
  429.     //    IUnknown Release() method implementation
  430.     //
  431.     ////
  432.     ULONG __stdcall Release(void)
  433.     {
  434.         if (--m_cRef == 0)
  435.         {
  436.             delete this ;
  437.             return 0 ;
  438.         }
  439.         
  440.         return m_cRef ;
  441.     }
  442.  
  443.     ////////////////////////////////////////////////////////////////////////
  444.     //
  445.     //    LockServer()
  446.     //
  447.     //    IClassFactory LockServer() method implementation
  448.     //
  449.     ////
  450.     HRESULT __stdcall LockServer(BOOL bLock)
  451.     {
  452.         bLock ? ObjectCreated() : ObjectDestroyed() ;
  453.  
  454.         return S_OK ;
  455.     }
  456.  
  457.  
  458.     // PRIVATE -------------------------------------------------------------
  459.  
  460.     private :
  461.  
  462.     ULONG    m_cRef ;        // refcount
  463. } ;
  464.  
  465. ////////////////////////////////////////////////////////////////////////////////
  466. //
  467. //    DllMain()
  468. //
  469. //    entry point
  470. //
  471. ////
  472. BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
  473. {
  474.     switch (fdwReason)
  475.     {
  476.       case DLL_PROCESS_ATTACH :
  477.         g_hDllMain = hDLLInst ;
  478.     }
  479.  
  480.     return TRUE ;
  481. }
  482.  
  483. // -----------------------------------------------------------------------------
  484.  
  485. TCHAR achSampleDesc[]        = "CNatCom";
  486. TCHAR achInprocServer32[]    = "InprocServer32";
  487. TCHAR achSampleProgID[]     = "CNatCom";
  488. TCHAR achProgID[]        = "CNatCom";
  489. TCHAR achThreadingModel[]    = "ThreadingModel";
  490. TCHAR achFree[]         = "Both";
  491.  
  492. #define GUIDSTR_MAX    (1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
  493. static const CHAR szDigits[]    = "0123456789ABCDEF";
  494. static const BYTE GuidMap[]    = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
  495.                     8, 9, '-', 10, 11, 12, 13, 14, 15 };
  496.  
  497. ////////////////////////////////////////////////////////////////////////////////
  498. //
  499. //    GUID2StringA()
  500. //
  501. //    converts GUID to string form
  502. //
  503. ////
  504. VOID GUID2StringA(REFGUID rguid, LPSTR lpsz)
  505. {
  506.     int    i;
  507.     LPSTR    p = lpsz;
  508.  
  509.     const BYTE * pBytes = (const BYTE *) &rguid;
  510.  
  511.     *p++ = '{';
  512.  
  513.     for (i = 0; i < sizeof(GuidMap); i++)
  514.     {
  515.         if (GuidMap[i] == '-')
  516.         {
  517.             *p++ = '-';
  518.         }
  519.         else
  520.         {
  521.             *p++ = szDigits[ (pBytes[GuidMap[i]] & 0xF0) >> 4 ];
  522.             *p++ = szDigits[ (pBytes[GuidMap[i]] & 0x0F) ];
  523.         }
  524.     }
  525.  
  526.     *p++ = '}';
  527.     *p   = '\0';
  528. }
  529.  
  530. ////////////////////////////////////////////////////////////////////////////////
  531. //
  532. //    NTCompatibleRegDeleteKey()
  533. //
  534. //    checks that registry key does not have any subkeys prior to deletion
  535. //
  536. ////
  537. LONG NTCompatibleRegDeleteKey(HKEY hKey, LPCTSTR szSubKey)
  538. {
  539.     TCHAR achName[MAX_PATH+1];
  540.     HKEY  hSubkey;
  541.  
  542.     if (ERROR_SUCCESS != RegOpenKey(hKey, szSubKey, &hSubkey))
  543.         return REGDB_E_INVALIDVALUE;
  544.  
  545.     if (ERROR_SUCCESS == RegEnumKey(hSubkey, 0, achName, sizeof(achName)/sizeof(TCHAR)))
  546.     {
  547.         RegCloseKey(hSubkey);
  548.         // There's still one subkey: fail the call.
  549.         return REGDB_E_INVALIDVALUE;
  550.     }
  551.  
  552.     RegCloseKey(hSubkey);
  553.     return RegDeleteKey(hKey, szSubKey);
  554. }
  555.  
  556. ////////////////////////////////////////////////////////////////////////////////
  557. //
  558. //    DllRegisterServer()
  559. //
  560. //    registers this COM server via the registry.
  561. //
  562. ////
  563. STDAPI DllRegisterServer(VOID)
  564. {
  565.     HKEY    hKey  = NULL;
  566.     HKEY    hKey2  = NULL;
  567.     HKEY    hKey3  = NULL;
  568.     DWORD    result;
  569.     HRESULT hr = SELFREG_E_CLASS;
  570.     CHAR    achCLSID[GUIDSTR_MAX];
  571.     CHAR    achLIBID[GUIDSTR_MAX] ;
  572.     TCHAR    achModulePathName[MAX_PATH];
  573.     TCHAR    achCurrentDirectory[MAX_PATH] ;
  574.  
  575.     // CLSID
  576.  
  577.     GUID2StringA(CLSID_CNatCom, achCLSID) ;
  578.  
  579.     // If we fail in the middle, the state of the registry entries
  580.     // is indeterminate (as per Ole specs.)
  581.  
  582.     // Create HKEY_CLASSES_ROOT\progid\CLSID
  583.     result = RegCreateKey(HKEY_CLASSES_ROOT, achSampleProgID, &hKey);
  584.     if (result != ERROR_SUCCESS) goto lExit;
  585.  
  586.     result = RegSetValue(hKey, NULL, REG_SZ, achSampleDesc, lstrlen(achSampleDesc));
  587.     if (result != ERROR_SUCCESS) goto lExit;
  588.  
  589.     result = RegCreateKey(hKey, TEXT("CLSID"), &hKey2);
  590.     if (result != ERROR_SUCCESS) goto lExit;
  591.  
  592.     result = RegSetValue(hKey2, NULL, REG_SZ, achCLSID, GUIDSTR_MAX-1);
  593.     if (result != ERROR_SUCCESS) goto lExit;
  594.  
  595.     RegCloseKey(hKey);
  596.     RegCloseKey(hKey2);
  597.     hKey = NULL;
  598.     hKey2 = NULL;
  599.  
  600.     // Create HKEY_CLASSES_ROOT\CLSID\...
  601.  
  602.     // create CLSID key
  603.     result = RegCreateKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hKey);
  604.     if (result != ERROR_SUCCESS) goto lExit ;
  605.  
  606.     // create CLSID/GUID key
  607.     result = RegCreateKey(hKey, achCLSID, &hKey2);
  608.     if (result != ERROR_SUCCESS) goto lExit ;
  609.  
  610.     // put in sample description value into CLSID\GUID key
  611.     result = RegSetValue(hKey2, NULL, REG_SZ, achSampleDesc, lstrlen(achSampleDesc));
  612.     if (result != ERROR_SUCCESS) goto lExit ;
  613.  
  614.     // get our path ..
  615.     result = GetModuleFileName(g_hDllMain, achModulePathName, sizeof(achModulePathName)/sizeof(TCHAR));
  616.     if (result == 0) goto lExit ;
  617.  
  618.     // create subkey under CLSID\GUID
  619.     result = RegCreateKey(hKey2, achInprocServer32, &hKey3);
  620.     if (result != ERROR_SUCCESS) goto lExit ;
  621.  
  622.     // set key value to the path obtained above
  623.     result = RegSetValue(hKey3, NULL, REG_SZ, achModulePathName, lstrlen(achModulePathName));
  624.     if (result != ERROR_SUCCESS) goto lExit ;
  625.  
  626.     // both
  627.     result = RegSetValueEx(hKey3, achThreadingModel, 0, REG_SZ, (BYTE*)achFree, sizeof(achFree));
  628.     if (result != ERROR_SUCCESS) goto lExit;
  629.  
  630.     RegCloseKey(hKey3);
  631.     hKey3 = NULL;
  632.  
  633.     // PROGID
  634.  
  635.     result = RegCreateKey(hKey2, achProgID, &hKey3);
  636.     if (result != ERROR_SUCCESS) goto lExit;
  637.  
  638.     result = RegSetValue(hKey3, NULL, REG_SZ, achSampleProgID, lstrlen(achSampleProgID));
  639.     if (result != ERROR_SUCCESS) goto lExit;
  640.  
  641.     RegCloseKey(hKey3);
  642.     hKey3 = NULL;
  643.  
  644.  
  645.     hr = S_OK ;
  646.  
  647.  lExit :
  648.  
  649.     // close up
  650.     if (hKey) RegCloseKey(hKey);
  651.     if (hKey2) RegCloseKey(hKey2);
  652.     if (hKey3) RegCloseKey(hKey3);
  653.  
  654.     return hr ;
  655. }
  656.  
  657. ////////////////////////////////////////////////////////////////////////////////
  658. //
  659. //    DllUnregisterServer()
  660. //
  661. //    removes our registry entries (entered via DllRegisterServer())
  662. //
  663. ////
  664. STDAPI DllUnregisterServer(VOID)
  665. {
  666.     HKEY    hKey  = NULL;
  667.     HKEY    hKey2 = NULL;
  668.     DWORD    result;
  669.     HRESULT hr = SELFREG_E_CLASS;
  670.     CHAR    achCLSID[GUIDSTR_MAX];
  671.     CHAR    achLIBID[GUIDSTR_MAX];
  672.  
  673.     // If we fail in the middle, the state of the registry entries
  674.     // is indeterminate (as per Ole specs.)
  675.     GUID2StringA(CLSID_CNatCom, achCLSID);
  676.  
  677.     result = RegOpenKey(HKEY_CLASSES_ROOT, achSampleProgID, &hKey);
  678.     if (result == ERROR_SUCCESS)
  679.     {
  680.         NTCompatibleRegDeleteKey(hKey, TEXT("CLSID"));
  681.         RegCloseKey(hKey);
  682.         hKey = NULL;
  683.         NTCompatibleRegDeleteKey(HKEY_CLASSES_ROOT, achSampleProgID);
  684.     }
  685.  
  686.     result = RegOpenKey(HKEY_CLASSES_ROOT, TEXT("CLSID"), &hKey);
  687.     result = RegOpenKey(hKey, achCLSID, &hKey2);
  688.  
  689.     if (result == ERROR_SUCCESS)
  690.     {
  691.         NTCompatibleRegDeleteKey(hKey2, achInprocServer32);
  692.         NTCompatibleRegDeleteKey(hKey2, achProgID);
  693.         RegCloseKey(hKey2);
  694.         hKey2 = NULL;
  695.         NTCompatibleRegDeleteKey(hKey, achCLSID);
  696.     }
  697.  
  698.     // If this fails, it means somebody else added a subkey to this tree.
  699.     // We're not allowed to touch it so ignore the failure.
  700.  
  701.     RegCloseKey(hKey);
  702.     hKey = NULL;
  703.  
  704.     hr = S_OK;
  705.  
  706.     return hr;
  707. }
  708.  
  709.  
  710. ////////////////////////////////////////////////////////////////////////////////
  711. //
  712. //    DllGetClassObject()
  713. //
  714. //    COM entry point
  715. //
  716. ////
  717. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, VOID **ppv)
  718. {
  719.     HRESULT         hr ;
  720.     class CNatComCF *    pcf;
  721.  
  722.     *ppv = NULL ;
  723.  
  724.     if (rclsid != CLSID_CNatCom)
  725.     {
  726.         return CLASS_E_CLASSNOTAVAILABLE;
  727.     }
  728.  
  729.     pcf = new CNatComCF() ;
  730.  
  731.     if (!pcf)
  732.     {
  733.         return CLASS_E_CLASSNOTAVAILABLE;
  734.     }
  735.  
  736.     hr = pcf->QueryInterface(riid, ppv) ;
  737.  
  738.     if (FAILED(hr))
  739.     {
  740.         delete pcf ;
  741.         return hr ;
  742.     }
  743.  
  744.     return S_OK ;
  745. }
  746.  
  747. ////////////////////////////////////////////////////////////////////////////////
  748. //
  749. //    DllCanUnloadNow()
  750. //
  751. //    returns refcount of objects which are using this .dll
  752. //
  753. ////
  754. STDAPI DllCanUnloadNow()
  755. {
  756.     return g_cObject ;
  757. }
  758.