Source code of Windows XP (NT5)
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

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. PROVAUTO.CPP
  5. Abstract:
  6. Defines the acutal "Put" and "Get" functions for the
  7. Automation provider. The syntax of the mapping string is;
  8. "[path],[classid]|property
  9. History:
  10. a-davj 3-13-96 Created.
  11. --*/
  12. NOTE, THE ORIGINAL SERVER2.CPP HAS CODE TO INITIALIZE gpStorage and ghAutoMutex
  13. #include "precomp.h"
  14. #include "stdafx.h"
  15. #include <wbemidl.h>
  16. #include "afxpriv.h"
  17. #include "provauto.h"
  18. #include "cvariant.h"
  19. #define NOTFOUND -1
  20. extern TCHAR * gpStorageFile;
  21. extern CMyDLL theApp;
  22. //////////////////////////////////////////////////////////////////////////////
  23. // Special automation version of CHandleCache which also stores a hidden window,
  24. // site and path information. The hidden window also contains a COleContainer
  25. // object. Note that this extra information is only used by OCXs. The various
  26. // values are freed up by the CImpAuto::Free routine and so a destructor isnt
  27. // needed for this class.
  28. //***************************************************************************
  29. //
  30. // CAutoCache::CAutoCache
  31. //
  32. // DESCRIPTION:
  33. //
  34. // Constructor.
  35. //
  36. //***************************************************************************
  37. CAutoCache::CAutoCache ()
  38. {
  39. pSavePath = NULL;
  40. pSite = NULL;
  41. pCtlWnd = NULL;
  42. }
  43. //***************************************************************************
  44. //
  45. // SCODE CImpAuto::DoCall
  46. //
  47. // DESCRIPTION:
  48. //
  49. // Makes an IDispath Invoke call.
  50. //
  51. // PARAMETERS:
  52. //
  53. // wOpt
  54. // ProvObj
  55. // iIndex
  56. // pDisp
  57. // vt
  58. // pData
  59. // pProp
  60. //
  61. // RETURN VALUE:
  62. // Return: True if OK. If there is a problem, then the error code is set
  63. // in pMo in addition to having a FALSE return code.
  64. //
  65. //
  66. //***************************************************************************
  67. SCODE CImpAuto::DoCall(
  68. WORD wOpt,
  69. CProvObj & ProvObj,
  70. int iIndex,
  71. LPDISPATCH pDisp,
  72. VARTYPE vt,
  73. void * pData,
  74. WCHAR * pProp)
  75. {
  76. USES_CONVERSION;
  77. DISPID dispid;
  78. SCODE sc;
  79. COleDispatchDriver Disp;
  80. BYTE cArgTypes[MAX_ARGS+2]; // Extra for null terminator and for Put value
  81. void * Args[MAX_ARGS+1]; // Extra for put value
  82. int iNumArgs = 0,iExp;
  83. // Get the dispatch ID for property/method name
  84. OLECHAR * pArg;
  85. if(pProp == NULL)
  86. pArg = T2OLE(ProvObj.sGetToken(iIndex));
  87. else
  88. pArg = pProp;
  89. sc = pDisp->GetIDsOfNames(IID_NULL,&pArg,1,LOCALE_SYSTEM_DEFAULT,
  90. &dispid);
  91. if (sc != S_OK)
  92. return sc;
  93. // Get the arguments, if any, ready for the call
  94. memset(cArgTypes,0,MAX_ARGS+2);
  95. iNumArgs = ProvObj.iGetNumExp(iIndex);
  96. if(iNumArgs > MAX_ARGS)
  97. {
  98. return WBEM_E_FAILED; // too many arguments
  99. }
  100. for(iExp = 0; iExp < iNumArgs; iExp++)
  101. {
  102. // if the argument is a string, then create a BSTR and point to it. If the
  103. // argument is an integer, just typecast it into the argument array
  104. if(ProvObj.IsExpString(iIndex,iExp))
  105. {
  106. Args[iExp] = SysAllocString(T2OLE(ProvObj.sGetStringExp(iIndex,iExp)));
  107. if(Args[iExp] == NULL)
  108. {
  109. sc = WBEM_E_OUT_OF_MEMORY;
  110. goto DoInvokeCleanup;
  111. }
  112. cArgTypes[iExp] = VT_BSTR;
  113. }
  114. else
  115. {
  116. cArgTypes[iExp] = VT_I4;
  117. Args[iExp] = (void *)ProvObj.iGetIntExp(iIndex,iExp,0);
  118. }
  119. }
  120. // use the MFC automation driver to do the acual invoke
  121. Disp.AttachDispatch(pDisp);
  122. TRY
  123. {
  124. if((wOpt & DISPATCH_PROPERTYPUT) || (wOpt & DISPATCH_PROPERTYPUTREF))
  125. {
  126. cArgTypes[iNumArgs] = (BYTE)vt;
  127. Args[iNumArgs] = pData;
  128. Disp.InvokeHelper(dispid,wOpt,VT_EMPTY,NULL,cArgTypes,
  129. Args[0],Args[1],Args[2],Args[3],Args[4],Args[5]);
  130. }
  131. else
  132. Disp.InvokeHelper(dispid,wOpt,vt,pData,cArgTypes,
  133. Args[0],Args[1],Args[2],Args[3],Args[4],Args[5]);
  134. sc = S_OK;
  135. }
  136. CATCH(CException, e)
  137. {
  138. sc = WBEM_E_FAILED;
  139. }
  140. END_CATCH
  141. Disp.DetachDispatch();
  142. // This is used to clean up any BSTR strings that might have been allocated. This
  143. // can be skipped if it fails before any of the strings are allocated.
  144. DoInvokeCleanup:
  145. for(iExp = 0; iExp < iNumArgs; iExp++)
  146. if(cArgTypes[iExp] == VT_BSTR)
  147. SysFreeString((BSTR)Args[iExp]);
  148. return sc;
  149. }
  150. //***************************************************************************
  151. //
  152. // SCODE CImpAuto::GetCFileStreamObj
  153. //
  154. // DESCRIPTION:
  155. //
  156. // Some OCXs use a persistent stream to load and save data. This
  157. // routine gets a COleStreamFile object for such proposes.
  158. //
  159. // PARAMETERS:
  160. //
  161. // pPath
  162. // ppStorage
  163. // **ppFile
  164. // *pCache
  165. //
  166. // RETURN VALUE:
  167. //
  168. //
  169. //***************************************************************************
  170. SCODE CImpAuto::GetCFileStreamObj(
  171. const TCHAR * pPath,
  172. LPSTORAGE * ppStorage,
  173. COleStreamFile **ppFile,
  174. CAutoCache *pCache)
  175. {
  176. SCODE sc;
  177. USES_CONVERSION;
  178. *ppStorage = NULL;
  179. *ppFile = NULL;
  180. if(pPath == NULL) // Some OCXs dont need storage, this is OK.
  181. return S_OK;
  182. // Save Path in the cache
  183. ASSERT(pCache->pSavePath == NULL);
  184. pCache->pSavePath = new TCHAR[lstrlen(pPath) + 1];
  185. lstrcpy(pCache->pSavePath,pPath);
  186. // During first run after install, the compond file will not exist. This
  187. // is not as a problem as it will be created during the write
  188. sc = StgIsStorageFile(T2OLE(gpStorageFile));
  189. if(sc == STG_E_FILENOTFOUND)
  190. return S_OK;
  191. if(sc != S_OK)
  192. { // unusual failure!
  193. return sc;
  194. }
  195. // Open up the root storage. It should never fail since we just checked to make
  196. // sure the file is available.
  197. // TODO, might want to mutex control access to the storage
  198. sc = StgOpenStorage(T2OLE(gpStorageFile),NULL,STGM_READ|STGM_SHARE_DENY_WRITE,
  199. NULL,0l,ppStorage);
  200. if(FAILED(sc))
  201. {
  202. return WBEM_E_FAILED;
  203. }
  204. // Create a new COleStreamFile object and set the stream using the storage object.
  205. *ppFile = new COleStreamFile();
  206. if(*ppFile == NULL)
  207. {
  208. return WBEM_E_OUT_OF_MEMORY;
  209. }
  210. // Open a stream. Note that failure isnt unusual since this might be the
  211. // first time for the control.
  212. COleStreamFile * pFile = *ppFile;
  213. if(!pFile->OpenStream(*ppStorage,pPath,STGM_READ|STGM_SHARE_EXCLUSIVE))
  214. {
  215. delete *ppFile;
  216. *ppFile = NULL;
  217. }
  218. return S_OK;
  219. }
  220. //***************************************************************************
  221. //
  222. // BOOL CImpAuto::bIsControl
  223. //
  224. // DESCRIPTION:
  225. //
  226. // tests if the IUnknown is pointing to an object which is an OCX.
  227. //
  228. // PARAMETERS:
  229. //
  230. // lpTest
  231. //
  232. // RETURN VALUE:
  233. //
  234. //
  235. //***************************************************************************
  236. BOOL CImpAuto::bIsControl(
  237. LPUNKNOWN lpTest)
  238. {
  239. LPOLECONTROL lpCont = NULL;
  240. SCODE sc = lpTest->QueryInterface(IID_IOleControl,(LPVOID *) & lpCont);
  241. if(FAILED(sc) || lpCont == NULL)
  242. return FALSE;
  243. // Have an OCX, free up the pointer for now since it will be retireved by
  244. // the COleControlSite object later on
  245. lpCont->Release();
  246. return TRUE;
  247. }
  248. //***************************************************************************
  249. //
  250. // SCODE CImpAuto::ParsePathClass
  251. //
  252. // DESCRIPTION:
  253. //
  254. // Takes in a string in the sMix argument which is of the same for
  255. // as the arguments to VB's GetObject and parses the string. This routine
  256. // retrieves the path and class strings and determines the type. This could be;
  257. // "path","class" (Type BOTH) or
  258. // "path" (Type PATH) or
  259. // "","class" (Type NEWCLASS) or
  260. // ,"class" (Type RUNNINGCLASS)
  261. //
  262. // PARAMETERS:
  263. //
  264. // sMix
  265. // sPath
  266. // sClass
  267. // type
  268. //
  269. // RETURN VALUE:
  270. //
  271. //
  272. //***************************************************************************
  273. SCODE CImpAuto::ParsePathClass(
  274. const CString & sMix,
  275. CString & sPath,
  276. CString & sClass,
  277. OBJTYPE * type)
  278. {
  279. int iLen = sMix.GetLength();
  280. int iFstst = NOTFOUND; // first quote of the first string
  281. int iFsten = NOTFOUND; // last quote of the last string
  282. int iSecst = NOTFOUND; // first quote of the second string
  283. int iSecen = NOTFOUND; // last quote of the second string
  284. int iCommaPos = NOTFOUND; // position of comma between strings
  285. int iIndex;
  286. int iNumSoFar = 0; // number of '"' found so far
  287. // Go through the string and find the starting and ending '"' of the path string
  288. // and possibly the class string. Note the location of the comma.
  289. for(iIndex = 0; iIndex < iLen; iIndex++)
  290. {
  291. if(sMix[iIndex] == DQUOTE)
  292. {
  293. iNumSoFar++;
  294. if(iFstst == NOTFOUND && iCommaPos == NOTFOUND)
  295. iFstst = iIndex;
  296. if(iCommaPos == NOTFOUND)
  297. iFsten = iIndex;
  298. if(iSecst == NOTFOUND && iCommaPos != NOTFOUND)
  299. iSecst = iIndex;
  300. if(iCommaPos != NOTFOUND)
  301. iSecen = iIndex;
  302. }
  303. if(sMix[iIndex] == SEPARATOR && (iNumSoFar%2 == 0) && iCommaPos == NOTFOUND)
  304. iCommaPos = iIndex;
  305. }
  306. // Verify that there were an even number of quotes.
  307. if(iNumSoFar%2 || iNumSoFar == 0)
  308. {
  309. return WBEM_E_FAILED; // odd number of quotes is bad
  310. }
  311. // Extract the strings.
  312. for(iIndex = iFstst+1; iIndex < iFsten; iIndex++)
  313. {
  314. sPath += sMix[iIndex];
  315. // if there is a "" in the string, copy just the first
  316. if(sMix[iIndex] == DQUOTE)
  317. iIndex++;
  318. }
  319. for(iIndex = iSecst+1; iIndex < iSecen; iIndex++)
  320. {
  321. sClass += sMix[iIndex];
  322. // if there is a "" in the string, copy just the first
  323. if(sMix[iIndex] == DQUOTE)
  324. iIndex++;
  325. }
  326. // make sure that something was retrieved!
  327. if(sPath.GetLength() < 1 && sClass.GetLength() < 1)
  328. {
  329. return WBEM_E_FAILED; // didnt get any data!
  330. }
  331. // figure out what type of request
  332. if(sPath.GetLength() > 0 && sClass.GetLength() > 0)
  333. *type = BOTH;
  334. else if(sPath.GetLength() > 0 && sClass.GetLength() == 0)
  335. *type = PATH;
  336. else if(sPath.GetLength() == 0 && sClass.GetLength() > 0 && iFstst != NOTFOUND)
  337. *type = NEWCLASS;
  338. else if(sPath.GetLength() == 0 && sClass.GetLength() > 0 && iFstst == NOTFOUND)
  339. *type = RUNNINGCLASS;
  340. else
  341. {
  342. return WBEM_E_FAILED; // got some sort of junk!
  343. }
  344. return S_OK; // all is well
  345. }
  346. //***************************************************************************
  347. //
  348. // CImpAuto::CImpAuto
  349. //
  350. // DESCRIPTION:
  351. //
  352. // Constructor.
  353. //
  354. // PARAMETERS:
  355. //
  356. // ObjectPath
  357. // User
  358. // Password
  359. //
  360. //***************************************************************************
  361. CImpAuto::CImpAuto()
  362. {
  363. wcscpy(wcCLSID,L"{DAC651D1-7CC7-11cf-A5B6-00AA00680C3F}");
  364. }
  365. //***************************************************************************
  366. // void CImpAuto::EndBatch
  367. //
  368. // DESCRIPTION:
  369. //
  370. // Called at the end of a batch of Refrest/Update Property calls. Free up
  371. // any cached handles and then delete the handle cache.
  372. //
  373. // PARAMETERS:
  374. //
  375. // lFlags
  376. // pClassInt
  377. // *pObj
  378. // bGet
  379. //
  380. // RETURN VALUE:
  381. //
  382. //
  383. //***************************************************************************
  384. void CImpAuto::EndBatch(
  385. long lFlags,
  386. IWbemClassObject FAR * pClassInt,
  387. CObject *pObj,
  388. BOOL bGet)
  389. {
  390. if(pObj != NULL)
  391. {
  392. Free(0,(CAutoCache *)pObj);
  393. delete pObj;
  394. }
  395. }
  396. //***************************************************************************
  397. //
  398. // void CImpAuto::Free
  399. //
  400. // DESCRIPTION:
  401. //
  402. // Frees up cached IDispatch interfaces starting with position
  403. // iStart till the end. After freeing handles, the cache object
  404. // member function is used to delete the cache entries.
  405. //
  406. // PARAMETERS:
  407. //
  408. // iStart
  409. // pCache
  410. //
  411. // RETURN VALUE:
  412. //
  413. //
  414. //***************************************************************************
  415. void CImpAuto::Free(
  416. int iStart,
  417. CAutoCache * pCache)
  418. {
  419. int iCurr;
  420. LPOLEOBJECT pTemp = NULL;
  421. AFX_MANAGE_STATE(AfxGetStaticModuleState())
  422. for(iCurr = pCache->lGetNumEntries()-1; iCurr >= iStart; iCurr--)
  423. {
  424. LPDISPATCH pDisp = (LPDISPATCH)pCache->hGetHandle(iCurr);
  425. if(pDisp != NULL)
  426. pDisp->Release();
  427. }
  428. pCache->Delete(iStart); // get cache to delete the entries
  429. if(iStart == 0)
  430. {
  431. if(pCache->pSavePath)
  432. {
  433. if(pCache->pSite)
  434. {
  435. DWORD dwRet;
  436. dwRet = WaitForSingleObject(ghAutoMutex,MAX_AUTO_WAIT);
  437. if(dwRet == WAIT_ABANDONED || dwRet == WAIT_OBJECT_0)
  438. {
  439. try
  440. {
  441. StoreControl(pCache);
  442. }
  443. catch(...) {}
  444. ReleaseMutex(ghAutoMutex);
  445. }
  446. }
  447. delete pCache->pSavePath;
  448. pCache->pSavePath = NULL;
  449. }
  450. if(pCache->pCtlWnd != NULL)
  451. {
  452. // DONOT delete the Site object since the Control container does it!!
  453. // Note important HACK! There is a bug in the MFC that ships with VC 4.0.
  454. // The COleControlSite::CreateOrLoad routine has a QueryInterface call
  455. // to get an IPersistMemory interface, BUT DOES NOT RELEASE IT! So, to
  456. // release it, there is a bit of code here to call release until the count
  457. // goes to 0.
  458. if(pCache->pSite)
  459. {
  460. pTemp = pCache->pSite->m_pObject;
  461. pTemp->AddRef();
  462. }
  463. pCache->pCtlWnd->DestroyWindow(); // note that DestroyWindow frees up the object
  464. pCache->pCtlWnd = NULL; // and gets rid of the container within
  465. // First release for the AddRef right above. Second possible release is
  466. // for the bug!
  467. if(pCache->pSite && pTemp)
  468. {
  469. DWORD dwRes = pTemp->Release();
  470. if(dwRes > 0)
  471. pTemp->Release();
  472. }
  473. }
  474. pCache->pSite = NULL;
  475. }
  476. }
  477. //***************************************************************************
  478. //
  479. // SCODE CImpAuto::RefreshProperty
  480. //
  481. // DESCRIPTION:
  482. //
  483. // Gets the value of a single property from an automation server.
  484. //
  485. // PARAMETERS:
  486. //
  487. // lFlags
  488. // pClassInt
  489. // PropName
  490. // ProvObj
  491. // pPackage
  492. // pVar
  493. //
  494. // RETURN VALUE:
  495. //
  496. //
  497. //***************************************************************************
  498. SCODE CImpAuto::RefreshProperty(
  499. long lFlags,
  500. IWbemClassObject FAR * pClassInt,
  501. BSTR PropName,
  502. CProvObj & ProvObj,
  503. CObject * pPackage,
  504. CVariant * pVar)
  505. {
  506. SCODE sc;
  507. USES_CONVERSION;
  508. CString sRet;
  509. LPDISPATCH pDisp = NULL;
  510. CAutoCache * pCache = (CAutoCache *)pPackage;
  511. AFX_MANAGE_STATE(AfxGetStaticModuleState())
  512. // Do a second parse on the provider string.
  513. CProvObj ObjectPath(ProvObj.sGetFullToken(1),DOT);
  514. sc = ObjectPath.dwGetStatus(1); //todo, is 1 ok??
  515. if(sc != S_OK)
  516. return sc;
  517. // Get the IDispatch interface and then do the "Get"
  518. int iDepth = ObjectPath.iGetNumTokens()-1;
  519. HINSTANCE hTest = afxCurrentInstanceHandle;
  520. pDisp = pGetDispatch(&sc,ObjectPath,ProvObj.sGetToken(0),pCache,iDepth);
  521. if(pDisp)
  522. {
  523. int iLast = ObjectPath.iGetNumTokens()-1;
  524. sc = DoCall(DISPATCH_PROPERTYGET,ObjectPath,iLast,pDisp,VT_BSTR,&sRet);
  525. if(sc == S_OK)
  526. {
  527. CVariant varAuto;
  528. sc = varAuto.SetData(T2OLE(sRet),VT_LPWSTR);
  529. if(sc != S_OK)
  530. return sc;
  531. sc = varAuto.DoPut(lFlags,pClassInt,PropName,pVar);
  532. }
  533. }
  534. return sc;
  535. }
  536. //***************************************************************************
  537. //
  538. // LPDISPATCH CImpAuto::pGetBoth
  539. //
  540. // DESCRIPTION:
  541. //
  542. // Gets IDISPATCH interface to the server using path and class.
  543. //
  544. // PARAMETERS:
  545. //
  546. // psc
  547. // pPath
  548. // pClass
  549. // *pCache
  550. //
  551. // RETURN VALUE:
  552. //
  553. //
  554. //***************************************************************************
  555. LPDISPATCH CImpAuto::pGetBoth(
  556. SCODE * psc,
  557. const TCHAR * pPath,
  558. const TCHAR * pClass,
  559. CAutoCache *pCache)
  560. {
  561. HRESULT sc;
  562. USES_CONVERSION;
  563. CLSID clsid;
  564. LPDISPATCH lpRetDispatch = NULL;
  565. LPUNKNOWN lpUnknown = NULL;
  566. LPPERSISTFILE lpPersist = NULL;
  567. sc = CLSIDFromProgID(T2OLE(pClass), &clsid);
  568. if (FAILED(sc))
  569. goto BadBoth;
  570. // create an instance with the IUnknown
  571. sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (LPVOID *)&lpUnknown);
  572. if (FAILED(sc))
  573. goto BadBoth;
  574. OleRun(lpUnknown); // Some objects need this!
  575. // If the class is an OCX, then use special code to get its value
  576. if(bIsControl(lpUnknown))
  577. {
  578. DWORD dwRet;
  579. dwRet = WaitForSingleObject(ghAutoMutex,MAX_AUTO_WAIT);
  580. if(dwRet == WAIT_ABANDONED || dwRet == WAIT_OBJECT_0)
  581. {
  582. try
  583. {
  584. lpRetDispatch = pGetOCX(psc,pPath,clsid,pCache,lpUnknown); //frees lpUnknown
  585. }
  586. catch(...)
  587. {
  588. lpRetDispatch = NULL;
  589. }
  590. ReleaseMutex(ghAutoMutex);
  591. }
  592. else
  593. *psc = WBEM_E_FAILED;
  594. return lpRetDispatch;
  595. }
  596. // query for persist file interface
  597. sc = lpUnknown->QueryInterface(IID_IPersistFile,(LPVOID *)&lpPersist);
  598. lpUnknown->Release();
  599. if (FAILED(sc))
  600. goto BadBoth;
  601. // do a sanity check, probably not necessary.
  602. ASSERT(lpPersist != NULL);
  603. if (lpPersist == NULL)
  604. {
  605. sc = WBEM_E_FAILED;
  606. goto BadBoth;
  607. }
  608. // Load up the desired file
  609. sc = lpPersist->Load(T2OLE(pPath),0);
  610. if (FAILED(sc))
  611. goto BadBoth;
  612. sc = lpPersist->QueryInterface(IID_IDispatch,(LPVOID *)&lpRetDispatch);
  613. lpPersist->Release();
  614. if (FAILED(sc))
  615. goto BadBoth;
  616. ASSERT(lpRetDispatch != NULL);
  617. if (lpRetDispatch != NULL)
  618. return lpRetDispatch;
  619. BadBoth:
  620. if(lpPersist != NULL)
  621. lpPersist->Release();
  622. *psc = sc;
  623. return NULL;
  624. }
  625. //***************************************************************************
  626. //
  627. // LPDISPATCH CImpAuto::pGetDispatch
  628. //
  629. // DESCRIPTION:
  630. //
  631. // Gets get the IDispatch for gets and sets
  632. //
  633. // PARAMETERS:
  634. //
  635. // psc
  636. // ObjectPath
  637. // pPathClass
  638. // *pCache
  639. // iDepth
  640. //
  641. // RETURN VALUE:
  642. //
  643. //
  644. //***************************************************************************
  645. LPDISPATCH CImpAuto::pGetDispatch(
  646. SCODE * psc,
  647. CProvObj & ObjectPath,
  648. LPCTSTR pPathClass,
  649. CAutoCache *pCache,
  650. int iDepth)
  651. {
  652. LPDISPATCH pRetDisp;
  653. int iNumSkip;
  654. int iIndex;
  655. // Get at least the application interface. If the object path is in common with
  656. // previous calls, then some of the subobject are already set and that is
  657. // indicated by the value in iNumSkip;
  658. pRetDisp = pGetDispatchRoot(psc,ObjectPath,pPathClass,pCache,iNumSkip);
  659. // For each subobject that wasnt in the cache, get its IDispatch, and add it
  660. // to the cache.
  661. for(iIndex = iNumSkip; iIndex < iDepth && pRetDisp; iIndex++)
  662. {
  663. LPDISPATCH pNewDisp;
  664. *psc = DoCall(DISPATCH_PROPERTYGET,ObjectPath,iIndex,
  665. pRetDisp,VT_DISPATCH,&pNewDisp);
  666. if(*psc != S_OK)
  667. return NULL;
  668. *psc = pCache->lAddToList(ObjectPath.sGetFullToken(iIndex),pNewDisp);
  669. if(*psc != S_OK)
  670. return NULL;
  671. pRetDisp = pNewDisp;
  672. }
  673. return pRetDisp;
  674. }
  675. //***************************************************************************
  676. //
  677. // LPDISPATCH CImpAuto::pGetDispatchRoot
  678. //
  679. // DESCRIPTION:
  680. //
  681. // Gets the interface to the application object or some other starting point
  682. // such as a "document" object.
  683. //
  684. // PARAMETERS:
  685. //
  686. // psc
  687. // ObjectPath
  688. // pPathClass
  689. // *pCache
  690. // iNumSkip
  691. //
  692. // RETURN VALUE:
  693. //
  694. //
  695. //***************************************************************************
  696. LPDISPATCH CImpAuto::pGetDispatchRoot(
  697. SCODE * psc,
  698. CProvObj & ObjectPath,
  699. LPCTSTR pPathClass,
  700. CAutoCache *pCache,
  701. int & iNumSkip)
  702. {
  703. iNumSkip = 0;
  704. LPDISPATCH pRetDisp = NULL;
  705. OBJTYPE type;
  706. HKEY hRoot = NULL;
  707. const TCHAR * pObject = ObjectPath.sGetFullToken(0);
  708. if(pPathClass == NULL || pObject == NULL)
  709. {
  710. *psc = WBEM_E_FAILED; // bad mapping string
  711. return NULL;
  712. }
  713. // If there are handles in the cache, then they may be used if and
  714. // only if the path/class matches.
  715. if(pCache->lGetNumEntries() > 0)
  716. {
  717. if(lstrcmpi(pCache->sGetString(0),pPathClass))
  718. // The path/class has changed.free all the cached handles.
  719. Free(0,pCache);
  720. else
  721. {
  722. // The Path/class matches what is in the cache. Determine how much
  723. // else is in common, free what isnt in common, and return
  724. // the subkey share a common path.
  725. iNumSkip = pCache->lGetNumMatch(1,0,ObjectPath);
  726. Free(1+iNumSkip,pCache);
  727. return (LPDISPATCH )pCache->hGetHandle(iNumSkip);
  728. }
  729. }
  730. // Need to get the initial IDispatch handle. Start off by breaking up
  731. // path/class string. Note that TRY/CATCH is used since
  732. // bParsePathClass does CString allocations which can give exceptions.
  733. CString sPath,sClass;
  734. TRY
  735. {
  736. *psc = ParsePathClass(pPathClass,sPath,sClass,&type);
  737. if(*psc != S_OK)
  738. return NULL; // bad string, actual error set in bParsePathClass
  739. }
  740. CATCH(CException, e)
  741. {
  742. *psc = WBEM_E_OUT_OF_MEMORY;
  743. return NULL;
  744. }
  745. END_CATCH
  746. // Based on the path/class combination, call the correct routine to
  747. // actually hook up to the server.
  748. switch(type)
  749. {
  750. case BOTH:
  751. pRetDisp = pGetBoth(psc,sPath,sClass,pCache);
  752. break;
  753. case PATH:
  754. pRetDisp = pGetPath(psc,sPath);
  755. break;
  756. case NEWCLASS:
  757. pRetDisp = pGetNewClass(psc,sClass,pCache);
  758. break;
  759. case RUNNINGCLASS:
  760. pRetDisp = pGetRunningClass(psc,sClass,pCache);
  761. break;
  762. default:
  763. *psc = WBEM_E_FAILED;
  764. }
  765. if(pRetDisp == NULL)
  766. return NULL;
  767. // Got the initial IDispatch interface. Add it to the Cache
  768. *psc = pCache->lAddToList(pPathClass,pRetDisp);
  769. if(*psc != S_OK)
  770. { // error adding to cache, probably memory
  771. pRetDisp->Release();
  772. return NULL;
  773. }
  774. return pRetDisp; // all is well!
  775. }
  776. //***************************************************************************
  777. //
  778. // LPDISPATCH CImpAuto::pGetNewClass
  779. //
  780. // DESCRIPTION:
  781. //
  782. // Gets IDISPATCH interface to the server using the class id and always
  783. // creates a new object.
  784. //
  785. // PARAMETERS:
  786. //
  787. // psc
  788. // pClass
  789. // *pCache
  790. //
  791. // RETURN VALUE:
  792. //
  793. //
  794. //***************************************************************************
  795. LPDISPATCH CImpAuto::pGetNewClass(
  796. SCODE * psc,
  797. const TCHAR * pClass,
  798. CAutoCache *pCache)
  799. {
  800. HRESULT sc;
  801. CLSID clsid;
  802. USES_CONVERSION;
  803. LPDISPATCH lpRetDispatch = NULL;
  804. LPUNKNOWN lpUnknown = NULL;
  805. sc = CLSIDFromProgID(T2OLE(pClass), &clsid);
  806. if (FAILED(sc))
  807. goto BadNewClass;
  808. // create an instance with the IUnknown
  809. sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (LPVOID *)&lpUnknown);
  810. if (FAILED(sc))
  811. goto BadNewClass;
  812. OleRun(lpUnknown);
  813. // If the class is an OCX, then use special code to get its value
  814. if(bIsControl(lpUnknown))
  815. {
  816. DWORD dwRet;
  817. dwRet = WaitForSingleObject(ghAutoMutex,MAX_AUTO_WAIT);
  818. if(dwRet == WAIT_ABANDONED || dwRet == WAIT_OBJECT_0)
  819. {
  820. try
  821. {
  822. lpRetDispatch = pGetOCX(psc,NULL,clsid,pCache,lpUnknown); //frees lpUnknown
  823. }
  824. catch(...)
  825. { lpRetDispatch = NULL;
  826. }
  827. ReleaseMutex(ghAutoMutex);
  828. }
  829. else
  830. *psc = WBEM_E_FAILED;
  831. return lpRetDispatch;
  832. }
  833. // query for IDispatch interface
  834. sc = lpUnknown->QueryInterface(IID_IDispatch,(LPVOID *)&lpRetDispatch);
  835. lpUnknown->Release();
  836. if (FAILED(sc))
  837. goto BadNewClass;
  838. ASSERT(lpRetDispatch != NULL);
  839. return lpRetDispatch;
  840. BadNewClass:
  841. *psc = sc;
  842. return NULL;
  843. }
  844. //***************************************************************************
  845. //
  846. // LPDISPATCH CImpAuto::pGetOCX
  847. //
  848. // DESCRIPTION:
  849. //
  850. // Gets IDISPATCH interface to an OCX. Note that the lpUnk should be
  851. // released at the end of the routine so that the server will
  852. // continue running even as it is setup as a control!
  853. //
  854. // PARAMETERS:
  855. //
  856. // psc
  857. // pPath
  858. // clsid
  859. // *pCache
  860. // lpUnk
  861. //
  862. // RETURN VALUE:
  863. //
  864. //
  865. //***************************************************************************
  866. LPDISPATCH CImpAuto::pGetOCX(
  867. SCODE * psc,
  868. const TCHAR * pPath,
  869. CLSID & clsid,
  870. CAutoCache *pCache,
  871. LPUNKNOWN lpUnk)
  872. {
  873. RECT rect;
  874. rect.left = 0; rect.right = 150; rect.top = 0; rect.bottom = 150;
  875. LPDISPATCH lpRetDispatch = NULL;
  876. COleControlContainer * pCont = NULL;
  877. BOOL bOK;
  878. SCODE sc;
  879. LPSTORAGE pStorage = NULL;
  880. COleStreamFile * pFileStream = NULL;
  881. // Possibly create a COleStreamFile object. This is done only if the pPath is
  882. // not NULL and if everything exists. This routine must release the pStorage
  883. // interface and the pFileStream objects if the are created!
  884. *psc = GetCFileStreamObj(pPath, &pStorage, &pFileStream,pCache);
  885. if(*psc != S_OK)
  886. goto EndpGetOCX;
  887. // Create the window that will contain the controls. The window's contstructor
  888. // creates the COleContainer object.
  889. pCache->pCtlWnd = new CCtlWnd();
  890. if(pCache->pCtlWnd == NULL)
  891. {
  892. *psc = WBEM_E_OUT_OF_MEMORY;
  893. goto EndpGetOCX;
  894. }
  895. pCont = pCache->pCtlWnd->pGetCont();
  896. // Do quick sanity check, shouldnt fail
  897. if(pCont == NULL)
  898. {
  899. *psc = WBEM_E_FAILED;
  900. goto EndpGetOCX;
  901. }
  902. // Use the control container to create the site and control in one call
  903. bOK = pCont->CreateControl(NULL, clsid, NULL,WS_CHILD,
  904. rect, 23, pFileStream, FALSE,
  905. NULL, &pCache->pSite);
  906. if(!bOK || pCache->pSite == NULL)
  907. {
  908. pCache->pSite = NULL;
  909. *psc = WBEM_E_FAILED;
  910. goto EndpGetOCX;
  911. }
  912. // query for IDispatch interface
  913. sc = pCache->pSite->m_pObject->QueryInterface(IID_IDispatch,
  914. (LPVOID *)&lpRetDispatch);
  915. if (FAILED(sc))
  916. {
  917. *psc = sc;
  918. lpRetDispatch = NULL;
  919. }
  920. EndpGetOCX:
  921. if(pFileStream)
  922. {
  923. pFileStream->Close();
  924. delete pFileStream;
  925. }
  926. if(pStorage)
  927. pStorage->Release();
  928. if(lpUnk)
  929. lpUnk->Release();
  930. return lpRetDispatch;
  931. }
  932. //***************************************************************************
  933. //
  934. // LPDISPATCH CImpAuto::pGetPath
  935. //
  936. // DESCRIPTION:
  937. //
  938. // Gets IDISPATCH interface to the server using the path.
  939. //
  940. // PARAMETERS:
  941. //
  942. // psc
  943. // pPath
  944. //
  945. // RETURN VALUE:
  946. //
  947. //
  948. //***************************************************************************
  949. LPDISPATCH CImpAuto::pGetPath(
  950. SCODE * psc,
  951. const TCHAR * pPath)
  952. {
  953. HRESULT sc;
  954. LPBC pbc=NULL;
  955. LPDISPATCH lpRetDispatch = NULL;
  956. USES_CONVERSION;
  957. LPMONIKER pmk;
  958. pmk=NULL;
  959. DWORD dwEat;
  960. // Get a bind context object.
  961. sc = CreateBindCtx(0, &pbc);
  962. if (FAILED(sc))
  963. {
  964. *psc = sc;
  965. return NULL;
  966. }
  967. // Get a moniker
  968. sc = MkParseDisplayName(pbc, T2OLE(pPath), &dwEat, &pmk);
  969. if (FAILED(sc))
  970. goto BadPath;
  971. // Bind the moniker
  972. sc = (pmk)->BindToObject(pbc, NULL, IID_IDispatch
  973. , (void **)&lpRetDispatch);
  974. pmk->Release();
  975. if(FAILED(sc))
  976. goto BadPath;
  977. ASSERT(lpRetDispatch != NULL);
  978. // If the class is an OCX, then something is wrong here.
  979. if(bIsControl(lpRetDispatch))
  980. {
  981. *psc = WBEM_E_FAILED;
  982. lpRetDispatch->Release();
  983. return NULL;
  984. }
  985. if(lpRetDispatch)
  986. { // should always be true at this point!
  987. pbc->Release();
  988. return lpRetDispatch;
  989. }
  990. sc = WBEM_E_FAILED;
  991. BadPath:
  992. if(pbc)
  993. pbc->Release();
  994. *psc = sc;
  995. return NULL;
  996. }
  997. //***************************************************************************
  998. //
  999. // LPDISPATCH CImpAuto::pGetRunningClass
  1000. //
  1001. // DESCRIPTION:
  1002. //
  1003. // Gets IDISPATCH interface to the server using the class id and always
  1004. // returns only running objects.
  1005. //
  1006. // PARAMETERS:
  1007. //
  1008. // psc
  1009. // pClass
  1010. // *pCache
  1011. //
  1012. // RETURN VALUE:
  1013. //
  1014. //
  1015. //***************************************************************************
  1016. LPDISPATCH CImpAuto::pGetRunningClass(
  1017. SCODE * psc,
  1018. const TCHAR * pClass,
  1019. CAutoCache *pCache)
  1020. {
  1021. HRESULT sc;
  1022. CLSID clsid;
  1023. LPDISPATCH lpRetDispatch = NULL;
  1024. USES_CONVERSION;
  1025. LPUNKNOWN lpUnknown = NULL;
  1026. sc = CLSIDFromProgID(T2OLE(pClass), &clsid);
  1027. if (FAILED(sc))
  1028. goto BadRunningClass;
  1029. // create an instance with the IUnknown
  1030. sc = GetActiveObject(clsid,NULL,&lpUnknown);
  1031. if (FAILED(sc))
  1032. goto BadRunningClass;
  1033. // query for IDispatch interface
  1034. sc = lpUnknown->QueryInterface(IID_IDispatch,(LPVOID *)&lpRetDispatch);
  1035. lpUnknown->Release();
  1036. if (FAILED(sc))
  1037. goto BadRunningClass;
  1038. // If the class is an OCX, then use special code to get its value
  1039. if(bIsControl(lpUnknown))
  1040. return pGetOCX(psc,NULL,clsid,pCache,lpUnknown); //frees lpUnknown
  1041. ASSERT(lpRetDispatch != NULL);
  1042. if (lpRetDispatch != NULL)
  1043. return lpRetDispatch;
  1044. BadRunningClass:
  1045. *psc = sc;
  1046. return NULL;
  1047. }
  1048. //***************************************************************************
  1049. //
  1050. // SCODE CImpAuto::UpdateProperty
  1051. //
  1052. // DESCRIPTION:
  1053. //
  1054. // Writes the value of a single property to an automation server.
  1055. //
  1056. // PARAMETERS:
  1057. //
  1058. // lFlags
  1059. // pClassInt
  1060. // PropName
  1061. // ProvObj
  1062. // pPackage
  1063. // pVar
  1064. //
  1065. // RETURN VALUE:
  1066. //
  1067. //
  1068. //***************************************************************************
  1069. SCODE CImpAuto::UpdateProperty(
  1070. long lFlags,
  1071. IWbemClassObject FAR * pClassInt,
  1072. BSTR PropName,
  1073. CProvObj & ProvObj,
  1074. CObject * pPackage,
  1075. CVariant * pVar)
  1076. {
  1077. CVariant vIn;
  1078. SCODE sc;
  1079. AFX_MANAGE_STATE(AfxGetStaticModuleState())
  1080. // Get the property value
  1081. if(pClassInt)
  1082. {
  1083. sc = pClassInt->Get(PropName,lFlags,vIn.GetVarPtr(),NULL,NULL);
  1084. if(sc != S_OK)
  1085. return sc;
  1086. sc = vIn.ChangeType(VT_BSTR);
  1087. }
  1088. else if(pVar)
  1089. {
  1090. sc =OMSVariantChangeType(vIn.GetVarPtr(), pVar->GetVarPtr(),0, VT_BSTR);
  1091. }
  1092. else
  1093. sc = WBEM_E_FAILED;
  1094. if(sc != S_OK)
  1095. return sc;
  1096. LPDISPATCH pDisp = NULL;
  1097. CAutoCache * pCache = (CAutoCache *)pPackage;
  1098. // Do a second parse on the provider string.
  1099. CProvObj ObjectPath(ProvObj.sGetFullToken(1),DOT);
  1100. sc = ObjectPath.dwGetStatus(1);
  1101. if(sc != S_OK)
  1102. return sc;
  1103. // Get the IDispatch interface and then do the "Get"
  1104. int iDepth = ObjectPath.iGetNumTokens()-1;
  1105. pDisp = pGetDispatch(&sc,ObjectPath,ProvObj.sGetToken(0),pCache,iDepth);
  1106. if(pDisp)
  1107. {
  1108. int iLast = ObjectPath.iGetNumTokens()-1;
  1109. sc = DoCall(DISPATCH_PROPERTYPUT,ObjectPath,iLast,pDisp,VT_BSTR,vIn.GetBstr());
  1110. }
  1111. return sc;
  1112. }
  1113. //***************************************************************************
  1114. //
  1115. // SCODE CImpAuto::StartBatch
  1116. //
  1117. // DESCRIPTION:
  1118. //
  1119. // Called at the start of a batch of Refrest/Update Property calls. Initialize
  1120. // the handle cache.
  1121. //
  1122. // PARAMETERS:
  1123. //
  1124. // lFlags
  1125. // pClassInt
  1126. // **pObj
  1127. // bGet
  1128. //
  1129. // RETURN VALUE:
  1130. //
  1131. //
  1132. //***************************************************************************
  1133. SCODE CImpAuto::StartBatch(
  1134. long lFlags,
  1135. IWbemClassObject FAR * pClassInt,
  1136. CObject **pObj,
  1137. BOOL bGet)
  1138. {
  1139. *pObj = new CAutoCache;
  1140. return (pObj != NULL) ? S_OK : WBEM_E_OUT_OF_MEMORY;
  1141. }
  1142. //***************************************************************************
  1143. //
  1144. // void CImpAuto::StoreControl
  1145. //
  1146. // DESCRIPTION:
  1147. //
  1148. // Used when an OCX is no longer being used and the OCX uses
  1149. // a stream to store its data.
  1150. //
  1151. // PARAMETERS:
  1152. //
  1153. // *pCache
  1154. //
  1155. //***************************************************************************
  1156. void CImpAuto::StoreControl(
  1157. CAutoCache *pCache)
  1158. {
  1159. SCODE sc;
  1160. LPSTORAGE pIStorage = NULL;
  1161. LPSTREAM pIStream = NULL;
  1162. LPPERSISTSTREAMINIT pPersStm = NULL;
  1163. USES_CONVERSION;
  1164. // Open up the storage file, create it if necessary
  1165. sc = StgIsStorageFile(T2OLE(gpStorageFile));
  1166. if(sc == S_OK)
  1167. sc = StgOpenStorage(T2OLE(gpStorageFile),NULL,
  1168. STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1169. NULL,0L, &pIStorage);
  1170. else if(sc == STG_E_FILENOTFOUND)
  1171. sc = StgCreateDocfile(T2OLE(gpStorageFile),
  1172. STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
  1173. 0L, &pIStorage);
  1174. if(sc != S_OK)
  1175. return; //todo, error handling?????
  1176. // Open/Create the stream
  1177. sc = pIStorage->OpenStream(T2OLE(pCache->pSavePath),NULL,
  1178. STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  1179. 0,&pIStream);
  1180. if(sc == STG_E_FILENOTFOUND)
  1181. sc = pIStorage->CreateStream(T2OLE(pCache->pSavePath),
  1182. STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_FAILIFTHERE,
  1183. 0,0,&pIStream);
  1184. if(sc != S_OK)
  1185. {
  1186. goto cleanupStoreControl;
  1187. }
  1188. sc = pCache->pSite->m_pObject->QueryInterface(IID_IPersistStreamInit,
  1189. (void **)&pPersStm);
  1190. if(!FAILED(sc))
  1191. pPersStm->Save(pIStream,TRUE);
  1192. cleanupStoreControl:
  1193. if(pPersStm)
  1194. pPersStm->Release();
  1195. if(pIStream)
  1196. pIStream->Release();
  1197. if(pIStorage)
  1198. pIStorage->Release();
  1199. }
  1200. /////////////////////////////////////////////////////////////////////////////////
  1201. // Special version of CWnd which is used to hold OCXs. It automatically sets
  1202. // itself up as an OCX container and it also has a function to return pointer
  1203. // to the control container.
  1204. //***************************************************************************
  1205. //
  1206. // CCtlWnd::CCtlWnd
  1207. //
  1208. // DESCRIPTION:
  1209. //
  1210. // Constructor.
  1211. //
  1212. //***************************************************************************
  1213. CCtlWnd::CCtlWnd()
  1214. {
  1215. RECT rect; rect.left = 0; rect.right = 50; rect.bottom = 100; rect.top = 0;
  1216. AfxEnableControlContainer();
  1217. HANDLE hh = afxCurrentInstanceHandle;
  1218. hh = AfxGetInstanceHandle();
  1219. Create(NULL,"");
  1220. InitControlContainer();
  1221. }
  1222. //***************************************************************************
  1223. //
  1224. // SCODE CImpAuto::MakeEnum
  1225. //
  1226. // DESCRIPTION:
  1227. //
  1228. // Creates a CEnumPerfInfo object which can be used for enumeration
  1229. //
  1230. // PARAMETERS:
  1231. //
  1232. // pClass
  1233. // ProvObj
  1234. // ppInfo
  1235. //
  1236. // RETURN VALUE:
  1237. //
  1238. //
  1239. //***************************************************************************
  1240. SCODE CImpAuto::MakeEnum(
  1241. IWbemClassObject * pClass,
  1242. CProvObj & ProvObj,
  1243. CEnumInfo ** ppInfo)
  1244. {
  1245. SCODE sc;
  1246. *ppInfo = NULL;
  1247. LPDISPATCH pDisp = NULL;
  1248. CAutoCache Cache;
  1249. AFX_MANAGE_STATE(AfxGetStaticModuleState())
  1250. // Do a second parse on the provider string.
  1251. CProvObj ObjectPath(ProvObj.sGetFullToken(1),DOT);
  1252. sc = ObjectPath.dwGetStatus(1); //todo, is 1 ok??
  1253. if(sc != S_OK)
  1254. return sc;
  1255. // Get the IDispatch interface and then get thedo the "Get"
  1256. int iDepth = ObjectPath.iGetNumTokens();
  1257. pDisp = pGetDispatch(&sc,ObjectPath,ProvObj.sGetToken(0),&Cache,iDepth);
  1258. if(pDisp)
  1259. {
  1260. int iCount;
  1261. sc = DoCall(DISPATCH_PROPERTYGET,ObjectPath,0,pDisp,VT_I4,
  1262. &iCount,L"Count");
  1263. if(sc == S_OK)
  1264. {
  1265. // Create a new CEnumAutoInfo object.
  1266. CEnumAutoInfo * pInfo = new CEnumAutoInfo(iCount);
  1267. if(pInfo == NULL)
  1268. {
  1269. sc = WBEM_E_OUT_OF_MEMORY;
  1270. }
  1271. else
  1272. *ppInfo = pInfo;
  1273. }
  1274. }
  1275. return sc;
  1276. }
  1277. //***************************************************************************
  1278. //
  1279. // SCODE CImpAuto::GetKey
  1280. //
  1281. // DESCRIPTION:
  1282. //
  1283. //
  1284. // PARAMETERS:
  1285. //
  1286. // pInfo
  1287. // iIndex
  1288. // ppKey
  1289. //
  1290. // RETURN VALUE:
  1291. //
  1292. //
  1293. //***************************************************************************
  1294. SCODE CImpAuto::GetKey(
  1295. CEnumInfo * pInfo,
  1296. int iIndex,
  1297. LPWSTR * ppKey)
  1298. {
  1299. *ppKey = new WCHAR[10];
  1300. CEnumAutoInfo * pAuto = (CEnumAutoInfo *)pInfo;
  1301. if(iIndex >= pAuto->GetCount())
  1302. return WBEM_E_FAILED;
  1303. if(*ppKey == NULL)
  1304. return WBEM_E_OUT_OF_MEMORY;
  1305. _itow(iIndex + 1,*ppKey,10);
  1306. return S_OK;
  1307. }
  1308. //***************************************************************************
  1309. //
  1310. // SCODE CImpAuto::MergeStrings
  1311. //
  1312. // DESCRIPTION:
  1313. //
  1314. // Combines the Class Context, Key, and Property Context strings.
  1315. //
  1316. // PARAMETERS:
  1317. //
  1318. // ppOut
  1319. // pClassContext
  1320. // pKey
  1321. // pPropContext
  1322. //
  1323. // RETURN VALUE:
  1324. //
  1325. //
  1326. //***************************************************************************
  1327. SCODE CImpAuto::MergeStrings(
  1328. LPWSTR * ppOut,
  1329. LPWSTR pClassContext,
  1330. LPWSTR pKey,
  1331. LPWSTR pPropContext)
  1332. {
  1333. // Allocate space for output
  1334. int iLen = 6;
  1335. if(pClassContext)
  1336. iLen += wcslen(pClassContext);
  1337. if(pKey)
  1338. iLen += wcslen(pKey);
  1339. if(pPropContext)
  1340. iLen += wcslen(pPropContext);
  1341. else
  1342. return WBEM_E_FAILED; // should always have this!
  1343. *ppOut = new WCHAR[iLen];
  1344. if(*ppOut == NULL)
  1345. return WBEM_E_OUT_OF_MEMORY;
  1346. // simple case is that everything is in the property context. That would
  1347. // be the case when the provider is being used as a simple dynamic
  1348. // property provider
  1349. if(pClassContext == NULL || pKey == NULL)
  1350. {
  1351. wcscpy(*ppOut,pPropContext);
  1352. return S_OK;
  1353. }
  1354. // Copy the class context, property, and finally the key
  1355. wcscpy(*ppOut,pClassContext);
  1356. wcscat(*ppOut,L"(");
  1357. wcscat(*ppOut,pKey);
  1358. wcscat(*ppOut,L").");
  1359. wcscat(*ppOut,pPropContext);
  1360. return S_OK;
  1361. }
  1362. //***************************************************************************
  1363. //
  1364. // CEnumAutoInfo::CEnumAutoInfo
  1365. //
  1366. // DESCRIPTION:
  1367. //
  1368. // Constructor.
  1369. //
  1370. // PARAMETERS:
  1371. //
  1372. // iCount
  1373. //
  1374. //***************************************************************************
  1375. CEnumAutoInfo::CEnumAutoInfo(
  1376. int iCount)
  1377. {
  1378. m_iCount = iCount;
  1379. }
  1380. //***************************************************************************
  1381. //
  1382. // CEnumAutoInfo::~CEnumAutoInfo
  1383. //
  1384. // DESCRIPTION:
  1385. //
  1386. // Destructor.
  1387. //
  1388. //***************************************************************************
  1389. CEnumAutoInfo::~CEnumAutoInfo()
  1390. {
  1391. }
  1392. //***************************************************************************
  1393. //
  1394. // CImpAutoProp::CImpAutoProp
  1395. //
  1396. // DESCRIPTION:
  1397. //
  1398. // Constructor.
  1399. //
  1400. //***************************************************************************
  1401. CImpAutoProp::CImpAutoProp()
  1402. {
  1403. m_pImpDynProv = new CImpAuto();
  1404. }
  1405. //***************************************************************************
  1406. //
  1407. // CImpAutoProp::~CImpAutoProp
  1408. //
  1409. // DESCRIPTION:
  1410. //
  1411. // Destructor.
  1412. //
  1413. //***************************************************************************
  1414. CImpAutoProp::~CImpAutoProp()
  1415. {
  1416. if(m_pImpDynProv)
  1417. delete m_pImpDynProv;
  1418. }