home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 14 / IOPROG_14.ISO / soft / sdkjava / sdkjava.exe / SDKJava.cab / Samples / native_com / com / natcom.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-05  |  15.7 KB  |  757 lines

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