595 lines
16 KiB
C++
595 lines
16 KiB
C++
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
// CWMIExtension.cpp : Implementation of the CWMIExtension class
|
||
|
|
||
|
#include "precomp.h"
|
||
|
extern ULONG g_ulObjCount;
|
||
|
//#include "wmiextension_i.c"
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
/* Constructor */
|
||
|
CWMIExtension::CWMIExtension()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ITypeLib *pITypeLib;
|
||
|
|
||
|
m_cRef = 0;
|
||
|
m_pUnkOuter = NULL;
|
||
|
m_pDispOuter = NULL;
|
||
|
m_pInner = NULL;
|
||
|
m_pSWMILocator = NULL;
|
||
|
m_bstrADsName = NULL;
|
||
|
m_pSWMIServices = NULL;
|
||
|
m_pSWMIObject = NULL;
|
||
|
m_pTypeInfo = NULL;
|
||
|
|
||
|
//Create inner object for controlling IUnknown implementation
|
||
|
m_pInner = new CInner(this);
|
||
|
|
||
|
if (m_pInner == NULL)
|
||
|
return;
|
||
|
|
||
|
|
||
|
hr = LoadRegTypeLib(LIBID_WMIEXTENSIONLib, 1,0,
|
||
|
PRIMARYLANGID(GetSystemDefaultLCID()), &pITypeLib);
|
||
|
if FAILED(hr)
|
||
|
return;
|
||
|
|
||
|
hr = pITypeLib->GetTypeInfoOfGuid(IID_IWMIExtension, &m_pTypeInfo);
|
||
|
pITypeLib->Release();
|
||
|
|
||
|
g_ulObjCount++; //global count for objects living in this DLL
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
CWMIExtension::~CWMIExtension()
|
||
|
{
|
||
|
if (m_pUnkOuter)
|
||
|
m_pUnkOuter = NULL;
|
||
|
|
||
|
if (m_pDispOuter)
|
||
|
m_pDispOuter = NULL;
|
||
|
|
||
|
if (m_pInner)
|
||
|
{
|
||
|
delete m_pInner;
|
||
|
m_pInner = NULL;
|
||
|
};
|
||
|
|
||
|
if (m_bstrADsName)
|
||
|
SysFreeString(m_bstrADsName);
|
||
|
|
||
|
if (m_pSWMIObject)
|
||
|
{
|
||
|
m_pSWMIObject->Release();
|
||
|
m_pSWMIObject = NULL;
|
||
|
};
|
||
|
|
||
|
if (m_pSWMIServices)
|
||
|
{
|
||
|
m_pSWMIServices->Release();
|
||
|
m_pSWMIServices = NULL;
|
||
|
};
|
||
|
|
||
|
if (m_pSWMILocator)
|
||
|
{
|
||
|
m_pSWMILocator->Release();
|
||
|
m_pSWMILocator = NULL;
|
||
|
};
|
||
|
|
||
|
if (m_pTypeInfo)
|
||
|
{
|
||
|
m_pTypeInfo->Release();
|
||
|
m_pTypeInfo = NULL;
|
||
|
};
|
||
|
|
||
|
g_ulObjCount--; //global count for objects living in this DLL
|
||
|
};
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CWMIExtension::CreateExtension(IUnknown *pUnkOuter, void **ppv)
|
||
|
{
|
||
|
CWMIExtension FAR* pObj = NULL;
|
||
|
HRESULT hr;
|
||
|
IADs *pADs = NULL;
|
||
|
BSTR bstrTempADSName = NULL;
|
||
|
|
||
|
pObj = new CWMIExtension();
|
||
|
if (pObj == NULL)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
//No addref needed for outer unknown
|
||
|
pObj->m_pUnkOuter = pUnkOuter;
|
||
|
|
||
|
/*
|
||
|
//Due to the fact that ADSI instantiate us for every object, regardless of whether we're actually being used or not,
|
||
|
//I am moving the code to obtain a locator pointer to the actual functions that need to use it...
|
||
|
//Obtain a WMI Locator and store in member variable
|
||
|
hr = CoCreateInstance(CLSID_SWbemLocator, NULL, CLSCTX_INPROC_SERVER,
|
||
|
IID_ISWbemLocator, (void **)&pObj->m_pSWMILocator);
|
||
|
if FAILED(hr)
|
||
|
{
|
||
|
delete pObj;
|
||
|
return hr;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
//Due to a bug in the locator security object, we cannot set the security settings here,
|
||
|
//but rather need to move this to the services pointer.
|
||
|
|
||
|
//Setup the impersonation and authentication levels for this locator
|
||
|
ISWbemSecurity *pSecurity = NULL;
|
||
|
hr = pObj->m_pSWMILocator->get_Security_(&pSecurity);
|
||
|
if FAILED(hr)
|
||
|
{
|
||
|
delete pObj;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pSecurity->put_ImpersonationLevel(wbemImpersonationLevelImpersonate);
|
||
|
hr = pSecurity->put_AuthenticationLevel(wbemAuthenticationLevelConnect);
|
||
|
hr = pSecurity->Release();
|
||
|
if FAILED(hr)
|
||
|
{
|
||
|
delete pObj;
|
||
|
return hr;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
//Obtain the name of this object from ADSI and store in member :
|
||
|
|
||
|
/* Moved to get_WMIObjectPath since here it doesn't work...
|
||
|
//Get a pointer to the IADs interface of the outer object
|
||
|
hr = pObj->m_pUnkOuter->QueryInterface(IID_IADs, (void **) &pADs );
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
//Get the name of the outer object
|
||
|
// hr = pADs->get_Name(&bstrTempADSName);
|
||
|
VARIANT var;
|
||
|
VariantInit(&var);
|
||
|
hr = pADs->Get(L"cn", &var);
|
||
|
pObj->m_bstrADsName = SysAllocString(var.bstrVal);
|
||
|
VariantClear(&var);
|
||
|
pADs->Release();
|
||
|
*/
|
||
|
|
||
|
//Since ADSI is adding a "CN=" prefix to the actual machine name, we need to remove it
|
||
|
// pObj->m_bstrADsName = SysAllocString(wcschr(bstrTempADSName, L'=')+1);
|
||
|
// pObj->m_bstrADsName = SysAllocString(bstrTempADSName);
|
||
|
// SysFreeString(bstrTempADSName);
|
||
|
|
||
|
// if FAILED(hr)
|
||
|
// return hr;
|
||
|
|
||
|
//Return the controlling unknown implementation pointer, and addref as required
|
||
|
hr = pObj->m_pInner->QueryInterface(IID_IUnknown, ppv);
|
||
|
|
||
|
return hr;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* IUnknown Methods */
|
||
|
STDMETHODIMP CWMIExtension::QueryInterface(REFIID riid, LPVOID FAR *ppv)
|
||
|
{
|
||
|
return m_pUnkOuter->QueryInterface(riid, ppv);
|
||
|
};
|
||
|
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
CWMIExtension::AddRef(void)
|
||
|
{
|
||
|
++m_cRef;
|
||
|
return m_pUnkOuter->AddRef();
|
||
|
};
|
||
|
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
CWMIExtension::Release(void)
|
||
|
{
|
||
|
--m_cRef;
|
||
|
return m_pUnkOuter->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
/* IDispatch methods */
|
||
|
//IDispatch implementation delegates to the aggregator in this case
|
||
|
STDMETHODIMP CWMIExtension::GetTypeInfoCount(unsigned int FAR* pctinfo)
|
||
|
{
|
||
|
IDispatch *pDisp;
|
||
|
HRESULT hr;
|
||
|
hr = m_pUnkOuter->QueryInterface(IID_IDispatch, (void **) &pDisp);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
hr = pDisp->GetTypeInfoCount(pctinfo);
|
||
|
pDisp->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CWMIExtension::GetTypeInfo(unsigned int itinfo, LCID lcid,
|
||
|
ITypeInfo FAR* FAR* pptinfo)
|
||
|
{
|
||
|
IDispatch *pDisp;
|
||
|
HRESULT hr;
|
||
|
hr = m_pUnkOuter->QueryInterface(IID_IDispatch, (void **) &pDisp);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
hr = pDisp->GetTypeInfo(itinfo, lcid, pptinfo);
|
||
|
pDisp->Release();
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CWMIExtension::GetIDsOfNames(REFIID iid, LPWSTR FAR* rgszNames,
|
||
|
unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
|
||
|
{
|
||
|
IDispatch *pDisp;
|
||
|
HRESULT hr;
|
||
|
hr = m_pUnkOuter->QueryInterface(IID_IDispatch, (void **) &pDisp);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
hr = pDisp->GetIDsOfNames(iid, rgszNames, cNames, lcid, rgdispid);
|
||
|
pDisp->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CWMIExtension::Invoke(DISPID dispidMember, REFIID iid, LCID lcid,
|
||
|
unsigned short wFlags, DISPPARAMS FAR* pdispparams,
|
||
|
VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo,
|
||
|
unsigned int FAR* puArgErr)
|
||
|
{
|
||
|
IDispatch *pDisp;
|
||
|
HRESULT hr;
|
||
|
hr = m_pUnkOuter->QueryInterface(IID_IDispatch, (void **) &pDisp);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
hr = pDisp->Invoke(dispidMember,
|
||
|
iid,
|
||
|
lcid,
|
||
|
wFlags,
|
||
|
pdispparams,
|
||
|
pvarResult,
|
||
|
pexcepinfo,
|
||
|
puArgErr
|
||
|
);
|
||
|
pDisp->Release();
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/* IAdsExtension methods */
|
||
|
STDMETHODIMP CWMIExtension::Operate(ULONG dwCode, VARIANT varData1,
|
||
|
VARIANT varData2, VARIANT varData3)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
switch (dwCode)
|
||
|
{
|
||
|
|
||
|
case ADS_EXT_INITCREDENTIALS:
|
||
|
// For debugging purpose you can prompt a dialog box
|
||
|
// MessageBox(NULL, "INITCRED", "ADsExt", MB_OK);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
hr = E_FAIL;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CWMIExtension::PrivateGetIDsOfNames(REFIID riid, OLECHAR ** rgszNames,
|
||
|
unsigned int cNames, LCID lcid, DISPID * rgdispid)
|
||
|
{
|
||
|
|
||
|
if (rgdispid == NULL)
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
return DispGetIDsOfNames(m_pTypeInfo, rgszNames, cNames, rgdispid);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
STDMETHODIMP CWMIExtension::PrivateInvoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
|
||
|
DISPPARAMS * pdispparams, VARIANT * pvarResult,
|
||
|
EXCEPINFO * pexcepinfo, UINT * puArgErr)
|
||
|
{
|
||
|
return DispInvoke( (IWMIExtension*)this,
|
||
|
m_pTypeInfo,
|
||
|
dispidMember,
|
||
|
wFlags,
|
||
|
pdispparams,
|
||
|
pvarResult,
|
||
|
pexcepinfo,
|
||
|
puArgErr );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* IWMIExtension methods */
|
||
|
STDMETHODIMP CWMIExtension::get_WMIObjectPath(BSTR FAR *strWMIObjectPath)
|
||
|
{
|
||
|
WCHAR wcSWMIName[1024];
|
||
|
HRESULT hr;
|
||
|
|
||
|
//Validate parameter
|
||
|
if (strWMIObjectPath == NULL)
|
||
|
return wbemErrInvalidParameter; //scripting enum
|
||
|
|
||
|
// Moved from CreateExtension() since it doesn't work there...
|
||
|
if (!m_bstrADsName)
|
||
|
{
|
||
|
IADs *pADs = NULL;
|
||
|
BSTR bstrTempADSName = NULL;
|
||
|
hr = m_pUnkOuter->QueryInterface(IID_IADs, (void **) &pADs );
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
//Get the name of the outer object
|
||
|
hr = pADs->get_Name(&bstrTempADSName);
|
||
|
if FAILED(hr)
|
||
|
{
|
||
|
pADs->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//Since ADSI is adding a "CN=" prefix to the actual machine name, we need to remove it
|
||
|
m_bstrADsName = SysAllocString(wcschr(bstrTempADSName, L'=')+1);
|
||
|
SysFreeString(bstrTempADSName);
|
||
|
pADs->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
//Construct the path for matching (S)WMI object
|
||
|
wcscpy(wcSWMIName, L"WINMGMTS:{impersonationLevel=impersonate}!//");
|
||
|
wcscat(wcSWMIName, m_bstrADsName);
|
||
|
wcscat(wcSWMIName, L"/root/cimv2:Win32_ComputerSystem.Name=\"");
|
||
|
wcscat(wcSWMIName, m_bstrADsName);
|
||
|
wcscat(wcSWMIName, L"\"");
|
||
|
|
||
|
//Allocate out parameter and copy result to it
|
||
|
*strWMIObjectPath = SysAllocString(wcSWMIName);
|
||
|
|
||
|
return NOERROR;
|
||
|
|
||
|
}; //get_WMIObjectPath
|
||
|
|
||
|
|
||
|
|
||
|
STDMETHODIMP CWMIExtension::GetWMIObject(ISWbemObject FAR* FAR* objWMIObject)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
BSTR bstrObjPath;
|
||
|
|
||
|
//Validate parameter
|
||
|
if (objWMIObject == NULL)
|
||
|
return wbemErrInvalidParameter;
|
||
|
|
||
|
// Moved from CreateExtension() since it doesn't work there...
|
||
|
//Obtain the name of this object from ADSI and store in member, if not already there
|
||
|
if (!m_bstrADsName)
|
||
|
{
|
||
|
IADs *pADs = NULL;
|
||
|
BSTR bstrTempADSName = NULL;
|
||
|
hr = m_pUnkOuter->QueryInterface(IID_IADs, (void **) &pADs );
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
//Get the name of the outer object
|
||
|
hr = pADs->get_Name(&bstrTempADSName);
|
||
|
if FAILED(hr)
|
||
|
{
|
||
|
pADs->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//Since ADSI is adding a "CN=" prefix to the actual machine name, we need to remove it
|
||
|
m_bstrADsName = SysAllocString(wcschr(bstrTempADSName, L'=')+1);
|
||
|
SysFreeString(bstrTempADSName);
|
||
|
pADs->Release();
|
||
|
}
|
||
|
|
||
|
//Obtain a WMI Locator and store in member variable, if not already there
|
||
|
if (!m_pSWMILocator)
|
||
|
{
|
||
|
hr = CoCreateInstance(CLSID_SWbemLocator, NULL, CLSCTX_INPROC_SERVER,
|
||
|
IID_ISWbemLocator, (void **)&m_pSWMILocator);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//Get the respective SWMI services pointer if we don't have it already, and cache in member
|
||
|
if (!m_pSWMIServices)
|
||
|
{
|
||
|
BSTR bstrNamespace = SysAllocString(L"root\\cimv2");
|
||
|
hr = m_pSWMILocator->ConnectServer(m_bstrADsName, bstrNamespace, NULL, NULL, 0, NULL, 0, NULL, &m_pSWMIServices);
|
||
|
SysFreeString(bstrNamespace);
|
||
|
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
//Setup the impersonation and authentication levels for this services pointer
|
||
|
ISWbemSecurity *pSecurity = NULL;
|
||
|
hr = m_pSWMIServices->get_Security_(&pSecurity);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
hr = pSecurity->put_ImpersonationLevel(wbemImpersonationLevelImpersonate);
|
||
|
hr = pSecurity->put_AuthenticationLevel(wbemAuthenticationLevelConnect);
|
||
|
hr = pSecurity->Release();
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
//Get the SWMI object using this services pointer, if we don't have it already, and cache in member
|
||
|
if (!m_pSWMIObject)
|
||
|
{
|
||
|
WCHAR wcObjPath[256];
|
||
|
|
||
|
//Construct the path of the object
|
||
|
wcscpy(wcObjPath, L"Win32_ComputerSystem.Name=\"");
|
||
|
wcscat(wcObjPath, m_bstrADsName);
|
||
|
wcscat(wcObjPath, L"\"");
|
||
|
|
||
|
bstrObjPath = SysAllocString(wcObjPath);
|
||
|
hr = m_pSWMIServices->Get(bstrObjPath, 0, NULL, &m_pSWMIObject);
|
||
|
SysFreeString(bstrObjPath);
|
||
|
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
};
|
||
|
|
||
|
//AddRef the object pointer before we hand it out...
|
||
|
m_pSWMIObject->AddRef();
|
||
|
*objWMIObject = m_pSWMIObject;
|
||
|
|
||
|
return NOERROR;
|
||
|
|
||
|
}; //GetWMIObject
|
||
|
|
||
|
|
||
|
STDMETHODIMP CWMIExtension::GetWMIServices(ISWbemServices FAR* FAR* objWMIServices)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
//Validate parameter
|
||
|
if (objWMIServices == NULL)
|
||
|
return wbemErrInvalidParameter;
|
||
|
|
||
|
// Moved from CreateExtension() since it doesn't work there...
|
||
|
//Obtain the name of this object from ADSI and store in member, if not already there
|
||
|
if (!m_bstrADsName)
|
||
|
{
|
||
|
IADs *pADs = NULL;
|
||
|
BSTR bstrTempADSName = NULL;
|
||
|
hr = m_pUnkOuter->QueryInterface(IID_IADs, (void **) &pADs );
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
//Get the name of the outer object
|
||
|
hr = pADs->get_Name(&bstrTempADSName);
|
||
|
if FAILED(hr)
|
||
|
{
|
||
|
pADs->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//Since ADSI is adding a "CN=" prefix to the actual machine name, we need to remove it
|
||
|
m_bstrADsName = SysAllocString(wcschr(bstrTempADSName, L'=')+1);
|
||
|
SysFreeString(bstrTempADSName);
|
||
|
pADs->Release();
|
||
|
}
|
||
|
|
||
|
//Obtain a WMI Locator and store in member variable, if not already there
|
||
|
if (!m_pSWMILocator)
|
||
|
{
|
||
|
hr = CoCreateInstance(CLSID_SWbemLocator, NULL, CLSCTX_INPROC_SERVER,
|
||
|
IID_ISWbemLocator, (void **)&m_pSWMILocator);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//Get the respective SWMI services pointer if we don't have it already, and cache in member
|
||
|
if (!m_pSWMIServices)
|
||
|
{
|
||
|
BSTR bstrNamespace = SysAllocString(L"root\\cimv2");
|
||
|
hr = m_pSWMILocator->ConnectServer(m_bstrADsName, bstrNamespace, NULL, NULL, 0, NULL, 0, NULL, &m_pSWMIServices);
|
||
|
SysFreeString(bstrNamespace);
|
||
|
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
//Setup the impersonation and authentication levels for this services pointer
|
||
|
ISWbemSecurity *pSecurity = NULL;
|
||
|
hr = m_pSWMIServices->get_Security_(&pSecurity);
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
hr = pSecurity->put_ImpersonationLevel(wbemImpersonationLevelImpersonate);
|
||
|
hr = pSecurity->put_AuthenticationLevel(wbemAuthenticationLevelConnect);
|
||
|
hr = pSecurity->Release();
|
||
|
if FAILED(hr)
|
||
|
return hr;
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
//AddRef the services pointer before we hand it out
|
||
|
m_pSWMIServices->AddRef();
|
||
|
*objWMIServices = m_pSWMIServices;
|
||
|
|
||
|
return NOERROR;
|
||
|
|
||
|
}; //GetWMIServices
|
||
|
|
||
|
|
||
|
/* Implementation of CInner class which implements the controlling IUnknown for the object */
|
||
|
//Constructor
|
||
|
CInner::CInner(CWMIExtension *pOwner)
|
||
|
{
|
||
|
m_cRef = 0;
|
||
|
m_pOwner = pOwner;
|
||
|
};
|
||
|
|
||
|
//Destructor
|
||
|
CInner::~CInner()
|
||
|
{
|
||
|
};
|
||
|
|
||
|
|
||
|
STDMETHODIMP CInner::QueryInterface(REFIID riid, LPVOID FAR *ppv)
|
||
|
{
|
||
|
if (riid == IID_IUnknown)
|
||
|
*ppv=(IUnknown *)this;
|
||
|
else if (riid == IID_IDispatch)
|
||
|
*ppv=(IDispatch *)m_pOwner;
|
||
|
else if (riid == IID_IWMIExtension)
|
||
|
*ppv=(IWMIExtension *)m_pOwner;
|
||
|
else if (riid == IID_IADsExtension)
|
||
|
*ppv=(IADsExtension *)m_pOwner;
|
||
|
else
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
((IUnknown *)*ppv)->AddRef();
|
||
|
return NOERROR;
|
||
|
};
|
||
|
|
||
|
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
CInner::AddRef(void)
|
||
|
{
|
||
|
return ++m_cRef;
|
||
|
};
|
||
|
|
||
|
|
||
|
STDMETHODIMP_(ULONG)
|
||
|
CInner::Release(void)
|
||
|
{
|
||
|
if (--m_cRef != 0)
|
||
|
return m_cRef;
|
||
|
|
||
|
delete m_pOwner;
|
||
|
return 0;
|
||
|
};
|
||
|
|
||
|
|
||
|
// eof CWMIExtension.cpp
|