mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1650 lines
41 KiB
1650 lines
41 KiB
/*++
|
|
|
|
Copyright (C) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
PROVAUTO.CPP
|
|
|
|
Abstract:
|
|
|
|
Defines the acutal "Put" and "Get" functions for the
|
|
Automation provider. The syntax of the mapping string is;
|
|
"[path],[classid]|property
|
|
|
|
History:
|
|
|
|
a-davj 3-13-96 Created.
|
|
|
|
--*/
|
|
|
|
NOTE, THE ORIGINAL SERVER2.CPP HAS CODE TO INITIALIZE gpStorage and ghAutoMutex
|
|
|
|
#include "precomp.h"
|
|
#include "stdafx.h"
|
|
#include <wbemidl.h>
|
|
#include "afxpriv.h"
|
|
#include "provauto.h"
|
|
#include "cvariant.h"
|
|
#define NOTFOUND -1
|
|
extern TCHAR * gpStorageFile;
|
|
extern CMyDLL theApp;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Special automation version of CHandleCache which also stores a hidden window,
|
|
// site and path information. The hidden window also contains a COleContainer
|
|
// object. Note that this extra information is only used by OCXs. The various
|
|
// values are freed up by the CImpAuto::Free routine and so a destructor isnt
|
|
// needed for this class.
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CAutoCache::CAutoCache
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CAutoCache::CAutoCache ()
|
|
{
|
|
pSavePath = NULL;
|
|
pSite = NULL;
|
|
pCtlWnd = NULL;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::DoCall
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Makes an IDispath Invoke call.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// wOpt
|
|
// ProvObj
|
|
// iIndex
|
|
// pDisp
|
|
// vt
|
|
// pData
|
|
// pProp
|
|
//
|
|
// RETURN VALUE:
|
|
// Return: True if OK. If there is a problem, then the error code is set
|
|
// in pMo in addition to having a FALSE return code.
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::DoCall(
|
|
WORD wOpt,
|
|
CProvObj & ProvObj,
|
|
int iIndex,
|
|
LPDISPATCH pDisp,
|
|
VARTYPE vt,
|
|
void * pData,
|
|
WCHAR * pProp)
|
|
{
|
|
USES_CONVERSION;
|
|
DISPID dispid;
|
|
SCODE sc;
|
|
COleDispatchDriver Disp;
|
|
|
|
BYTE cArgTypes[MAX_ARGS+2]; // Extra for null terminator and for Put value
|
|
void * Args[MAX_ARGS+1]; // Extra for put value
|
|
int iNumArgs = 0,iExp;
|
|
|
|
|
|
// Get the dispatch ID for property/method name
|
|
|
|
OLECHAR * pArg;
|
|
if(pProp == NULL)
|
|
pArg = T2OLE(ProvObj.sGetToken(iIndex));
|
|
else
|
|
pArg = pProp;
|
|
|
|
sc = pDisp->GetIDsOfNames(IID_NULL,&pArg,1,LOCALE_SYSTEM_DEFAULT,
|
|
&dispid);
|
|
if (sc != S_OK)
|
|
return sc;
|
|
|
|
// Get the arguments, if any, ready for the call
|
|
|
|
memset(cArgTypes,0,MAX_ARGS+2);
|
|
iNumArgs = ProvObj.iGetNumExp(iIndex);
|
|
if(iNumArgs > MAX_ARGS)
|
|
{
|
|
return WBEM_E_FAILED; // too many arguments
|
|
}
|
|
for(iExp = 0; iExp < iNumArgs; iExp++)
|
|
{
|
|
|
|
// if the argument is a string, then create a BSTR and point to it. If the
|
|
// argument is an integer, just typecast it into the argument array
|
|
|
|
if(ProvObj.IsExpString(iIndex,iExp))
|
|
{
|
|
Args[iExp] = SysAllocString(T2OLE(ProvObj.sGetStringExp(iIndex,iExp)));
|
|
if(Args[iExp] == NULL)
|
|
{
|
|
sc = WBEM_E_OUT_OF_MEMORY;
|
|
goto DoInvokeCleanup;
|
|
}
|
|
cArgTypes[iExp] = VT_BSTR;
|
|
}
|
|
else
|
|
{
|
|
cArgTypes[iExp] = VT_I4;
|
|
Args[iExp] = (void *)ProvObj.iGetIntExp(iIndex,iExp,0);
|
|
}
|
|
}
|
|
|
|
|
|
// use the MFC automation driver to do the acual invoke
|
|
|
|
Disp.AttachDispatch(pDisp);
|
|
TRY
|
|
{
|
|
if((wOpt & DISPATCH_PROPERTYPUT) || (wOpt & DISPATCH_PROPERTYPUTREF))
|
|
{
|
|
cArgTypes[iNumArgs] = (BYTE)vt;
|
|
Args[iNumArgs] = pData;
|
|
Disp.InvokeHelper(dispid,wOpt,VT_EMPTY,NULL,cArgTypes,
|
|
Args[0],Args[1],Args[2],Args[3],Args[4],Args[5]);
|
|
}
|
|
else
|
|
Disp.InvokeHelper(dispid,wOpt,vt,pData,cArgTypes,
|
|
Args[0],Args[1],Args[2],Args[3],Args[4],Args[5]);
|
|
sc = S_OK;
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
sc = WBEM_E_FAILED;
|
|
}
|
|
END_CATCH
|
|
|
|
|
|
Disp.DetachDispatch();
|
|
|
|
// This is used to clean up any BSTR strings that might have been allocated. This
|
|
// can be skipped if it fails before any of the strings are allocated.
|
|
|
|
DoInvokeCleanup:
|
|
for(iExp = 0; iExp < iNumArgs; iExp++)
|
|
if(cArgTypes[iExp] == VT_BSTR)
|
|
SysFreeString((BSTR)Args[iExp]);
|
|
return sc;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::GetCFileStreamObj
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Some OCXs use a persistent stream to load and save data. This
|
|
// routine gets a COleStreamFile object for such proposes.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pPath
|
|
// ppStorage
|
|
// **ppFile
|
|
// *pCache
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::GetCFileStreamObj(
|
|
const TCHAR * pPath,
|
|
LPSTORAGE * ppStorage,
|
|
COleStreamFile **ppFile,
|
|
CAutoCache *pCache)
|
|
{
|
|
SCODE sc;
|
|
USES_CONVERSION;
|
|
*ppStorage = NULL;
|
|
*ppFile = NULL;
|
|
if(pPath == NULL) // Some OCXs dont need storage, this is OK.
|
|
return S_OK;
|
|
|
|
// Save Path in the cache
|
|
|
|
ASSERT(pCache->pSavePath == NULL);
|
|
pCache->pSavePath = new TCHAR[lstrlen(pPath) + 1];
|
|
lstrcpy(pCache->pSavePath,pPath);
|
|
|
|
// During first run after install, the compond file will not exist. This
|
|
// is not as a problem as it will be created during the write
|
|
|
|
sc = StgIsStorageFile(T2OLE(gpStorageFile));
|
|
if(sc == STG_E_FILENOTFOUND)
|
|
return S_OK;
|
|
if(sc != S_OK)
|
|
{ // unusual failure!
|
|
return sc;
|
|
}
|
|
|
|
// Open up the root storage. It should never fail since we just checked to make
|
|
// sure the file is available.
|
|
// TODO, might want to mutex control access to the storage
|
|
|
|
sc = StgOpenStorage(T2OLE(gpStorageFile),NULL,STGM_READ|STGM_SHARE_DENY_WRITE,
|
|
NULL,0l,ppStorage);
|
|
|
|
if(FAILED(sc))
|
|
{
|
|
return WBEM_E_FAILED;
|
|
}
|
|
|
|
// Create a new COleStreamFile object and set the stream using the storage object.
|
|
|
|
*ppFile = new COleStreamFile();
|
|
if(*ppFile == NULL)
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// Open a stream. Note that failure isnt unusual since this might be the
|
|
// first time for the control.
|
|
|
|
COleStreamFile * pFile = *ppFile;
|
|
if(!pFile->OpenStream(*ppStorage,pPath,STGM_READ|STGM_SHARE_EXCLUSIVE))
|
|
{
|
|
delete *ppFile;
|
|
*ppFile = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// BOOL CImpAuto::bIsControl
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// tests if the IUnknown is pointing to an object which is an OCX.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// lpTest
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
BOOL CImpAuto::bIsControl(
|
|
LPUNKNOWN lpTest)
|
|
{
|
|
LPOLECONTROL lpCont = NULL;
|
|
SCODE sc = lpTest->QueryInterface(IID_IOleControl,(LPVOID *) & lpCont);
|
|
if(FAILED(sc) || lpCont == NULL)
|
|
return FALSE;
|
|
|
|
// Have an OCX, free up the pointer for now since it will be retireved by
|
|
// the COleControlSite object later on
|
|
|
|
lpCont->Release();
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::ParsePathClass
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Takes in a string in the sMix argument which is of the same for
|
|
// as the arguments to VB's GetObject and parses the string. This routine
|
|
// retrieves the path and class strings and determines the type. This could be;
|
|
// "path","class" (Type BOTH) or
|
|
// "path" (Type PATH) or
|
|
// "","class" (Type NEWCLASS) or
|
|
// ,"class" (Type RUNNINGCLASS)
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// sMix
|
|
// sPath
|
|
// sClass
|
|
// type
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::ParsePathClass(
|
|
const CString & sMix,
|
|
CString & sPath,
|
|
CString & sClass,
|
|
OBJTYPE * type)
|
|
{
|
|
int iLen = sMix.GetLength();
|
|
int iFstst = NOTFOUND; // first quote of the first string
|
|
int iFsten = NOTFOUND; // last quote of the last string
|
|
int iSecst = NOTFOUND; // first quote of the second string
|
|
int iSecen = NOTFOUND; // last quote of the second string
|
|
int iCommaPos = NOTFOUND; // position of comma between strings
|
|
int iIndex;
|
|
int iNumSoFar = 0; // number of '"' found so far
|
|
|
|
// Go through the string and find the starting and ending '"' of the path string
|
|
// and possibly the class string. Note the location of the comma.
|
|
|
|
for(iIndex = 0; iIndex < iLen; iIndex++)
|
|
{
|
|
if(sMix[iIndex] == DQUOTE)
|
|
{
|
|
iNumSoFar++;
|
|
if(iFstst == NOTFOUND && iCommaPos == NOTFOUND)
|
|
iFstst = iIndex;
|
|
if(iCommaPos == NOTFOUND)
|
|
iFsten = iIndex;
|
|
if(iSecst == NOTFOUND && iCommaPos != NOTFOUND)
|
|
iSecst = iIndex;
|
|
if(iCommaPos != NOTFOUND)
|
|
iSecen = iIndex;
|
|
}
|
|
if(sMix[iIndex] == SEPARATOR && (iNumSoFar%2 == 0) && iCommaPos == NOTFOUND)
|
|
iCommaPos = iIndex;
|
|
}
|
|
|
|
// Verify that there were an even number of quotes.
|
|
|
|
if(iNumSoFar%2 || iNumSoFar == 0)
|
|
{
|
|
return WBEM_E_FAILED; // odd number of quotes is bad
|
|
}
|
|
|
|
// Extract the strings.
|
|
|
|
for(iIndex = iFstst+1; iIndex < iFsten; iIndex++)
|
|
{
|
|
sPath += sMix[iIndex];
|
|
|
|
// if there is a "" in the string, copy just the first
|
|
if(sMix[iIndex] == DQUOTE)
|
|
iIndex++;
|
|
}
|
|
|
|
|
|
for(iIndex = iSecst+1; iIndex < iSecen; iIndex++)
|
|
{
|
|
sClass += sMix[iIndex];
|
|
|
|
// if there is a "" in the string, copy just the first
|
|
if(sMix[iIndex] == DQUOTE)
|
|
iIndex++;
|
|
}
|
|
|
|
// make sure that something was retrieved!
|
|
|
|
if(sPath.GetLength() < 1 && sClass.GetLength() < 1)
|
|
{
|
|
return WBEM_E_FAILED; // didnt get any data!
|
|
}
|
|
|
|
// figure out what type of request
|
|
|
|
if(sPath.GetLength() > 0 && sClass.GetLength() > 0)
|
|
*type = BOTH;
|
|
else if(sPath.GetLength() > 0 && sClass.GetLength() == 0)
|
|
*type = PATH;
|
|
else if(sPath.GetLength() == 0 && sClass.GetLength() > 0 && iFstst != NOTFOUND)
|
|
*type = NEWCLASS;
|
|
else if(sPath.GetLength() == 0 && sClass.GetLength() > 0 && iFstst == NOTFOUND)
|
|
*type = RUNNINGCLASS;
|
|
else
|
|
{
|
|
return WBEM_E_FAILED; // got some sort of junk!
|
|
}
|
|
return S_OK; // all is well
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CImpAuto::CImpAuto
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// ObjectPath
|
|
// User
|
|
// Password
|
|
//
|
|
//***************************************************************************
|
|
|
|
CImpAuto::CImpAuto()
|
|
{
|
|
wcscpy(wcCLSID,L"{DAC651D1-7CC7-11cf-A5B6-00AA00680C3F}");
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
// void CImpAuto::EndBatch
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called at the end of a batch of Refrest/Update Property calls. Free up
|
|
// any cached handles and then delete the handle cache.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// lFlags
|
|
// pClassInt
|
|
// *pObj
|
|
// bGet
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
void CImpAuto::EndBatch(
|
|
long lFlags,
|
|
IWbemClassObject FAR * pClassInt,
|
|
CObject *pObj,
|
|
BOOL bGet)
|
|
{
|
|
if(pObj != NULL)
|
|
{
|
|
Free(0,(CAutoCache *)pObj);
|
|
delete pObj;
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void CImpAuto::Free
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Frees up cached IDispatch interfaces starting with position
|
|
// iStart till the end. After freeing handles, the cache object
|
|
// member function is used to delete the cache entries.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// iStart
|
|
// pCache
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
void CImpAuto::Free(
|
|
int iStart,
|
|
CAutoCache * pCache)
|
|
{
|
|
int iCurr;
|
|
LPOLEOBJECT pTemp = NULL;
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
for(iCurr = pCache->lGetNumEntries()-1; iCurr >= iStart; iCurr--)
|
|
{
|
|
LPDISPATCH pDisp = (LPDISPATCH)pCache->hGetHandle(iCurr);
|
|
if(pDisp != NULL)
|
|
pDisp->Release();
|
|
}
|
|
pCache->Delete(iStart); // get cache to delete the entries
|
|
if(iStart == 0)
|
|
{
|
|
if(pCache->pSavePath)
|
|
{
|
|
if(pCache->pSite)
|
|
{
|
|
DWORD dwRet;
|
|
dwRet = WaitForSingleObject(ghAutoMutex,MAX_AUTO_WAIT);
|
|
if(dwRet == WAIT_ABANDONED || dwRet == WAIT_OBJECT_0)
|
|
{
|
|
try
|
|
{
|
|
StoreControl(pCache);
|
|
}
|
|
catch(...) {}
|
|
ReleaseMutex(ghAutoMutex);
|
|
}
|
|
}
|
|
delete pCache->pSavePath;
|
|
pCache->pSavePath = NULL;
|
|
}
|
|
if(pCache->pCtlWnd != NULL)
|
|
{
|
|
// DONOT delete the Site object since the Control container does it!!
|
|
// Note important HACK! There is a bug in the MFC that ships with VC 4.0.
|
|
// The COleControlSite::CreateOrLoad routine has a QueryInterface call
|
|
// to get an IPersistMemory interface, BUT DOES NOT RELEASE IT! So, to
|
|
// release it, there is a bit of code here to call release until the count
|
|
// goes to 0.
|
|
|
|
if(pCache->pSite)
|
|
{
|
|
pTemp = pCache->pSite->m_pObject;
|
|
pTemp->AddRef();
|
|
}
|
|
pCache->pCtlWnd->DestroyWindow(); // note that DestroyWindow frees up the object
|
|
pCache->pCtlWnd = NULL; // and gets rid of the container within
|
|
// First release for the AddRef right above. Second possible release is
|
|
// for the bug!
|
|
if(pCache->pSite && pTemp)
|
|
{
|
|
DWORD dwRes = pTemp->Release();
|
|
if(dwRes > 0)
|
|
pTemp->Release();
|
|
}
|
|
}
|
|
pCache->pSite = NULL;
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::RefreshProperty
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets the value of a single property from an automation server.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// lFlags
|
|
// pClassInt
|
|
// PropName
|
|
// ProvObj
|
|
// pPackage
|
|
// pVar
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::RefreshProperty(
|
|
long lFlags,
|
|
IWbemClassObject FAR * pClassInt,
|
|
BSTR PropName,
|
|
CProvObj & ProvObj,
|
|
CObject * pPackage,
|
|
CVariant * pVar)
|
|
{
|
|
SCODE sc;
|
|
USES_CONVERSION;
|
|
CString sRet;
|
|
LPDISPATCH pDisp = NULL;
|
|
CAutoCache * pCache = (CAutoCache *)pPackage;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
// Do a second parse on the provider string.
|
|
|
|
CProvObj ObjectPath(ProvObj.sGetFullToken(1),DOT);
|
|
sc = ObjectPath.dwGetStatus(1); //todo, is 1 ok??
|
|
if(sc != S_OK)
|
|
return sc;
|
|
|
|
// Get the IDispatch interface and then do the "Get"
|
|
|
|
int iDepth = ObjectPath.iGetNumTokens()-1;
|
|
|
|
HINSTANCE hTest = afxCurrentInstanceHandle;
|
|
|
|
pDisp = pGetDispatch(&sc,ObjectPath,ProvObj.sGetToken(0),pCache,iDepth);
|
|
if(pDisp)
|
|
{
|
|
int iLast = ObjectPath.iGetNumTokens()-1;
|
|
sc = DoCall(DISPATCH_PROPERTYGET,ObjectPath,iLast,pDisp,VT_BSTR,&sRet);
|
|
if(sc == S_OK)
|
|
{
|
|
CVariant varAuto;
|
|
sc = varAuto.SetData(T2OLE(sRet),VT_LPWSTR);
|
|
if(sc != S_OK)
|
|
return sc;
|
|
sc = varAuto.DoPut(lFlags,pClassInt,PropName,pVar);
|
|
}
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LPDISPATCH CImpAuto::pGetBoth
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets IDISPATCH interface to the server using path and class.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// psc
|
|
// pPath
|
|
// pClass
|
|
// *pCache
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LPDISPATCH CImpAuto::pGetBoth(
|
|
SCODE * psc,
|
|
const TCHAR * pPath,
|
|
const TCHAR * pClass,
|
|
CAutoCache *pCache)
|
|
{
|
|
HRESULT sc;
|
|
USES_CONVERSION;
|
|
CLSID clsid;
|
|
LPDISPATCH lpRetDispatch = NULL;
|
|
LPUNKNOWN lpUnknown = NULL;
|
|
LPPERSISTFILE lpPersist = NULL;
|
|
|
|
sc = CLSIDFromProgID(T2OLE(pClass), &clsid);
|
|
if (FAILED(sc))
|
|
goto BadBoth;
|
|
|
|
// create an instance with the IUnknown
|
|
|
|
sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (LPVOID *)&lpUnknown);
|
|
if (FAILED(sc))
|
|
goto BadBoth;
|
|
|
|
OleRun(lpUnknown); // Some objects need this!
|
|
|
|
// If the class is an OCX, then use special code to get its value
|
|
|
|
if(bIsControl(lpUnknown))
|
|
{
|
|
DWORD dwRet;
|
|
dwRet = WaitForSingleObject(ghAutoMutex,MAX_AUTO_WAIT);
|
|
if(dwRet == WAIT_ABANDONED || dwRet == WAIT_OBJECT_0)
|
|
{
|
|
try
|
|
{
|
|
lpRetDispatch = pGetOCX(psc,pPath,clsid,pCache,lpUnknown); //frees lpUnknown
|
|
}
|
|
catch(...)
|
|
{
|
|
lpRetDispatch = NULL;
|
|
}
|
|
ReleaseMutex(ghAutoMutex);
|
|
}
|
|
else
|
|
*psc = WBEM_E_FAILED;
|
|
return lpRetDispatch;
|
|
}
|
|
|
|
// query for persist file interface
|
|
|
|
sc = lpUnknown->QueryInterface(IID_IPersistFile,(LPVOID *)&lpPersist);
|
|
lpUnknown->Release();
|
|
if (FAILED(sc))
|
|
goto BadBoth;
|
|
|
|
// do a sanity check, probably not necessary.
|
|
|
|
ASSERT(lpPersist != NULL);
|
|
if (lpPersist == NULL)
|
|
{
|
|
sc = WBEM_E_FAILED;
|
|
goto BadBoth;
|
|
}
|
|
|
|
// Load up the desired file
|
|
|
|
sc = lpPersist->Load(T2OLE(pPath),0);
|
|
if (FAILED(sc))
|
|
goto BadBoth;
|
|
|
|
sc = lpPersist->QueryInterface(IID_IDispatch,(LPVOID *)&lpRetDispatch);
|
|
lpPersist->Release();
|
|
if (FAILED(sc))
|
|
goto BadBoth;
|
|
|
|
ASSERT(lpRetDispatch != NULL);
|
|
if (lpRetDispatch != NULL)
|
|
return lpRetDispatch;
|
|
|
|
|
|
BadBoth:
|
|
if(lpPersist != NULL)
|
|
lpPersist->Release();
|
|
*psc = sc;
|
|
return NULL;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LPDISPATCH CImpAuto::pGetDispatch
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets get the IDispatch for gets and sets
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// psc
|
|
// ObjectPath
|
|
// pPathClass
|
|
// *pCache
|
|
// iDepth
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LPDISPATCH CImpAuto::pGetDispatch(
|
|
SCODE * psc,
|
|
CProvObj & ObjectPath,
|
|
LPCTSTR pPathClass,
|
|
CAutoCache *pCache,
|
|
int iDepth)
|
|
{
|
|
LPDISPATCH pRetDisp;
|
|
int iNumSkip;
|
|
int iIndex;
|
|
|
|
// Get at least the application interface. If the object path is in common with
|
|
// previous calls, then some of the subobject are already set and that is
|
|
// indicated by the value in iNumSkip;
|
|
|
|
pRetDisp = pGetDispatchRoot(psc,ObjectPath,pPathClass,pCache,iNumSkip);
|
|
|
|
// For each subobject that wasnt in the cache, get its IDispatch, and add it
|
|
// to the cache.
|
|
|
|
for(iIndex = iNumSkip; iIndex < iDepth && pRetDisp; iIndex++)
|
|
{
|
|
LPDISPATCH pNewDisp;
|
|
*psc = DoCall(DISPATCH_PROPERTYGET,ObjectPath,iIndex,
|
|
pRetDisp,VT_DISPATCH,&pNewDisp);
|
|
if(*psc != S_OK)
|
|
return NULL;
|
|
*psc = pCache->lAddToList(ObjectPath.sGetFullToken(iIndex),pNewDisp);
|
|
if(*psc != S_OK)
|
|
return NULL;
|
|
pRetDisp = pNewDisp;
|
|
}
|
|
return pRetDisp;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LPDISPATCH CImpAuto::pGetDispatchRoot
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets the interface to the application object or some other starting point
|
|
// such as a "document" object.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// psc
|
|
// ObjectPath
|
|
// pPathClass
|
|
// *pCache
|
|
// iNumSkip
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LPDISPATCH CImpAuto::pGetDispatchRoot(
|
|
SCODE * psc,
|
|
CProvObj & ObjectPath,
|
|
LPCTSTR pPathClass,
|
|
CAutoCache *pCache,
|
|
int & iNumSkip)
|
|
{
|
|
iNumSkip = 0;
|
|
LPDISPATCH pRetDisp = NULL;
|
|
OBJTYPE type;
|
|
HKEY hRoot = NULL;
|
|
const TCHAR * pObject = ObjectPath.sGetFullToken(0);
|
|
if(pPathClass == NULL || pObject == NULL)
|
|
{
|
|
*psc = WBEM_E_FAILED; // bad mapping string
|
|
return NULL;
|
|
}
|
|
|
|
// If there are handles in the cache, then they may be used if and
|
|
// only if the path/class matches.
|
|
|
|
if(pCache->lGetNumEntries() > 0)
|
|
{
|
|
if(lstrcmpi(pCache->sGetString(0),pPathClass))
|
|
|
|
// The path/class has changed.free all the cached handles.
|
|
|
|
Free(0,pCache);
|
|
else
|
|
{
|
|
|
|
// The Path/class matches what is in the cache. Determine how much
|
|
// else is in common, free what isnt in common, and return
|
|
// the subkey share a common path.
|
|
|
|
iNumSkip = pCache->lGetNumMatch(1,0,ObjectPath);
|
|
Free(1+iNumSkip,pCache);
|
|
return (LPDISPATCH )pCache->hGetHandle(iNumSkip);
|
|
}
|
|
}
|
|
|
|
|
|
// Need to get the initial IDispatch handle. Start off by breaking up
|
|
// path/class string. Note that TRY/CATCH is used since
|
|
// bParsePathClass does CString allocations which can give exceptions.
|
|
|
|
CString sPath,sClass;
|
|
|
|
TRY
|
|
{
|
|
*psc = ParsePathClass(pPathClass,sPath,sClass,&type);
|
|
if(*psc != S_OK)
|
|
return NULL; // bad string, actual error set in bParsePathClass
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
*psc = WBEM_E_OUT_OF_MEMORY;
|
|
return NULL;
|
|
}
|
|
END_CATCH
|
|
|
|
// Based on the path/class combination, call the correct routine to
|
|
// actually hook up to the server.
|
|
|
|
switch(type)
|
|
{
|
|
case BOTH:
|
|
pRetDisp = pGetBoth(psc,sPath,sClass,pCache);
|
|
break;
|
|
|
|
case PATH:
|
|
pRetDisp = pGetPath(psc,sPath);
|
|
break;
|
|
|
|
case NEWCLASS:
|
|
pRetDisp = pGetNewClass(psc,sClass,pCache);
|
|
break;
|
|
|
|
case RUNNINGCLASS:
|
|
pRetDisp = pGetRunningClass(psc,sClass,pCache);
|
|
break;
|
|
|
|
default:
|
|
*psc = WBEM_E_FAILED;
|
|
}
|
|
|
|
if(pRetDisp == NULL)
|
|
return NULL;
|
|
|
|
// Got the initial IDispatch interface. Add it to the Cache
|
|
|
|
*psc = pCache->lAddToList(pPathClass,pRetDisp);
|
|
if(*psc != S_OK)
|
|
{ // error adding to cache, probably memory
|
|
pRetDisp->Release();
|
|
return NULL;
|
|
}
|
|
return pRetDisp; // all is well!
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LPDISPATCH CImpAuto::pGetNewClass
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets IDISPATCH interface to the server using the class id and always
|
|
// creates a new object.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// psc
|
|
// pClass
|
|
// *pCache
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LPDISPATCH CImpAuto::pGetNewClass(
|
|
SCODE * psc,
|
|
const TCHAR * pClass,
|
|
CAutoCache *pCache)
|
|
{
|
|
HRESULT sc;
|
|
CLSID clsid;
|
|
USES_CONVERSION;
|
|
LPDISPATCH lpRetDispatch = NULL;
|
|
LPUNKNOWN lpUnknown = NULL;
|
|
|
|
sc = CLSIDFromProgID(T2OLE(pClass), &clsid);
|
|
if (FAILED(sc))
|
|
goto BadNewClass;
|
|
|
|
// create an instance with the IUnknown
|
|
|
|
sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (LPVOID *)&lpUnknown);
|
|
if (FAILED(sc))
|
|
goto BadNewClass;
|
|
OleRun(lpUnknown);
|
|
|
|
// If the class is an OCX, then use special code to get its value
|
|
|
|
if(bIsControl(lpUnknown))
|
|
{
|
|
DWORD dwRet;
|
|
dwRet = WaitForSingleObject(ghAutoMutex,MAX_AUTO_WAIT);
|
|
if(dwRet == WAIT_ABANDONED || dwRet == WAIT_OBJECT_0)
|
|
{
|
|
try
|
|
{
|
|
lpRetDispatch = pGetOCX(psc,NULL,clsid,pCache,lpUnknown); //frees lpUnknown
|
|
}
|
|
catch(...)
|
|
{ lpRetDispatch = NULL;
|
|
}
|
|
ReleaseMutex(ghAutoMutex);
|
|
}
|
|
else
|
|
*psc = WBEM_E_FAILED;
|
|
return lpRetDispatch;
|
|
}
|
|
|
|
// query for IDispatch interface
|
|
|
|
sc = lpUnknown->QueryInterface(IID_IDispatch,(LPVOID *)&lpRetDispatch);
|
|
lpUnknown->Release();
|
|
if (FAILED(sc))
|
|
goto BadNewClass;
|
|
|
|
ASSERT(lpRetDispatch != NULL);
|
|
return lpRetDispatch;
|
|
|
|
BadNewClass:
|
|
*psc = sc;
|
|
return NULL;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LPDISPATCH CImpAuto::pGetOCX
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets IDISPATCH interface to an OCX. Note that the lpUnk should be
|
|
// released at the end of the routine so that the server will
|
|
// continue running even as it is setup as a control!
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// psc
|
|
// pPath
|
|
// clsid
|
|
// *pCache
|
|
// lpUnk
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LPDISPATCH CImpAuto::pGetOCX(
|
|
SCODE * psc,
|
|
const TCHAR * pPath,
|
|
CLSID & clsid,
|
|
CAutoCache *pCache,
|
|
LPUNKNOWN lpUnk)
|
|
{
|
|
RECT rect;
|
|
rect.left = 0; rect.right = 150; rect.top = 0; rect.bottom = 150;
|
|
LPDISPATCH lpRetDispatch = NULL;
|
|
COleControlContainer * pCont = NULL;
|
|
BOOL bOK;
|
|
SCODE sc;
|
|
LPSTORAGE pStorage = NULL;
|
|
COleStreamFile * pFileStream = NULL;
|
|
|
|
|
|
// Possibly create a COleStreamFile object. This is done only if the pPath is
|
|
// not NULL and if everything exists. This routine must release the pStorage
|
|
// interface and the pFileStream objects if the are created!
|
|
|
|
*psc = GetCFileStreamObj(pPath, &pStorage, &pFileStream,pCache);
|
|
if(*psc != S_OK)
|
|
goto EndpGetOCX;
|
|
|
|
|
|
// Create the window that will contain the controls. The window's contstructor
|
|
// creates the COleContainer object.
|
|
|
|
pCache->pCtlWnd = new CCtlWnd();
|
|
if(pCache->pCtlWnd == NULL)
|
|
{
|
|
*psc = WBEM_E_OUT_OF_MEMORY;
|
|
goto EndpGetOCX;
|
|
}
|
|
pCont = pCache->pCtlWnd->pGetCont();
|
|
|
|
// Do quick sanity check, shouldnt fail
|
|
|
|
if(pCont == NULL)
|
|
{
|
|
*psc = WBEM_E_FAILED;
|
|
goto EndpGetOCX;
|
|
}
|
|
|
|
// Use the control container to create the site and control in one call
|
|
|
|
bOK = pCont->CreateControl(NULL, clsid, NULL,WS_CHILD,
|
|
rect, 23, pFileStream, FALSE,
|
|
NULL, &pCache->pSite);
|
|
|
|
if(!bOK || pCache->pSite == NULL)
|
|
{
|
|
pCache->pSite = NULL;
|
|
*psc = WBEM_E_FAILED;
|
|
goto EndpGetOCX;
|
|
}
|
|
|
|
// query for IDispatch interface
|
|
|
|
sc = pCache->pSite->m_pObject->QueryInterface(IID_IDispatch,
|
|
(LPVOID *)&lpRetDispatch);
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
*psc = sc;
|
|
lpRetDispatch = NULL;
|
|
}
|
|
|
|
EndpGetOCX:
|
|
if(pFileStream)
|
|
{
|
|
pFileStream->Close();
|
|
delete pFileStream;
|
|
}
|
|
if(pStorage)
|
|
pStorage->Release();
|
|
if(lpUnk)
|
|
lpUnk->Release();
|
|
return lpRetDispatch;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LPDISPATCH CImpAuto::pGetPath
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets IDISPATCH interface to the server using the path.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// psc
|
|
// pPath
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LPDISPATCH CImpAuto::pGetPath(
|
|
SCODE * psc,
|
|
const TCHAR * pPath)
|
|
{
|
|
HRESULT sc;
|
|
LPBC pbc=NULL;
|
|
LPDISPATCH lpRetDispatch = NULL;
|
|
USES_CONVERSION;
|
|
LPMONIKER pmk;
|
|
pmk=NULL;
|
|
DWORD dwEat;
|
|
|
|
// Get a bind context object.
|
|
|
|
sc = CreateBindCtx(0, &pbc);
|
|
if (FAILED(sc))
|
|
{
|
|
*psc = sc;
|
|
return NULL;
|
|
}
|
|
|
|
// Get a moniker
|
|
|
|
sc = MkParseDisplayName(pbc, T2OLE(pPath), &dwEat, &pmk);
|
|
if (FAILED(sc))
|
|
goto BadPath;
|
|
|
|
// Bind the moniker
|
|
|
|
sc = (pmk)->BindToObject(pbc, NULL, IID_IDispatch
|
|
, (void **)&lpRetDispatch);
|
|
|
|
pmk->Release();
|
|
if(FAILED(sc))
|
|
goto BadPath;
|
|
ASSERT(lpRetDispatch != NULL);
|
|
|
|
// If the class is an OCX, then something is wrong here.
|
|
|
|
if(bIsControl(lpRetDispatch))
|
|
{
|
|
*psc = WBEM_E_FAILED;
|
|
lpRetDispatch->Release();
|
|
return NULL;
|
|
}
|
|
|
|
if(lpRetDispatch)
|
|
{ // should always be true at this point!
|
|
pbc->Release();
|
|
return lpRetDispatch;
|
|
}
|
|
sc = WBEM_E_FAILED;
|
|
|
|
BadPath:
|
|
if(pbc)
|
|
pbc->Release();
|
|
*psc = sc;
|
|
return NULL;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// LPDISPATCH CImpAuto::pGetRunningClass
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets IDISPATCH interface to the server using the class id and always
|
|
// returns only running objects.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// psc
|
|
// pClass
|
|
// *pCache
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
LPDISPATCH CImpAuto::pGetRunningClass(
|
|
SCODE * psc,
|
|
const TCHAR * pClass,
|
|
CAutoCache *pCache)
|
|
{
|
|
HRESULT sc;
|
|
CLSID clsid;
|
|
LPDISPATCH lpRetDispatch = NULL;
|
|
USES_CONVERSION;
|
|
LPUNKNOWN lpUnknown = NULL;
|
|
|
|
sc = CLSIDFromProgID(T2OLE(pClass), &clsid);
|
|
if (FAILED(sc))
|
|
goto BadRunningClass;
|
|
|
|
// create an instance with the IUnknown
|
|
|
|
sc = GetActiveObject(clsid,NULL,&lpUnknown);
|
|
if (FAILED(sc))
|
|
goto BadRunningClass;
|
|
|
|
// query for IDispatch interface
|
|
|
|
sc = lpUnknown->QueryInterface(IID_IDispatch,(LPVOID *)&lpRetDispatch);
|
|
lpUnknown->Release();
|
|
if (FAILED(sc))
|
|
goto BadRunningClass;
|
|
|
|
// If the class is an OCX, then use special code to get its value
|
|
|
|
if(bIsControl(lpUnknown))
|
|
return pGetOCX(psc,NULL,clsid,pCache,lpUnknown); //frees lpUnknown
|
|
|
|
ASSERT(lpRetDispatch != NULL);
|
|
if (lpRetDispatch != NULL)
|
|
return lpRetDispatch;
|
|
|
|
BadRunningClass:
|
|
*psc = sc;
|
|
return NULL;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::UpdateProperty
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Writes the value of a single property to an automation server.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// lFlags
|
|
// pClassInt
|
|
// PropName
|
|
// ProvObj
|
|
// pPackage
|
|
// pVar
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::UpdateProperty(
|
|
long lFlags,
|
|
IWbemClassObject FAR * pClassInt,
|
|
BSTR PropName,
|
|
CProvObj & ProvObj,
|
|
CObject * pPackage,
|
|
CVariant * pVar)
|
|
{
|
|
CVariant vIn;
|
|
SCODE sc;
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
// Get the property value
|
|
|
|
if(pClassInt)
|
|
{
|
|
sc = pClassInt->Get(PropName,lFlags,vIn.GetVarPtr(),NULL,NULL);
|
|
if(sc != S_OK)
|
|
return sc;
|
|
sc = vIn.ChangeType(VT_BSTR);
|
|
}
|
|
else if(pVar)
|
|
{
|
|
sc =OMSVariantChangeType(vIn.GetVarPtr(), pVar->GetVarPtr(),0, VT_BSTR);
|
|
}
|
|
else
|
|
sc = WBEM_E_FAILED;
|
|
if(sc != S_OK)
|
|
return sc;
|
|
|
|
|
|
|
|
LPDISPATCH pDisp = NULL;
|
|
CAutoCache * pCache = (CAutoCache *)pPackage;
|
|
|
|
// Do a second parse on the provider string.
|
|
|
|
CProvObj ObjectPath(ProvObj.sGetFullToken(1),DOT);
|
|
sc = ObjectPath.dwGetStatus(1);
|
|
if(sc != S_OK)
|
|
return sc;
|
|
|
|
// Get the IDispatch interface and then do the "Get"
|
|
|
|
int iDepth = ObjectPath.iGetNumTokens()-1;
|
|
pDisp = pGetDispatch(&sc,ObjectPath,ProvObj.sGetToken(0),pCache,iDepth);
|
|
if(pDisp)
|
|
{
|
|
int iLast = ObjectPath.iGetNumTokens()-1;
|
|
sc = DoCall(DISPATCH_PROPERTYPUT,ObjectPath,iLast,pDisp,VT_BSTR,vIn.GetBstr());
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::StartBatch
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called at the start of a batch of Refrest/Update Property calls. Initialize
|
|
// the handle cache.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// lFlags
|
|
// pClassInt
|
|
// **pObj
|
|
// bGet
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::StartBatch(
|
|
long lFlags,
|
|
IWbemClassObject FAR * pClassInt,
|
|
CObject **pObj,
|
|
BOOL bGet)
|
|
{
|
|
*pObj = new CAutoCache;
|
|
return (pObj != NULL) ? S_OK : WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void CImpAuto::StoreControl
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Used when an OCX is no longer being used and the OCX uses
|
|
// a stream to store its data.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// *pCache
|
|
//
|
|
//***************************************************************************
|
|
|
|
void CImpAuto::StoreControl(
|
|
CAutoCache *pCache)
|
|
{
|
|
SCODE sc;
|
|
LPSTORAGE pIStorage = NULL;
|
|
LPSTREAM pIStream = NULL;
|
|
LPPERSISTSTREAMINIT pPersStm = NULL;
|
|
USES_CONVERSION;
|
|
|
|
// Open up the storage file, create it if necessary
|
|
|
|
sc = StgIsStorageFile(T2OLE(gpStorageFile));
|
|
|
|
if(sc == S_OK)
|
|
sc = StgOpenStorage(T2OLE(gpStorageFile),NULL,
|
|
STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
|
|
NULL,0L, &pIStorage);
|
|
else if(sc == STG_E_FILENOTFOUND)
|
|
sc = StgCreateDocfile(T2OLE(gpStorageFile),
|
|
STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
|
|
0L, &pIStorage);
|
|
if(sc != S_OK)
|
|
return; //todo, error handling?????
|
|
|
|
// Open/Create the stream
|
|
|
|
sc = pIStorage->OpenStream(T2OLE(pCache->pSavePath),NULL,
|
|
STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
|
|
0,&pIStream);
|
|
if(sc == STG_E_FILENOTFOUND)
|
|
sc = pIStorage->CreateStream(T2OLE(pCache->pSavePath),
|
|
STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_FAILIFTHERE,
|
|
0,0,&pIStream);
|
|
if(sc != S_OK)
|
|
{
|
|
goto cleanupStoreControl;
|
|
}
|
|
sc = pCache->pSite->m_pObject->QueryInterface(IID_IPersistStreamInit,
|
|
(void **)&pPersStm);
|
|
if(!FAILED(sc))
|
|
pPersStm->Save(pIStream,TRUE);
|
|
|
|
cleanupStoreControl:
|
|
if(pPersStm)
|
|
pPersStm->Release();
|
|
if(pIStream)
|
|
pIStream->Release();
|
|
if(pIStorage)
|
|
pIStorage->Release();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
// Special version of CWnd which is used to hold OCXs. It automatically sets
|
|
// itself up as an OCX container and it also has a function to return pointer
|
|
// to the control container.
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CCtlWnd::CCtlWnd
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CCtlWnd::CCtlWnd()
|
|
{
|
|
RECT rect; rect.left = 0; rect.right = 50; rect.bottom = 100; rect.top = 0;
|
|
AfxEnableControlContainer();
|
|
HANDLE hh = afxCurrentInstanceHandle;
|
|
hh = AfxGetInstanceHandle();
|
|
Create(NULL,"");
|
|
InitControlContainer();
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::MakeEnum
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Creates a CEnumPerfInfo object which can be used for enumeration
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pClass
|
|
// ProvObj
|
|
// ppInfo
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::MakeEnum(
|
|
IWbemClassObject * pClass,
|
|
CProvObj & ProvObj,
|
|
CEnumInfo ** ppInfo)
|
|
{
|
|
SCODE sc;
|
|
*ppInfo = NULL;
|
|
LPDISPATCH pDisp = NULL;
|
|
CAutoCache Cache;
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
|
|
|
// Do a second parse on the provider string.
|
|
|
|
CProvObj ObjectPath(ProvObj.sGetFullToken(1),DOT);
|
|
sc = ObjectPath.dwGetStatus(1); //todo, is 1 ok??
|
|
if(sc != S_OK)
|
|
return sc;
|
|
|
|
// Get the IDispatch interface and then get thedo the "Get"
|
|
|
|
int iDepth = ObjectPath.iGetNumTokens();
|
|
pDisp = pGetDispatch(&sc,ObjectPath,ProvObj.sGetToken(0),&Cache,iDepth);
|
|
if(pDisp)
|
|
{
|
|
int iCount;
|
|
sc = DoCall(DISPATCH_PROPERTYGET,ObjectPath,0,pDisp,VT_I4,
|
|
&iCount,L"Count");
|
|
if(sc == S_OK)
|
|
{
|
|
// Create a new CEnumAutoInfo object.
|
|
CEnumAutoInfo * pInfo = new CEnumAutoInfo(iCount);
|
|
if(pInfo == NULL)
|
|
{
|
|
sc = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
*ppInfo = pInfo;
|
|
}
|
|
}
|
|
return sc;
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::GetKey
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pInfo
|
|
// iIndex
|
|
// ppKey
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::GetKey(
|
|
CEnumInfo * pInfo,
|
|
int iIndex,
|
|
LPWSTR * ppKey)
|
|
{
|
|
*ppKey = new WCHAR[10];
|
|
CEnumAutoInfo * pAuto = (CEnumAutoInfo *)pInfo;
|
|
if(iIndex >= pAuto->GetCount())
|
|
return WBEM_E_FAILED;
|
|
if(*ppKey == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
_itow(iIndex + 1,*ppKey,10);
|
|
return S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// SCODE CImpAuto::MergeStrings
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Combines the Class Context, Key, and Property Context strings.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// ppOut
|
|
// pClassContext
|
|
// pKey
|
|
// pPropContext
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
SCODE CImpAuto::MergeStrings(
|
|
LPWSTR * ppOut,
|
|
LPWSTR pClassContext,
|
|
LPWSTR pKey,
|
|
LPWSTR pPropContext)
|
|
{
|
|
|
|
// Allocate space for output
|
|
|
|
int iLen = 6;
|
|
if(pClassContext)
|
|
iLen += wcslen(pClassContext);
|
|
if(pKey)
|
|
iLen += wcslen(pKey);
|
|
if(pPropContext)
|
|
iLen += wcslen(pPropContext);
|
|
else
|
|
return WBEM_E_FAILED; // should always have this!
|
|
*ppOut = new WCHAR[iLen];
|
|
if(*ppOut == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
// simple case is that everything is in the property context. That would
|
|
// be the case when the provider is being used as a simple dynamic
|
|
// property provider
|
|
|
|
if(pClassContext == NULL || pKey == NULL)
|
|
{
|
|
wcscpy(*ppOut,pPropContext);
|
|
return S_OK;
|
|
}
|
|
|
|
// Copy the class context, property, and finally the key
|
|
|
|
wcscpy(*ppOut,pClassContext);
|
|
wcscat(*ppOut,L"(");
|
|
wcscat(*ppOut,pKey);
|
|
wcscat(*ppOut,L").");
|
|
wcscat(*ppOut,pPropContext);
|
|
return S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CEnumAutoInfo::CEnumAutoInfo
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// iCount
|
|
//
|
|
//***************************************************************************
|
|
|
|
CEnumAutoInfo::CEnumAutoInfo(
|
|
int iCount)
|
|
{
|
|
m_iCount = iCount;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CEnumAutoInfo::~CEnumAutoInfo
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CEnumAutoInfo::~CEnumAutoInfo()
|
|
{
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CImpAutoProp::CImpAutoProp
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CImpAutoProp::CImpAutoProp()
|
|
{
|
|
m_pImpDynProv = new CImpAuto();
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CImpAutoProp::~CImpAutoProp
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CImpAutoProp::~CImpAutoProp()
|
|
{
|
|
if(m_pImpDynProv)
|
|
delete m_pImpDynProv;
|
|
}
|