605 lines
16 KiB
C++
605 lines
16 KiB
C++
//***************************************************************************
|
|
//
|
|
// Copyright (c) 1998-2000 Microsoft Corporation
|
|
//
|
|
// LOCATOR.CPP
|
|
//
|
|
// alanbos 15-Aug-96 Created.
|
|
//
|
|
// Defines the implementation of ISWbemLocator
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
#include "objsink.h"
|
|
|
|
#define WBEMS_DEFAULT_SERVER L"."
|
|
|
|
extern CRITICAL_SECTION g_csErrorCache;
|
|
wchar_t *CSWbemLocator::s_pDefaultNamespace = NULL;
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CSWbemLocator::CSWbemLocator
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CSWbemLocator::CSWbemLocator(CSWbemPrivilegeSet *pPrivilegeSet) :
|
|
m_pUnsecuredApartment (NULL),
|
|
m_pIServiceProvider (NULL),
|
|
m_cRef (0)
|
|
{
|
|
// Initialize the underlying locators
|
|
HRESULT result = CoCreateInstance(CLSID_WbemLocator, 0,
|
|
CLSCTX_INPROC_SERVER, IID_IWbemLocator,
|
|
(LPVOID *) &m_pIWbemLocator);
|
|
|
|
EnsureGlobalsInitialized () ;
|
|
|
|
m_Dispatch.SetObj((ISWbemLocator *)this, IID_ISWbemLocator,
|
|
CLSID_SWbemLocator, L"SWbemLocator");
|
|
|
|
m_SecurityInfo = new CWbemLocatorSecurity (pPrivilegeSet);
|
|
|
|
if (m_SecurityInfo)
|
|
{
|
|
// Set the impersonation level by default in the locator - note
|
|
// that this must be done after EnsureGlobalsInitialized is called
|
|
m_SecurityInfo->put_ImpersonationLevel (CSWbemSecurity::GetDefaultImpersonationLevel ());
|
|
}
|
|
|
|
InterlockedIncrement(&g_cObj);
|
|
}
|
|
|
|
CSWbemLocator::CSWbemLocator(CSWbemLocator & csWbemLocator) :
|
|
m_pUnsecuredApartment (NULL),
|
|
m_pIServiceProvider (NULL),
|
|
m_cRef (0)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::CSWbemLocator()";)
|
|
// This is a smart COM pointers so no explicit AddRef required
|
|
m_pIWbemLocator = csWbemLocator.m_pIWbemLocator;
|
|
|
|
m_Dispatch.SetObj((ISWbemLocator *)this,IID_ISWbemLocator,
|
|
CLSID_SWbemLocator, L"SWbemLocator");
|
|
m_SecurityInfo = new CWbemLocatorSecurity (csWbemLocator.m_SecurityInfo);
|
|
|
|
InterlockedIncrement(&g_cObj);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CSWbemLocator::~CSWbemLocator
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CSWbemLocator::~CSWbemLocator(void)
|
|
{
|
|
InterlockedDecrement(&g_cObj);
|
|
|
|
RELEASEANDNULL(m_SecurityInfo)
|
|
RELEASEANDNULL(m_pUnsecuredApartment)
|
|
}
|
|
|
|
//***************************************************************************
|
|
// HRESULT CSWbemLocator::QueryInterface
|
|
// long CSWbemLocator::AddRef
|
|
// long CSWbemLocator::Release
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Standard Com IUNKNOWN functions.
|
|
//
|
|
//***************************************************************************
|
|
|
|
STDMETHODIMP CSWbemLocator::QueryInterface (
|
|
|
|
IN REFIID riid,
|
|
OUT LPVOID *ppv
|
|
)
|
|
{
|
|
*ppv=NULL;
|
|
|
|
if (IID_IUnknown==riid)
|
|
*ppv = reinterpret_cast<IUnknown*>(this);
|
|
else if (IID_ISWbemLocator==riid)
|
|
*ppv = (ISWbemLocator *)this;
|
|
else if (IID_IDispatch==riid)
|
|
*ppv = (IDispatch *)((ISWbemLocator *)this);
|
|
else if (IID_IObjectSafety==riid)
|
|
*ppv = (IObjectSafety *)this;
|
|
else if (IID_IDispatchEx==riid)
|
|
*ppv = (IDispatchEx *)this;
|
|
else if (IID_ISupportErrorInfo==riid)
|
|
*ppv = (ISupportErrorInfo *)this;
|
|
else if (IID_IProvideClassInfo==riid)
|
|
*ppv = (IProvideClassInfo *)this;
|
|
|
|
if (NULL!=*ppv)
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CSWbemLocator::AddRef(void)
|
|
{
|
|
InterlockedIncrement(&m_cRef);
|
|
return m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CSWbemLocator::Release(void)
|
|
{
|
|
InterlockedDecrement(&m_cRef);
|
|
if (0L!=m_cRef)
|
|
return m_cRef;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// IDispatch methods should be inline
|
|
|
|
STDMETHODIMP CSWbemLocator::GetTypeInfoCount(UINT* pctinfo)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetTypeInfoCount()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.GetTypeInfoCount(pctinfo);}
|
|
STDMETHODIMP CSWbemLocator::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetTypeInfo()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.GetTypeInfo(itinfo, lcid, pptinfo);}
|
|
STDMETHODIMP CSWbemLocator::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames,
|
|
UINT cNames, LCID lcid, DISPID* rgdispid)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetIdsOfNames()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.GetIDsOfNames(riid, rgszNames, cNames,
|
|
lcid,
|
|
rgdispid);}
|
|
STDMETHODIMP CSWbemLocator::Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
|
|
WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
|
|
EXCEPINFO* pexcepinfo, UINT* puArgErr)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::Invoke()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.Invoke(dispidMember, riid, lcid, wFlags,
|
|
pdispparams, pvarResult, pexcepinfo, puArgErr);}
|
|
|
|
// IDispatchEx methods should be inline
|
|
HRESULT STDMETHODCALLTYPE CSWbemLocator::GetDispID(
|
|
/* [in] */ BSTR bstrName,
|
|
/* [in] */ DWORD grfdex,
|
|
/* [out] */ DISPID __RPC_FAR *pid)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetDispID()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.GetDispID(bstrName, grfdex, pid);
|
|
}
|
|
|
|
/* [local] */ HRESULT STDMETHODCALLTYPE CSWbemLocator::InvokeEx(
|
|
/* [in] */ DISPID id,
|
|
/* [in] */ LCID lcid,
|
|
/* [in] */ WORD wFlags,
|
|
/* [in] */ DISPPARAMS __RPC_FAR *pdp,
|
|
/* [out] */ VARIANT __RPC_FAR *pvarRes,
|
|
/* [out] */ EXCEPINFO __RPC_FAR *pei,
|
|
/* [unique][in] */ IServiceProvider __RPC_FAR *pspCaller)
|
|
{
|
|
HRESULT hr;
|
|
_RD(static char *me = "CSWbemLocator::InvokeEx()";)
|
|
_RPrint(me, "Called", (long)id, "id");
|
|
_RPrint(me, "Called", (long)wFlags, "wFlags");
|
|
|
|
|
|
/*
|
|
* Store away the service provider so that it can be accessed
|
|
* by calls that remote to CIMOM
|
|
*/
|
|
m_pIServiceProvider = pspCaller;
|
|
|
|
hr = m_Dispatch.InvokeEx(id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
|
|
|
|
m_pIServiceProvider = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CSWbemLocator::DeleteMemberByName(
|
|
/* [in] */ BSTR bstr,
|
|
/* [in] */ DWORD grfdex)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::DeleteMemberByName()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.DeleteMemberByName(bstr, grfdex);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CSWbemLocator::DeleteMemberByDispID(
|
|
/* [in] */ DISPID id)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::DeletememberByDispId()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.DeleteMemberByDispID(id);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CSWbemLocator::GetMemberProperties(
|
|
/* [in] */ DISPID id,
|
|
/* [in] */ DWORD grfdexFetch,
|
|
/* [out] */ DWORD __RPC_FAR *pgrfdex)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetMemberProperties()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.GetMemberProperties(id, grfdexFetch, pgrfdex);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CSWbemLocator::GetMemberName(
|
|
/* [in] */ DISPID id,
|
|
/* [out] */ BSTR __RPC_FAR *pbstrName)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetMemberName()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.GetMemberName(id, pbstrName);
|
|
}
|
|
|
|
|
|
/*
|
|
* I don't think this needs implementing
|
|
*/
|
|
HRESULT STDMETHODCALLTYPE CSWbemLocator::GetNextDispID(
|
|
/* [in] */ DWORD grfdex,
|
|
/* [in] */ DISPID id,
|
|
/* [out] */ DISPID __RPC_FAR *pid)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetNextDispID()";)
|
|
HRESULT rc = S_FALSE;
|
|
|
|
_RPrint(me, "Called", 0, "");
|
|
if ((grfdex & fdexEnumAll) && pid) {
|
|
if (DISPID_STARTENUM == id) {
|
|
*pid = 1;
|
|
rc = S_OK;
|
|
} else if (1 == id) {
|
|
*pid = 2;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CSWbemLocator::GetNameSpaceParent(
|
|
/* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunk)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::GetNamespaceParent()";)
|
|
_RPrint(me, "Called", 0, "");
|
|
return m_Dispatch.GetNameSpaceParent(ppunk);
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
// HRESULT CSWbemLocator::InterfaceSupportsErrorInfo
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Standard Com ISupportErrorInfo functions.
|
|
//
|
|
//***************************************************************************
|
|
|
|
STDMETHODIMP CSWbemLocator::InterfaceSupportsErrorInfo (IN REFIID riid)
|
|
{
|
|
return (IID_ISWbemLocator == riid) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CSWbemLocator::ConnectServer
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Initiate connection to namespace
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// bsServer The Server to which to connect
|
|
// bsNamespace The namespace to connect to (default is reg lookup)
|
|
// bsUser The user ("" implies default to logged-on user)
|
|
// bsPassword The password ("" implies default to logged-on user's
|
|
// password if bsUser == "")
|
|
// bsLocale Requested locale
|
|
// bsAuthority Authority
|
|
// lSecurityFlags Currently 0 by default
|
|
// pContext If non-null, extra context info for the connection
|
|
// ppNamespace On successful return addresses the IWbemSServices
|
|
// connection to the namespace.
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
// WBEM_S_NO_ERROR success
|
|
// WBEM_E_INVALID_PARAMETER bad input parameters
|
|
// WBEM_E_FAILED otherwise
|
|
//
|
|
// Other WBEM error codes may be returned by ConnectServer etc., in which
|
|
// case these are passed on to the caller.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CSWbemLocator::ConnectServer (
|
|
BSTR bsServer,
|
|
BSTR bsNamespace,
|
|
BSTR bsUser,
|
|
BSTR bsPassword,
|
|
BSTR bsLocale,
|
|
BSTR bsAuthority,
|
|
long lSecurityFlags,
|
|
/*ISWbemValueBag*/ IDispatch *pContext,
|
|
ISWbemServices **ppNamespace
|
|
)
|
|
{
|
|
_RD(static char *me = "CSWbemLocator::ConnectServer";)
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
ResetLastErrors ();
|
|
|
|
if (NULL == ppNamespace)
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
else if (m_pIWbemLocator && m_SecurityInfo)
|
|
{
|
|
bool useDefaultUser = (NULL == bsUser) || (0 == wcslen(bsUser));
|
|
bool useDefaultAuthority = (NULL != bsAuthority) && (0 == wcslen (bsAuthority));
|
|
|
|
// Build the namespace path
|
|
BSTR bsNamespacePath = BuildPath (bsServer, bsNamespace);
|
|
|
|
// Get the context
|
|
IWbemContext *pIContext = CSWbemNamedValueSet::GetIWbemContext (pContext, m_pIServiceProvider);
|
|
|
|
// Connect to the requested namespace
|
|
IWbemServices *pIWbemService = NULL;
|
|
|
|
bool needToResetSecurity = false;
|
|
HANDLE hThreadToken = NULL;
|
|
|
|
if (m_SecurityInfo->SetSecurity (bsUser, needToResetSecurity, hThreadToken))
|
|
hr = m_pIWbemLocator->ConnectServer (
|
|
bsNamespacePath,
|
|
(useDefaultUser) ? NULL : bsUser,
|
|
(useDefaultUser) ? NULL : bsPassword,
|
|
((NULL != bsLocale) && (0 < wcslen (bsLocale))) ? bsLocale : NULL,
|
|
lSecurityFlags,
|
|
(useDefaultAuthority) ? NULL : bsAuthority,
|
|
pIContext,
|
|
&pIWbemService);
|
|
|
|
if (needToResetSecurity)
|
|
m_SecurityInfo->ResetSecurity (hThreadToken);
|
|
|
|
if (WBEM_S_NO_ERROR == hr)
|
|
{
|
|
// Create a new CSWbemServices using the IWbemServices interface
|
|
// just returned. This will AddRef pIWbemService.
|
|
|
|
CSWbemServices *pService =
|
|
new CSWbemServices (
|
|
pIWbemService,
|
|
bsNamespacePath,
|
|
((NULL != bsAuthority) && (0 < wcslen (bsAuthority))) ? bsAuthority : NULL,
|
|
(useDefaultUser) ? NULL : bsUser,
|
|
(useDefaultUser) ? NULL : bsPassword,
|
|
m_SecurityInfo,
|
|
((NULL != bsLocale) && (0 < wcslen (bsLocale))) ? bsLocale : NULL
|
|
);
|
|
|
|
if (!pService)
|
|
hr = WBEM_E_OUT_OF_MEMORY;
|
|
else if (FAILED(hr = pService->QueryInterface (IID_ISWbemServices,
|
|
(PPVOID) ppNamespace)))
|
|
delete pService;
|
|
|
|
pIWbemService->Release ();
|
|
}
|
|
|
|
if (NULL != pIContext)
|
|
pIContext->Release ();
|
|
|
|
SysFreeString (bsNamespacePath);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
m_Dispatch.RaiseException (hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CSWbemLocator::BuildPath
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Build a namespace path from a server and namespace
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// bsServer The Server to which to connect
|
|
// bsNamespace The namespace to connect to (default is reg lookup)
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
// The fully-formed namespace path
|
|
//
|
|
//***************************************************************************
|
|
|
|
BSTR CSWbemLocator::BuildPath (BSTR bsServer, BSTR bsNamespace)
|
|
{
|
|
BSTR namespacePath = NULL;
|
|
bool ok = false;
|
|
CComBSTR bsPath;
|
|
|
|
if ((NULL == bsServer) || (0 == wcslen(bsServer)))
|
|
bsServer = WBEMS_DEFAULT_SERVER;
|
|
|
|
// Use the default namespace if none supplied
|
|
if ((NULL == bsNamespace) || (0 == wcslen(bsNamespace)))
|
|
{
|
|
const wchar_t *defaultNamespace = GetDefaultNamespace ();
|
|
|
|
if (defaultNamespace)
|
|
{
|
|
CWbemPathCracker pathCracker;
|
|
pathCracker.SetServer (bsServer);
|
|
pathCracker.SetNamespacePath (defaultNamespace);
|
|
ok = pathCracker.GetPathText (bsPath, false, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CWbemPathCracker pathCracker;
|
|
pathCracker.SetServer (bsServer);
|
|
pathCracker.SetNamespacePath (bsNamespace);
|
|
ok = pathCracker.GetPathText (bsPath, false, true);
|
|
}
|
|
|
|
if (ok)
|
|
namespacePath = bsPath.Detach ();
|
|
|
|
return namespacePath;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CSWbemLocator::GetDefaultNamespace
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Get the default namespace path
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// None
|
|
//
|
|
// RETURN VALUES:
|
|
//
|
|
// The default Namespace.
|
|
//
|
|
//***************************************************************************
|
|
|
|
const wchar_t *CSWbemLocator::GetDefaultNamespace ()
|
|
{
|
|
if (!s_pDefaultNamespace)
|
|
{
|
|
// Get the value from the registry key
|
|
HKEY hKey;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
WBEMS_RK_SCRIPTING, 0, KEY_QUERY_VALUE, &hKey))
|
|
{
|
|
DWORD dataLen = 0;
|
|
|
|
// Find out how much space to allocate first
|
|
if (ERROR_SUCCESS == RegQueryValueEx (hKey, WBEMS_RV_DEFNS,
|
|
NULL, NULL, NULL, &dataLen))
|
|
{
|
|
TCHAR *defNamespace = new TCHAR [dataLen];
|
|
|
|
if (defNamespace)
|
|
{
|
|
if (ERROR_SUCCESS == RegQueryValueEx (hKey, WBEMS_RV_DEFNS,
|
|
NULL, NULL, (LPBYTE) defNamespace, &dataLen))
|
|
{
|
|
#ifndef UNICODE
|
|
// Convert the multibyte value to its wide character equivalent
|
|
int wDataLen = MultiByteToWideChar(CP_ACP, 0, defNamespace, -1, NULL, 0);
|
|
s_pDefaultNamespace = new wchar_t [wDataLen];
|
|
|
|
if (s_pDefaultNamespace)
|
|
MultiByteToWideChar(CP_ACP, 0, defNamespace, -1, s_pDefaultNamespace, wDataLen);
|
|
#else
|
|
s_pDefaultNamespace = new wchar_t [wcslen (defNamespace) + 1];
|
|
|
|
if (s_pDefaultNamespace)
|
|
wcscpy (s_pDefaultNamespace, defNamespace);
|
|
#endif
|
|
}
|
|
|
|
delete [] defNamespace;
|
|
}
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
// If we failed to read the registry OK, just use the default
|
|
if (!s_pDefaultNamespace)
|
|
{
|
|
#ifndef UNICODE
|
|
int wDataLen = MultiByteToWideChar(CP_ACP, 0, WBEMS_DEFNS, -1, NULL, 0);
|
|
s_pDefaultNamespace = new wchar_t [wDataLen];
|
|
|
|
if (s_pDefaultNamespace)
|
|
MultiByteToWideChar(CP_ACP, 0, WBEMS_DEFNS, -1, s_pDefaultNamespace, wDataLen);
|
|
#else
|
|
s_pDefaultNamespace = new wchar_t [wcslen (WBEMS_DEFNS) + 1];
|
|
|
|
if (s_pDefaultNamespace)
|
|
wcscpy (s_pDefaultNamespace, WBEMS_DEFNS);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return s_pDefaultNamespace;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CSWbemLocator::get_Security_
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Return the security configurator
|
|
//
|
|
// WBEM_S_NO_ERROR success
|
|
// WBEM_E_INVALID_PARAMETER bad input parameters
|
|
// WBEM_E_FAILED otherwise
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CSWbemLocator::get_Security_ (
|
|
ISWbemSecurity **ppSecurity
|
|
)
|
|
{
|
|
HRESULT hr = WBEM_E_FAILED;
|
|
|
|
ResetLastErrors ();
|
|
|
|
if (NULL == ppSecurity)
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
{
|
|
*ppSecurity = NULL;
|
|
|
|
if (m_SecurityInfo)
|
|
{
|
|
if (SUCCEEDED (m_SecurityInfo->QueryInterface (IID_ISWbemSecurity,
|
|
(PPVOID) ppSecurity)))
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
m_Dispatch.RaiseException (hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|