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.

1195 lines
26 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. #include "precomp.h"
  8. #include <wbemint.h>
  9. #include <wbemutil.h>
  10. #include <md5wbem.h>
  11. #include <arrtempl.h>
  12. #include "smrtmrsh.h"
  13. #include "buffer.h"
  14. static DWORD g_dwSignature = 0xabcdefab;
  15. static WORD g_dwVersion = 0;
  16. enum { e_ClassIdNone=0,
  17. e_ClassIdHash,
  18. e_ClassIdHashAndPath } ClassIdType_e;
  19. enum { e_DataPartial=0,
  20. e_DataFull } DataType_e;
  21. /****
  22. Packed Object Format
  23. - 4 byte magic number
  24. - 2 byte version number
  25. - 1 byte class id type
  26. - 4 byte class id len
  27. - N byte class id
  28. - 1 byte data type
  29. - 4 byte data len
  30. - N byte data
  31. *****/
  32. #define HDRSIZE 16 // size of msg w/o variable length data.
  33. #define HASHSIZE 16
  34. /**************************************************************************
  35. CWbemObjectWrapper - smooths out differences between Nova and Whistler
  36. ***************************************************************************/
  37. class CWbemObjectWrapper
  38. {
  39. CWbemPtr<_IWmiObject> m_pWmiObj;
  40. CWbemPtr<IWbemObjectAccess> m_pObjAccess;
  41. // CWbemPtr<IWbemObjectInternals> m_pObjInt;
  42. public:
  43. HRESULT SetPointer( IWbemClassObject* pObj )
  44. {
  45. HRESULT hr;
  46. hr = pObj->QueryInterface( IID__IWmiObject, (void**)&m_pWmiObj );
  47. if ( FAILED(hr) )
  48. {
  49. hr = pObj->QueryInterface( IID_IWbemObjectAccess,
  50. (void**)&m_pObjAccess );
  51. if ( SUCCEEDED(hr) )
  52. {
  53. // hr = pObj->QueryInterface( IID_IWbemObjectInternals,
  54. // (void**)&m_pObjInt );
  55. }
  56. }
  57. return hr;
  58. }
  59. operator IWbemObjectAccess* ()
  60. {
  61. IWbemObjectAccess* pAccess;
  62. if ( m_pWmiObj != NULL )
  63. {
  64. pAccess = m_pWmiObj;
  65. }
  66. else
  67. {
  68. pAccess = m_pObjAccess;
  69. }
  70. return pAccess;
  71. }
  72. BOOL IsValid()
  73. {
  74. return m_pWmiObj != NULL || m_pObjAccess != NULL;
  75. }
  76. HRESULT SetObjectParts( LPVOID pMem,
  77. DWORD dwDestBufSize,
  78. DWORD dwParts )
  79. {
  80. HRESULT hr;
  81. if ( m_pWmiObj != NULL )
  82. {
  83. hr = m_pWmiObj->SetObjectParts( pMem, dwDestBufSize, dwParts );
  84. }
  85. else
  86. {
  87. hr = WBEM_E_NOT_SUPPORTED;
  88. }
  89. return hr;
  90. }
  91. HRESULT GetObjectParts( LPVOID pDestination,
  92. DWORD dwDestBufSize,
  93. DWORD dwParts,
  94. DWORD *pdwUsed )
  95. {
  96. HRESULT hr;
  97. if ( m_pWmiObj != NULL )
  98. {
  99. hr = m_pWmiObj->GetObjectParts( pDestination,
  100. dwDestBufSize,
  101. dwParts,
  102. pdwUsed );
  103. }
  104. else
  105. {
  106. hr = WBEM_E_NOT_SUPPORTED;
  107. }
  108. return hr;
  109. }
  110. HRESULT MergeClassPart( IWbemClassObject* pObj )
  111. {
  112. HRESULT hr;
  113. if ( m_pWmiObj != NULL )
  114. {
  115. hr = m_pWmiObj->MergeClassPart( pObj );
  116. }
  117. else
  118. {
  119. hr = WBEM_E_NOT_SUPPORTED;
  120. }
  121. return hr;
  122. }
  123. };
  124. HRESULT GetClassPath( IWbemClassObject* pObj,
  125. LPCWSTR wszNamespace,
  126. PBYTE pBuff,
  127. ULONG cBuff,
  128. ULONG* pcUsed )
  129. {
  130. HRESULT hr;
  131. *pcUsed = 0;
  132. CPropVar vNamespace, vClass;
  133. //
  134. // before trying to optimize the property access, realize that
  135. // class objects do not support handle access to the __Namespace prop.
  136. //
  137. hr = pObj->Get( L"__NAMESPACE", 0, &vNamespace, NULL, NULL );
  138. if ( FAILED(hr) )
  139. {
  140. return hr;
  141. }
  142. hr = pObj->Get( L"__CLASS", 0, &vClass, NULL, NULL );
  143. if ( FAILED(hr) )
  144. {
  145. return hr;
  146. }
  147. if ( V_VT(&vNamespace) == VT_BSTR )
  148. {
  149. wszNamespace = V_BSTR(&vNamespace);
  150. }
  151. if ( wszNamespace == NULL )
  152. {
  153. return WBEM_E_NOT_SUPPORTED;
  154. }
  155. if ( V_VT(&vClass) != VT_BSTR )
  156. {
  157. return WBEM_E_CRITICAL_ERROR;
  158. }
  159. ULONG cNamespace = wcslen(wszNamespace)*2;
  160. ULONG cClass = wcslen(V_BSTR(&vClass))*2;
  161. //
  162. // add 4 for the two null terminators
  163. //
  164. *pcUsed = cNamespace + cClass + 4;
  165. if ( cBuff < *pcUsed )
  166. {
  167. return WBEM_E_BUFFER_TOO_SMALL;
  168. }
  169. ULONG iBuff = 0;
  170. memcpy( pBuff+iBuff, wszNamespace, cNamespace );
  171. iBuff += cNamespace;
  172. *(WCHAR*)(pBuff+iBuff) = ':';
  173. iBuff+= 2;
  174. memcpy( pBuff+iBuff, V_BSTR(&vClass), cClass );
  175. iBuff += cClass;
  176. *(WCHAR*)(pBuff+iBuff) = '\0';
  177. iBuff+= 2;
  178. _DBG_ASSERT( iBuff == *pcUsed );
  179. return hr;
  180. }
  181. HRESULT GetClassPartHash( CWbemObjectWrapper& rWrap,
  182. PBYTE pClassPartHash,
  183. ULONG cClassPartHash )
  184. {
  185. HRESULT hr;
  186. //
  187. // Too bad we have to perform a copy here, but no other way. This
  188. // function requires the passed in buffer be big enough to hold both
  189. // the class part and the hash. This is not really too limiting because
  190. // in most cases where this function is used, the caller already has
  191. // enough memory allocated to use here as a workarea.
  192. //
  193. DWORD dwSize;
  194. if ( cClassPartHash >= HASHSIZE )
  195. {
  196. hr = rWrap.GetObjectParts( pClassPartHash+HASHSIZE,
  197. cClassPartHash-HASHSIZE,
  198. WBEM_OBJ_CLASS_PART,
  199. &dwSize );
  200. if ( SUCCEEDED(hr) )
  201. {
  202. MD5::Transform( pClassPartHash+HASHSIZE, dwSize, pClassPartHash );
  203. }
  204. }
  205. else
  206. {
  207. hr = WBEM_E_BUFFER_TOO_SMALL;
  208. }
  209. return hr;
  210. }
  211. /***************************************************************************
  212. CSmartObjectMarshaler
  213. ****************************************************************************/
  214. HRESULT CSmartObjectMarshaler::GetMaxMarshalSize( IWbemClassObject* pObj,
  215. LPCWSTR wszNamespace,
  216. DWORD dwFlags,
  217. ULONG* pulSize )
  218. {
  219. HRESULT hr;
  220. CWbemPtr<IMarshal> pMrsh;
  221. hr = pObj->QueryInterface( IID_IMarshal, (void**)&pMrsh );
  222. if ( FAILED(hr) )
  223. {
  224. return hr;
  225. }
  226. //
  227. // user is requesting the required size to pack object. For now,
  228. // we always use the size of the entire object blob. However, the
  229. // actual size of the object may be much smaller.
  230. //
  231. DWORD dwSize;
  232. hr = pMrsh->GetMarshalSizeMax( IID_IWbemClassObject,
  233. pObj,
  234. MSHCTX_INPROC,
  235. NULL,
  236. 0,
  237. &dwSize );
  238. if ( FAILED(hr) )
  239. {
  240. return hr;
  241. }
  242. *pulSize = dwSize + HDRSIZE + HASHSIZE;
  243. if ( dwFlags == WMIMSG_FLAG_MRSH_PARTIAL )
  244. {
  245. hr = GetClassPath( pObj, wszNamespace, NULL, 0, &dwSize );
  246. if ( hr == WBEM_E_BUFFER_TOO_SMALL )
  247. {
  248. *pulSize += dwSize;
  249. hr = WBEM_S_NO_ERROR;
  250. }
  251. else
  252. {
  253. _DBG_ASSERT( FAILED(hr) );
  254. }
  255. }
  256. return hr;
  257. }
  258. HRESULT CSmartObjectMarshaler::InternalPack( IWbemClassObject* pObj,
  259. LPCWSTR wszNamespace,
  260. DWORD dwFlags,
  261. ULONG cBuff,
  262. BYTE* pBuff,
  263. ULONG* pcUsed )
  264. {
  265. HRESULT hr;
  266. *pcUsed = 0;
  267. //
  268. // make sure we have enough room for at least the header data.
  269. //
  270. if ( cBuff < HDRSIZE )
  271. {
  272. return WBEM_E_BUFFER_TOO_SMALL;
  273. }
  274. ULONG iBuff = 0;
  275. memcpy( pBuff + iBuff, &g_dwSignature, 4 );
  276. iBuff += 4;
  277. memcpy( pBuff + iBuff, &g_dwVersion, 2 );
  278. iBuff += 2;
  279. //
  280. // write class information
  281. //
  282. DWORD dwSize;
  283. BOOL bPartialData;
  284. CWbemObjectWrapper ObjWrap;
  285. PBYTE pClassPartHash = NULL;
  286. if ( dwFlags == WMIMSG_FLAG_MRSH_FULL_ONCE )
  287. {
  288. hr = ObjWrap.SetPointer( pObj );
  289. if ( FAILED(hr) )
  290. {
  291. return hr;
  292. }
  293. //
  294. // send class part hash for class info
  295. //
  296. *(pBuff+iBuff) = char(e_ClassIdHash);
  297. iBuff++;
  298. dwSize = HASHSIZE;
  299. memcpy( pBuff+iBuff, &dwSize, 4 );
  300. iBuff += 4;
  301. hr = GetClassPartHash( ObjWrap, pBuff+iBuff, cBuff-iBuff );
  302. if ( FAILED(hr) )
  303. {
  304. return hr;
  305. }
  306. pClassPartHash = pBuff+iBuff;
  307. iBuff += HASHSIZE;
  308. //
  309. // see if we've sent the class part before
  310. //
  311. CInCritSec ics( &m_cs );
  312. bPartialData = m_SentMap[pClassPartHash];
  313. }
  314. else if ( dwFlags == WMIMSG_FLAG_MRSH_PARTIAL )
  315. {
  316. hr = ObjWrap.SetPointer( pObj );
  317. if ( FAILED(hr) )
  318. {
  319. return hr;
  320. }
  321. //
  322. // send class path and class part hash for class info
  323. //
  324. *(pBuff+iBuff) = char(e_ClassIdHashAndPath);
  325. iBuff++;
  326. PBYTE pLen = pBuff+iBuff;
  327. iBuff+= 4; // leave room for class info size
  328. hr = GetClassPartHash( ObjWrap, pBuff+iBuff, cBuff-iBuff );
  329. if ( FAILED(hr) )
  330. {
  331. return hr;
  332. }
  333. iBuff += HASHSIZE;
  334. hr = GetClassPath( pObj,
  335. wszNamespace,
  336. pBuff+iBuff,
  337. cBuff-iBuff,
  338. &dwSize );
  339. if ( FAILED(hr) )
  340. {
  341. return hr;
  342. }
  343. iBuff += dwSize;
  344. dwSize += HASHSIZE; // size if both hash and path
  345. memcpy( pLen, &dwSize, 4 );
  346. bPartialData = TRUE;
  347. }
  348. else if ( dwFlags == WMIMSG_FLAG_MRSH_FULL )
  349. {
  350. //
  351. // no class information
  352. //
  353. *(pBuff+iBuff) = char(e_ClassIdNone);
  354. iBuff++;
  355. memset( pBuff + iBuff, 0, 4 );
  356. iBuff += 4;
  357. bPartialData = FALSE;
  358. }
  359. else
  360. {
  361. return WBEM_E_INVALID_PARAMETER;
  362. }
  363. //
  364. // write data
  365. //
  366. if ( bPartialData )
  367. {
  368. *(pBuff+iBuff) = char(e_DataPartial);
  369. iBuff++;
  370. PBYTE pLen = pBuff+iBuff;
  371. iBuff += 4; // fill in length afterwords.
  372. //
  373. // now get instance part
  374. //
  375. _DBG_ASSERT( ObjWrap.IsValid() );
  376. hr = ObjWrap.GetObjectParts( pBuff+iBuff,
  377. cBuff-iBuff,
  378. WBEM_OBJ_DECORATION_PART |
  379. WBEM_OBJ_INSTANCE_PART,
  380. &dwSize );
  381. if ( FAILED(hr) )
  382. {
  383. return hr;
  384. }
  385. iBuff += dwSize;
  386. //
  387. // go back and set length ..
  388. //
  389. memcpy( pLen, &dwSize, 4 );
  390. }
  391. else
  392. {
  393. *(pBuff+iBuff) = char(e_DataFull);
  394. iBuff++;
  395. PBYTE pLen = pBuff+iBuff;
  396. iBuff += 4; // fill in length afterwords.
  397. //
  398. // for now, use MarshalInterface() to marshal object. The reason
  399. // for this is because SetObjectMemory() has a bug where
  400. // it assumes ownership of the memory ( even though the client
  401. // doesn't have access to the allocator used to free it ).
  402. //
  403. CBuffer Strm( pBuff+iBuff, cBuff-iBuff, FALSE );
  404. CWbemPtr<IMarshal> pMrsh;
  405. hr = pObj->QueryInterface( IID_IMarshal, (void**)&pMrsh );
  406. if ( FAILED(hr) )
  407. {
  408. return hr;
  409. }
  410. hr = pMrsh->MarshalInterface( &Strm,
  411. IID_IWbemClassObject,
  412. pObj,
  413. MSHCTX_INPROC,
  414. NULL,
  415. 0 );
  416. if ( FAILED(hr) )
  417. {
  418. return hr;
  419. }
  420. //
  421. // check if we read more data than we can fit into our buffer. We
  422. // can tell this if the buffer is no longer the one we passed in.
  423. //
  424. if ( Strm.GetRawData() != pBuff+iBuff )
  425. {
  426. return WBEM_E_BUFFER_TOO_SMALL;
  427. }
  428. dwSize = Strm.GetIndex();
  429. iBuff += dwSize;
  430. //
  431. // go back and set length of the data.
  432. //
  433. memcpy( pLen, &dwSize, 4 );
  434. if ( dwFlags == WMIMSG_FLAG_MRSH_FULL_ONCE )
  435. {
  436. //
  437. // mark that we've successfully packed the class part once.
  438. //
  439. _DBG_ASSERT( pClassPartHash != NULL );
  440. CInCritSec ics(&m_cs);
  441. m_SentMap[pClassPartHash] = TRUE;
  442. }
  443. }
  444. *pcUsed = iBuff;
  445. return WBEM_S_NO_ERROR;
  446. }
  447. STDMETHODIMP CSmartObjectMarshaler::Pack( IWbemClassObject* pObj,
  448. LPCWSTR wszNamespace,
  449. DWORD dwFlags,
  450. ULONG cBuff,
  451. BYTE* pBuff,
  452. ULONG* pcUsed )
  453. {
  454. HRESULT hr;
  455. ENTER_API_CALL
  456. hr = InternalPack( pObj, wszNamespace, dwFlags, cBuff, pBuff, pcUsed );
  457. if ( hr == WBEM_E_BUFFER_TOO_SMALL )
  458. {
  459. HRESULT hr2;
  460. hr2 = GetMaxMarshalSize( pObj, wszNamespace, dwFlags, pcUsed );
  461. if ( FAILED(hr2) )
  462. {
  463. hr = hr2;
  464. }
  465. }
  466. EXIT_API_CALL
  467. return hr;
  468. }
  469. STDMETHODIMP CSmartObjectMarshaler::Flush()
  470. {
  471. CInCritSec ics(&m_cs);
  472. m_SentMap.clear();
  473. return S_OK;
  474. }
  475. /***************************************************************************
  476. CSmartObjectUnmarshaler
  477. ****************************************************************************/
  478. HRESULT CSmartObjectUnmarshaler::EnsureInitialized()
  479. {
  480. HRESULT hr;
  481. CInCritSec ics( &m_cs );
  482. if ( m_pEmptyClass != NULL )
  483. {
  484. return WBEM_S_NO_ERROR;
  485. }
  486. //
  487. // allocate a template class object which we can use for spawning
  488. // 'empty' instances from.
  489. //
  490. CWbemPtr<IWbemClassObject> pEmptyClass;
  491. hr = CoCreateInstance( CLSID_WbemClassObject,
  492. NULL,
  493. CLSCTX_INPROC,
  494. IID_IWbemClassObject,
  495. (void**)&pEmptyClass );
  496. if ( FAILED(hr) )
  497. {
  498. return hr;
  499. }
  500. VARIANT vName;
  501. V_VT(&vName) = VT_BSTR;
  502. V_BSTR(&vName) = L"__DummyClass";
  503. hr = pEmptyClass->Put( L"__CLASS", 0, &vName, NULL );
  504. if ( FAILED(hr) )
  505. {
  506. return hr;
  507. }
  508. //
  509. // allocate a locator to access namespaces for obtaining class definitions.
  510. //
  511. CWbemPtr<IWbemLocator> pLocator;
  512. hr = CoCreateInstance( CLSID_WbemLocator,
  513. NULL,
  514. CLSCTX_INPROC,
  515. IID_IWbemLocator,
  516. (void**)&pLocator );
  517. if ( FAILED(hr) )
  518. {
  519. return hr;
  520. }
  521. //
  522. // Allocate a full object unmarshaler. This is used to create classes
  523. // or instances that were sent in full.
  524. //
  525. hr = CoCreateInstance( CLSID_WbemClassObjectProxy,
  526. NULL,
  527. CLSCTX_INPROC,
  528. IID_IMarshal,
  529. (void**)&m_pUnmrsh );
  530. if ( FAILED(hr) )
  531. {
  532. return hr;
  533. }
  534. m_pEmptyClass = pEmptyClass;
  535. m_pLocator = pLocator;
  536. return WBEM_S_NO_ERROR;
  537. }
  538. void CSmartObjectUnmarshaler::MakeRoomInCache( DWORD dwSize )
  539. {
  540. while ( !m_Cache.empty() && dwSize + m_ulCacheSize > m_ulMaxCacheSize )
  541. {
  542. DWORD dwLeastRecentTime = 0xffffffff;
  543. ClassPartMap::iterator it, itLeastRecent;
  544. for( it = m_Cache.begin(); it != m_Cache.end(); it++ )
  545. {
  546. CacheRecord& rCurrent = it->second;
  547. if ( rCurrent.m_dwLastUsedTime <= dwLeastRecentTime )
  548. {
  549. itLeastRecent = it;
  550. dwLeastRecentTime = rCurrent.m_dwLastUsedTime;
  551. }
  552. }
  553. _DBG_ASSERT( m_ulCacheSize >= itLeastRecent->second.m_dwClassSize );
  554. m_ulCacheSize -= itLeastRecent->second.m_dwClassSize;
  555. m_Cache.erase( itLeastRecent );
  556. }
  557. }
  558. HRESULT CSmartObjectUnmarshaler::CacheClassPart( PBYTE pClassHash,
  559. DWORD dwSize,
  560. IWbemClassObject* pClassPart )
  561. {
  562. HRESULT hr;
  563. CInCritSec ics(&m_cs);
  564. ClassPartMap::iterator it = m_Cache.find( pClassHash );
  565. if ( it == m_Cache.end() )
  566. {
  567. MakeRoomInCache( dwSize );
  568. if ( dwSize + m_ulCacheSize < m_ulMaxCacheSize )
  569. {
  570. //
  571. // create the record and add to cache.
  572. //
  573. CacheRecord Record;
  574. Record.m_dwClassSize = dwSize;
  575. Record.m_pClassPart = pClassPart;
  576. Record.m_dwLastUsedTime = GetTickCount();
  577. m_Cache[pClassHash] = Record;
  578. m_ulCacheSize += dwSize;
  579. hr = WBEM_S_NO_ERROR;
  580. }
  581. else
  582. {
  583. //
  584. // the class part size is too big to store in the cache.
  585. //
  586. hr = WBEM_S_FALSE;
  587. }
  588. }
  589. else
  590. {
  591. //
  592. // already in the cache.
  593. //
  594. hr = WBEM_S_NO_ERROR;
  595. }
  596. return hr;
  597. }
  598. HRESULT CSmartObjectUnmarshaler::FindClassPart( PBYTE pClassPartHash,
  599. LPCWSTR wszClassPath,
  600. IWbemClassObject** ppClassPart)
  601. {
  602. HRESULT hr;
  603. //
  604. // first try the cache ...
  605. //
  606. ClassPartMap::iterator it;
  607. {
  608. CInCritSec ics(&m_cs);
  609. it = m_Cache.find( pClassPartHash );
  610. if ( it != m_Cache.end() )
  611. {
  612. it->second.m_dwLastUsedTime = GetTickCount();
  613. *ppClassPart = it->second.m_pClassPart;
  614. (*ppClassPart)->AddRef();
  615. // DEBUGTRACE((LOG_ESS,
  616. // "MRSH: Cache Hit !!! %d bytes saved in transmission\n",
  617. // it->second.m_dwClassSize ));
  618. return WBEM_S_NO_ERROR;
  619. }
  620. }
  621. //
  622. // expensive route ... fetch the class object from wmi
  623. //
  624. if ( wszClassPath == NULL )
  625. {
  626. //
  627. // there's nothing we can do.
  628. //
  629. return WBEM_E_NOT_FOUND;
  630. }
  631. CWbemPtr<IWbemServices> pSvc;
  632. CWbemBSTR bsNamespace = wszClassPath;
  633. WCHAR* pch = wcschr( bsNamespace, ':' );
  634. if ( pch == NULL )
  635. {
  636. return WBEM_E_INVALID_OBJECT_PATH;
  637. }
  638. *pch++ = '\0';
  639. hr = m_pLocator->ConnectServer( bsNamespace, NULL, NULL,
  640. NULL, 0, NULL, NULL, &pSvc );
  641. if ( FAILED(hr) )
  642. {
  643. return hr;
  644. }
  645. CWbemBSTR bsRelpath = pch;
  646. CWbemPtr<IWbemClassObject> pClass;
  647. hr = pSvc->GetObject( bsRelpath, 0, NULL, &pClass, NULL );
  648. if ( FAILED(hr) )
  649. {
  650. return hr;
  651. }
  652. CWbemPtr<IWbemClassObject> pClassPart;
  653. hr = pClass->SpawnInstance( 0, &pClassPart );
  654. if ( FAILED(hr) )
  655. {
  656. return hr;
  657. }
  658. //
  659. // now we have to verify that hash of the class part and the
  660. // hash sent in the message are the same.
  661. //
  662. CWbemObjectWrapper ObjWrap;
  663. hr = ObjWrap.SetPointer( pClassPart );
  664. if ( FAILED(hr) )
  665. {
  666. return hr;
  667. }
  668. DWORD dwSize;
  669. hr = ObjWrap.GetObjectParts( NULL, 0, WBEM_OBJ_CLASS_PART, &dwSize );
  670. if ( hr != WBEM_E_BUFFER_TOO_SMALL )
  671. {
  672. _DBG_ASSERT( FAILED(hr) );
  673. return hr;
  674. }
  675. PBYTE pBuff = new BYTE[dwSize+HASHSIZE];
  676. if ( pBuff == NULL )
  677. {
  678. return WBEM_E_OUT_OF_MEMORY;
  679. }
  680. CVectorDeleteMe<BYTE> tdm( pBuff );
  681. hr = GetClassPartHash( ObjWrap, pBuff, dwSize+HASHSIZE );
  682. if ( FAILED(hr) )
  683. {
  684. return hr;
  685. }
  686. if ( memcmp( pBuff, pClassPartHash, HASHSIZE ) == 0 )
  687. {
  688. //
  689. // things look good so cache the class part.
  690. //
  691. hr = CacheClassPart( pClassPartHash, dwSize, pClassPart );
  692. if ( FAILED(hr) )
  693. {
  694. return hr;
  695. }
  696. *ppClassPart = pClassPart;
  697. (*ppClassPart)->AddRef();
  698. }
  699. else
  700. {
  701. //
  702. // class parts don't match up, nothing else we can do.
  703. //
  704. hr = WBEM_E_NOT_FOUND;
  705. }
  706. return hr;
  707. }
  708. STDMETHODIMP CSmartObjectUnmarshaler::Unpack( ULONG cBuff,
  709. PBYTE pBuff,
  710. DWORD dwFlags,
  711. IWbemClassObject** ppObj,
  712. ULONG* pcUsed )
  713. {
  714. HRESULT hr;
  715. ENTER_API_CALL
  716. *pcUsed = 0;
  717. *ppObj = NULL;
  718. hr = EnsureInitialized();
  719. if ( FAILED(hr) )
  720. {
  721. return hr;
  722. }
  723. if ( cBuff < HDRSIZE )
  724. {
  725. return WMIMSG_E_INVALIDMESSAGE;
  726. }
  727. //
  728. // verify signature and version info
  729. //
  730. DWORD dw;
  731. ULONG iBuff = 0;
  732. memcpy( &dw, pBuff + iBuff, 4 );
  733. iBuff += 6; // version info is not currently used;
  734. if ( dw != g_dwSignature )
  735. {
  736. return WMIMSG_E_INVALIDMESSAGE;
  737. }
  738. //
  739. // obtain the class id type
  740. //
  741. char chClassIdType = *(pBuff + iBuff);
  742. iBuff++;
  743. memcpy( &dw, pBuff + iBuff, 4 );
  744. iBuff += 4;
  745. if ( cBuff - iBuff - 5 < dw ) // 5 is for what's left in the hdr to read
  746. {
  747. return WMIMSG_E_INVALIDMESSAGE;
  748. }
  749. //
  750. // obtain the class information associated with the data
  751. //
  752. PBYTE pClassPartHash = NULL;
  753. LPCWSTR wszClassPath = NULL;
  754. if ( chClassIdType == e_ClassIdHash )
  755. {
  756. pClassPartHash = pBuff+iBuff;
  757. }
  758. else if ( chClassIdType == e_ClassIdHashAndPath )
  759. {
  760. pClassPartHash = pBuff+iBuff;
  761. wszClassPath = LPWSTR(pBuff+iBuff+HASHSIZE);
  762. if ( *(WCHAR*)(pBuff+iBuff+dw-2) != '\0' )
  763. {
  764. return WMIMSG_E_INVALIDMESSAGE;
  765. }
  766. }
  767. else if ( chClassIdType == e_ClassIdNone )
  768. {
  769. if ( dw != 0 )
  770. {
  771. return WMIMSG_E_INVALIDMESSAGE;
  772. }
  773. }
  774. else
  775. {
  776. return WMIMSG_E_INVALIDMESSAGE;
  777. }
  778. iBuff += dw;
  779. //
  780. // get data part info
  781. //
  782. char chDataType = *(pBuff+iBuff);
  783. iBuff++;
  784. memcpy( &dw, pBuff+iBuff, 4 );
  785. iBuff += 4;
  786. if ( dw > cBuff-iBuff )
  787. {
  788. return WMIMSG_E_INVALIDMESSAGE;
  789. }
  790. CWbemPtr<IWbemClassObject> pObj;
  791. if ( chDataType == e_DataFull )
  792. {
  793. CBuffer Strm( pBuff+iBuff, cBuff-iBuff, FALSE );
  794. hr = m_pUnmrsh->UnmarshalInterface( &Strm,
  795. IID_IWbemClassObject,
  796. (void**)&pObj );
  797. if ( FAILED(hr) )
  798. {
  799. return WMIMSG_E_INVALIDMESSAGE;
  800. }
  801. dw = Strm.GetIndex();
  802. //
  803. // if there is an associated hash we need to store the class part
  804. // of the unmarshaled object in our cache.
  805. //
  806. if ( pClassPartHash != NULL )
  807. {
  808. //
  809. // create an empty version of the instance to store in the
  810. // cache. All we're interested in storing is the class part.
  811. //
  812. CWbemPtr<IWbemClassObject> pClassPart;
  813. hr = pObj->SpawnInstance( 0, &pClassPart );
  814. if ( FAILED(hr) )
  815. {
  816. return hr;
  817. }
  818. CWbemObjectWrapper ObjWrap;
  819. hr = ObjWrap.SetPointer( pClassPart );
  820. if ( FAILED(hr) )
  821. {
  822. return hr;
  823. }
  824. DWORD dwSize;
  825. hr = ObjWrap.GetObjectParts( NULL,
  826. 0,
  827. WBEM_OBJ_CLASS_PART,
  828. &dwSize );
  829. if ( hr != WBEM_E_BUFFER_TOO_SMALL )
  830. {
  831. _DBG_ASSERT( FAILED(hr) );
  832. return hr;
  833. }
  834. hr = CacheClassPart( pClassPartHash, dwSize, pClassPart );
  835. if ( FAILED(hr) )
  836. {
  837. return hr;
  838. }
  839. }
  840. }
  841. else if ( chDataType == e_DataPartial )
  842. {
  843. CWbemPtr<IWbemClassObject> pClassPart;
  844. _DBG_ASSERT( pClassPartHash != NULL );
  845. hr = FindClassPart( pClassPartHash, wszClassPath, &pClassPart );
  846. if ( FAILED(hr) )
  847. {
  848. return hr;
  849. }
  850. hr = m_pEmptyClass->SpawnInstance( 0, &pObj );
  851. if ( FAILED(hr) )
  852. {
  853. return hr;
  854. }
  855. CWbemObjectWrapper ObjWrap;
  856. hr = ObjWrap.SetPointer( pObj );
  857. if ( FAILED(hr) )
  858. {
  859. return hr;
  860. }
  861. //
  862. // aquires ownership of the memory -- must be CoTaskMemAlloc-ed
  863. // kind of unfortunate - but the memory has to be allocated and
  864. // copied sometime so guess its not that big of a deal.
  865. //
  866. PVOID pInstData = CoTaskMemAlloc( dw );
  867. if ( NULL == pInstData )
  868. {
  869. return WBEM_E_OUT_OF_MEMORY;
  870. }
  871. memcpy( pInstData, pBuff+iBuff, dw );
  872. hr = ObjWrap.SetObjectParts( pInstData,
  873. dw,
  874. WBEM_OBJ_DECORATION_PART |
  875. WBEM_OBJ_INSTANCE_PART );
  876. if ( FAILED(hr) )
  877. {
  878. CoTaskMemFree( pInstData );
  879. return hr;
  880. }
  881. hr = ObjWrap.MergeClassPart( pClassPart );
  882. if ( FAILED(hr) )
  883. {
  884. return hr;
  885. }
  886. }
  887. else
  888. {
  889. return WMIMSG_E_INVALIDMESSAGE;
  890. }
  891. iBuff += dw; // advance the index to account for the data part
  892. pObj->AddRef();
  893. *ppObj = pObj;
  894. *pcUsed = iBuff;
  895. EXIT_API_CALL
  896. return WBEM_S_NO_ERROR;
  897. }
  898. STDMETHODIMP CSmartObjectUnmarshaler::Flush()
  899. {
  900. CInCritSec ics(&m_cs);
  901. m_Cache.clear();
  902. return S_OK;
  903. }