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.

635 lines
18 KiB

  1. /********************************************************************
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. Package.cpp
  5. Abstract:
  6. Cryptography stuff for hcupdate packages
  7. Revision History:
  8. Ghim-Sim Chua (gschua) 07/07/99
  9. - created
  10. Davide Massarenti (dmassare) 03/24/2001
  11. - moved into database code.
  12. ********************************************************************/
  13. #include "stdafx.h"
  14. #include <wintrust.h>
  15. #include <wincrypt.h>
  16. #include <sipbase.h>
  17. #include <softpub.h>
  18. ////////////////////////////////////////////////////////////////////////////////
  19. static void local_GetDNInfo( PCCERT_CONTEXT pCC ,
  20. LPCSTR field ,
  21. LPCWSTR fieldName ,
  22. MPC::wstring& strBuf ,
  23. MPC::wstring* strPlainName = NULL)
  24. {
  25. WCHAR rgTmp[512];
  26. if(strBuf.length()) strBuf += L",";
  27. strBuf += fieldName;
  28. ::CertGetNameStringW( pCC, CERT_NAME_ATTR_TYPE, 0, (void*)field, rgTmp, MAXSTRLEN(rgTmp) ); rgTmp[MAXSTRLEN(rgTmp)] = 0;
  29. if(strPlainName) *strPlainName = rgTmp;
  30. strBuf += rgTmp;
  31. }
  32. ////////////////////////////////////////////////////////////////////////////////
  33. Taxonomy::Package::Package()
  34. {
  35. // MPC::wstring m_strFileName;
  36. m_fTemporary = false; // bool m_fTemporary;
  37. m_lSequence = 0; // long m_lSequence;
  38. m_dwCRC = 0; // DWORD m_dwCRC;
  39. //
  40. // MPC::wstring m_strSKU;
  41. // MPC::wstring m_strLanguage;
  42. // MPC::wstring m_strVendorID;
  43. // MPC::wstring m_strVendorName;
  44. // MPC::wstring m_strProductID;
  45. // MPC::wstring m_strVersion;
  46. //
  47. m_fMicrosoft = false; // bool m_fMicrosoft;
  48. m_fBuiltin = false; // bool m_fBuiltin;
  49. }
  50. Taxonomy::Package::~Package()
  51. {
  52. if(m_fTemporary) Remove( Logger() );
  53. }
  54. HRESULT Taxonomy::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ Taxonomy::Package& val )
  55. {
  56. HRESULT hr;
  57. if(SUCCEEDED(hr = (stream >> val.m_lSequence )) &&
  58. SUCCEEDED(hr = (stream >> val.m_dwCRC )) &&
  59. SUCCEEDED(hr = (stream >> val.m_strSKU )) &&
  60. SUCCEEDED(hr = (stream >> val.m_strLanguage )) &&
  61. SUCCEEDED(hr = (stream >> val.m_strVendorID )) &&
  62. SUCCEEDED(hr = (stream >> val.m_strVendorName)) &&
  63. SUCCEEDED(hr = (stream >> val.m_strProductID )) &&
  64. SUCCEEDED(hr = (stream >> val.m_strVersion )) &&
  65. SUCCEEDED(hr = (stream >> val.m_fMicrosoft )) &&
  66. SUCCEEDED(hr = (stream >> val.m_fBuiltin )) )
  67. {
  68. hr = S_OK;
  69. }
  70. return hr;
  71. }
  72. HRESULT Taxonomy::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const Taxonomy::Package& val )
  73. {
  74. HRESULT hr;
  75. if(SUCCEEDED(hr = (stream << val.m_lSequence )) &&
  76. SUCCEEDED(hr = (stream << val.m_dwCRC )) &&
  77. SUCCEEDED(hr = (stream << val.m_strSKU )) &&
  78. SUCCEEDED(hr = (stream << val.m_strLanguage )) &&
  79. SUCCEEDED(hr = (stream << val.m_strVendorID )) &&
  80. SUCCEEDED(hr = (stream << val.m_strVendorName)) &&
  81. SUCCEEDED(hr = (stream << val.m_strProductID )) &&
  82. SUCCEEDED(hr = (stream << val.m_strVersion )) &&
  83. SUCCEEDED(hr = (stream << val.m_fMicrosoft )) &&
  84. SUCCEEDED(hr = (stream << val.m_fBuiltin )) )
  85. {
  86. hr = S_OK;
  87. }
  88. return hr;
  89. }
  90. ////////////////////
  91. static int local_nCompareVersion( /*[in]*/ DWORD dwVer1, /*[in]*/ DWORD dwBuild1 ,
  92. /*[in]*/ DWORD dwVer2, /*[in]*/ DWORD dwBuild2 )
  93. {
  94. if(dwVer1 > dwVer2) return 1;
  95. if(dwVer1 < dwVer2) return -1;
  96. // dwVer1 == dwVer2
  97. if(dwBuild1 > dwBuild2) return 1;
  98. if(dwBuild1 < dwBuild2) return -1;
  99. return 0;
  100. }
  101. static bool local_fConvertDotVersionStrToDwords( /*[in ]*/ const MPC::wstring& strVer ,
  102. /*[out]*/ DWORD& dwVer ,
  103. /*[out]*/ DWORD& dwBuild )
  104. {
  105. unsigned int iVerFields[4];
  106. if(swscanf( strVer.c_str(), L"%u.%u.%u.%u", &iVerFields[0], &iVerFields[1], &iVerFields[2], &iVerFields[3] ) == 4)
  107. {
  108. dwVer = (iVerFields[0] << 16) + iVerFields[1];
  109. dwBuild = (iVerFields[2] << 16) + iVerFields[3];
  110. return true;
  111. }
  112. return false;
  113. }
  114. int Taxonomy::Package::Compare( /*[in]*/ const Package& pkg, /*[in]*/ DWORD dwMode ) const
  115. {
  116. int iCmp = 0;
  117. DWORD dwVer1;
  118. DWORD dwVer2;
  119. DWORD dwBuild1;
  120. DWORD dwBuild2;
  121. if(dwMode & c_Cmp_SKU)
  122. {
  123. iCmp = MPC::StrICmp( m_strSKU , pkg.m_strSKU ); if(iCmp) return iCmp;
  124. iCmp = MPC::StrICmp( m_strLanguage , pkg.m_strLanguage ); if(iCmp) return iCmp;
  125. }
  126. if(dwMode & c_Cmp_ID)
  127. {
  128. iCmp = MPC::StrICmp( m_strVendorID , pkg.m_strVendorID ); if(iCmp) return iCmp;
  129. iCmp = MPC::StrICmp( m_strProductID, pkg.m_strProductID ); if(iCmp) return iCmp;
  130. }
  131. if(dwMode & c_Cmp_VERSION)
  132. {
  133. if(local_fConvertDotVersionStrToDwords( m_strVersion, dwVer1, dwBuild1 ) &&
  134. local_fConvertDotVersionStrToDwords( pkg.m_strVersion, dwVer2, dwBuild2 ) )
  135. {
  136. iCmp = local_nCompareVersion( dwVer1, dwBuild1, dwVer2, dwBuild2 );
  137. }
  138. else
  139. {
  140. iCmp = MPC::StrICmp( m_strVersion, pkg.m_strVersion );
  141. }
  142. }
  143. return iCmp;
  144. }
  145. ////////////////////////////////////////////////////////////////////////////////
  146. HRESULT Taxonomy::Package::GenerateFileName()
  147. {
  148. HRESULT hr;
  149. if(m_strFileName.size() == 0)
  150. {
  151. WCHAR rgBuf[MAX_PATH]; _snwprintf( rgBuf, MAXSTRLEN(rgBuf), L"%s\\package_%ld.cab", HC_ROOT_HELPSVC_PKGSTORE, m_lSequence ); rgBuf[MAXSTRLEN(rgBuf)] = 0;
  152. if(FAILED(hr = MPC::SubstituteEnvVariables( m_strFileName = rgBuf ))) return hr;
  153. }
  154. return S_OK;
  155. }
  156. HRESULT Taxonomy::Package::Import( /*[in]*/ Logger& log ,
  157. /*[in]*/ LPCWSTR szFile ,
  158. /*[in]*/ long lSequence ,
  159. /*[in]*/ MPC::Impersonation* imp )
  160. {
  161. __HCP_FUNC_ENTRY( "Taxonomy::Package::Import" );
  162. HRESULT hr;
  163. m_fTemporary = true;
  164. m_lSequence = lSequence;
  165. __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateFileName());
  166. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::DeleteFile( m_strFileName ));
  167. if(imp)
  168. {
  169. __MPC_EXIT_IF_METHOD_FAILS(hr, SVC::CopyFileWhileImpersonating( szFile, m_strFileName.c_str(), *imp, /*fImpersonateForSource*/true ));
  170. }
  171. else
  172. {
  173. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CopyFile( szFile, m_strFileName.c_str() ));
  174. }
  175. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ComputeCRC( m_dwCRC, m_strFileName.c_str() ));
  176. ::SetFileAttributesW( m_strFileName.c_str(), FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM );
  177. log.WriteLog( -1, L"\nImported package %s into package store\n\n", szFile );
  178. hr = S_OK;
  179. __HCP_FUNC_CLEANUP;
  180. if(FAILED(hr))
  181. {
  182. log.WriteLog( hr, L"Failed to copy %s into package store", szFile );
  183. }
  184. __HCP_FUNC_EXIT(hr);
  185. }
  186. ////////////////////////////////////////////////////////////////////////////////
  187. static HRESULT local_GetSignerInfo( /*[in]*/ HCRYPTMSG hMsg, /*[in]*/ DWORD index, /*[in/out]*/ BYTE*& pSignerInfo )
  188. {
  189. __HCP_FUNC_ENTRY( "local_GetSignerInfo" );
  190. HRESULT hr;
  191. BYTE* pbEncodedSigner = NULL;
  192. DWORD cbEncodedSigner = 0;
  193. DWORD cbSignerInfo = 0;
  194. delete [] pSignerInfo; pSignerInfo = NULL;
  195. //
  196. // get the encoded signer BLOB
  197. //
  198. ::CryptMsgGetParam( hMsg, CMSG_ENCODED_SIGNER, index, NULL, &cbEncodedSigner );
  199. __MPC_EXIT_IF_ALLOC_FAILS(hr, pbEncodedSigner, new BYTE[cbEncodedSigner]);
  200. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CryptMsgGetParam( hMsg, CMSG_ENCODED_SIGNER, index, pbEncodedSigner, &cbEncodedSigner ));
  201. //
  202. // decode the EncodedSigner info
  203. //
  204. ::CryptDecodeObject( PKCS_7_ASN_ENCODING|CRYPT_ASN_ENCODING, PKCS7_SIGNER_INFO, pbEncodedSigner, cbEncodedSigner, 0, NULL, &cbSignerInfo );
  205. __MPC_EXIT_IF_ALLOC_FAILS(hr, pSignerInfo, new BYTE[cbSignerInfo]);
  206. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CryptDecodeObject( PKCS_7_ASN_ENCODING|CRYPT_ASN_ENCODING, PKCS7_SIGNER_INFO,
  207. pbEncodedSigner, cbEncodedSigner, 0, pSignerInfo, &cbSignerInfo ));
  208. hr = S_OK;
  209. __HCP_FUNC_CLEANUP;
  210. delete [] pbEncodedSigner;
  211. __HCP_FUNC_EXIT(hr);
  212. }
  213. HRESULT Taxonomy::Package::Authenticate( /*[in]*/ Logger& log )
  214. {
  215. __HCP_FUNC_ENTRY( "Taxonomy::Package::Authenticate" );
  216. HRESULT hr;
  217. if(m_fBuiltin == false)
  218. {
  219. __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateFileName());
  220. //
  221. // First, verify the signature is valid.
  222. //
  223. {
  224. WINTRUST_DATA wtdWinTrust;
  225. WINTRUST_FILE_INFO wtfWinTrustFile;
  226. GUID c_guidPubSoftwareTrustProv = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  227. //
  228. // set up wintrust file info struct
  229. //
  230. ::ZeroMemory( &wtfWinTrustFile, sizeof(wtfWinTrustFile) );
  231. wtfWinTrustFile.cbStruct = sizeof(wtfWinTrustFile);
  232. wtfWinTrustFile.pcwszFilePath = m_strFileName.c_str();
  233. wtfWinTrustFile.hFile = NULL;
  234. //
  235. // set up wintrust data struct
  236. //
  237. ::ZeroMemory( &wtdWinTrust, sizeof(wtdWinTrust) );
  238. wtdWinTrust.cbStruct = sizeof(wtdWinTrust);
  239. wtdWinTrust.dwUnionChoice = WTD_CHOICE_FILE;
  240. wtdWinTrust.pFile = &wtfWinTrustFile;
  241. wtdWinTrust.dwUIChoice = WTD_UI_NONE; // Whistler special : must always be silent otherwise won't come back
  242. // Verify the trust of the help package
  243. if(FAILED(hr = ::WinVerifyTrust( 0, &c_guidPubSoftwareTrustProv, &wtdWinTrust )))
  244. {
  245. LPCWSTR szError;
  246. switch(hr)
  247. {
  248. case TRUST_E_SUBJECT_NOT_TRUSTED : szError = L"subject not trusted" ; break;
  249. case TRUST_E_PROVIDER_UNKNOWN : szError = L"provider unknown" ; break;
  250. case TRUST_E_ACTION_UNKNOWN : szError = L"action unknown" ; break;
  251. case TRUST_E_SUBJECT_FORM_UNKNOWN: szError = L"subject form unknown"; break;
  252. default: szError = L"unknown" ; break;
  253. }
  254. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( hr, L"Help package cannot be trusted\nError WinVerifyTrust %s", szError ));
  255. }
  256. }
  257. //
  258. // Then open the certificate and extract the DN.
  259. //
  260. {
  261. HCRYPTMSG hMsg = NULL;
  262. m_strVendorID.erase();
  263. if(::CryptQueryObject( CERT_QUERY_OBJECT_FILE,
  264. m_strFileName.c_str(),
  265. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
  266. CERT_QUERY_FORMAT_FLAG_BINARY ,
  267. 0, NULL, NULL, NULL, NULL, &hMsg, NULL ))
  268. {
  269. HCERTSTORE hCertStore;
  270. hCertStore = ::CertOpenStore( CERT_STORE_PROV_MSG, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, NULL, (const void *)hMsg );
  271. if(hCertStore)
  272. {
  273. BYTE* rgSignerInfo = NULL;
  274. if(SUCCEEDED(local_GetSignerInfo( hMsg, 0, rgSignerInfo )))
  275. {
  276. PCMSG_SIGNER_INFO pSignerInfo = (PCMSG_SIGNER_INFO)rgSignerInfo;
  277. CERT_INFO certInfo; ::ZeroMemory( &certInfo, sizeof(certInfo) );
  278. PCCERT_CONTEXT pCertContext;
  279. certInfo.SerialNumber = pSignerInfo->SerialNumber;
  280. certInfo.Issuer = pSignerInfo->Issuer;
  281. pCertContext = ::CertGetSubjectCertificateFromStore( hCertStore, X509_ASN_ENCODING, &certInfo );
  282. if(pCertContext)
  283. {
  284. local_GetDNInfo( pCertContext, szOID_COMMON_NAME , L"CN=", m_strVendorID, &m_strVendorName );
  285. local_GetDNInfo( pCertContext, szOID_LOCALITY_NAME , L"L=" , m_strVendorID );
  286. local_GetDNInfo( pCertContext, szOID_STATE_OR_PROVINCE_NAME, L"S=" , m_strVendorID );
  287. local_GetDNInfo( pCertContext, szOID_COUNTRY_NAME , L"C=" , m_strVendorID );
  288. ::CertFreeCertificateContext( pCertContext );
  289. }
  290. delete [] rgSignerInfo;
  291. }
  292. ::CertCloseStore( hCertStore, 0 );
  293. }
  294. ::CryptMsgClose( hMsg );
  295. }
  296. if(m_strVendorID.size() == 0)
  297. {
  298. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), L"Help package cannot be trusted: unable to extract signer\n" ));
  299. }
  300. //
  301. // Escape unsafe character in the CertID.
  302. //
  303. {
  304. LPWSTR szCertID = (LPWSTR)m_strVendorID.c_str();
  305. while(szCertID[0])
  306. {
  307. switch(szCertID[0])
  308. {
  309. case L'\\':
  310. case L'/':
  311. case L':':
  312. case L'*':
  313. case L'?':
  314. case L'"':
  315. case L'<':
  316. case L'>':
  317. case L'|':
  318. szCertID[0] = L'_';
  319. }
  320. szCertID++;
  321. }
  322. }
  323. }
  324. }
  325. else
  326. {
  327. m_strVendorID = HC_MICROSOFT_DN;
  328. MPC::LocalizeString( IDS_HELPSVC_SEMGR_OWNER, m_strVendorName );
  329. }
  330. m_fMicrosoft = (MPC::StrICmp( m_strVendorID, HC_MICROSOFT_DN ) == 0);
  331. //
  332. // Extract package info from packagedescription.xml
  333. //
  334. {
  335. MPC::XmlUtil xml;
  336. bool fFound;
  337. __MPC_EXIT_IF_METHOD_FAILS(hr, ExtractPkgDesc( log, xml ));
  338. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"PRODUCT", L"ID", m_strProductID, fFound ));
  339. if(fFound == false) // Set some default.
  340. {
  341. m_strProductID = L"<default>";
  342. }
  343. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"VERSION", L"VALUE", m_strVersion, fFound ));
  344. if(fFound == false) // Set some default.
  345. {
  346. m_strVersion = L"1.0.0.0";
  347. }
  348. if(m_fBuiltin == false) // System packages inherit SKU/Language from the database.
  349. {
  350. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"SKU", L"VALUE", m_strSKU, fFound ));
  351. if(fFound == false) // Not a valid package!!
  352. {
  353. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( E_INVALIDARG, L"Missing SKU element" ));
  354. }
  355. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"LANGUAGE", L"VALUE", m_strLanguage, fFound ));
  356. if(fFound == false) // Not a valid package!!
  357. {
  358. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( E_INVALIDARG, L"Missing LANGAUGE element" ));
  359. }
  360. }
  361. }
  362. if(m_lSequence >= 0)
  363. {
  364. m_fTemporary = false;
  365. }
  366. hr = S_OK;
  367. __HCP_FUNC_CLEANUP;
  368. __HCP_FUNC_EXIT(hr);
  369. }
  370. HRESULT Taxonomy::Package::Remove( /*[in]*/ Logger& log )
  371. {
  372. __HCP_FUNC_ENTRY( "Taxonomy::Package::Remove" );
  373. HRESULT hr;
  374. //
  375. // There's no private file for this package, nothing to do.
  376. //
  377. if(m_lSequence == -1)
  378. {
  379. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  380. }
  381. if(m_lSequence)
  382. {
  383. if(SUCCEEDED(GenerateFileName()))
  384. {
  385. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::DeleteFile( m_strFileName ));
  386. log.WriteLog( -1, L"\nRemove package %s [%s] (Vendor: %s) from package store\n\n", m_strProductID.c_str(), m_strVersion.c_str(), m_strVendorID.c_str() );
  387. m_strFileName.erase();
  388. }
  389. }
  390. hr = S_OK;
  391. __HCP_FUNC_CLEANUP;
  392. __HCP_FUNC_EXIT(hr);
  393. }
  394. HRESULT Taxonomy::Package::ExtractFile( /*[in]*/ Logger& log ,
  395. /*[in]*/ LPCWSTR szFileDestination ,
  396. /*[in]*/ LPCWSTR szNameInCabinet )
  397. {
  398. __HCP_FUNC_ENTRY( "Taxonomy::Package::ExtractFile" );
  399. HRESULT hr;
  400. __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateFileName());
  401. if(FAILED(hr = MPC::DecompressFromCabinet( m_strFileName.c_str(), szFileDestination, szNameInCabinet )))
  402. {
  403. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( hr, L"Error extracting %s from help package", szNameInCabinet ));
  404. }
  405. log.WriteLog( S_OK, L"Extracted %s from help package", szNameInCabinet );
  406. hr = S_OK;
  407. __HCP_FUNC_CLEANUP;
  408. __HCP_FUNC_EXIT(hr);
  409. }
  410. HRESULT Taxonomy::Package::ExtractXMLFile( /*[in]*/ Logger& log ,
  411. /*[in]*/ MPC::XmlUtil& xml ,
  412. /*[in]*/ LPCWSTR szTag ,
  413. /*[in]*/ LPCWSTR szNameInCabinet )
  414. {
  415. __HCP_FUNC_ENTRY( "Taxonomy::Package::ExtractXMLFile" );
  416. HRESULT hr;
  417. MPC::wstring strTmp;
  418. bool fLoaded;
  419. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( strTmp ));
  420. __MPC_EXIT_IF_METHOD_FAILS(hr, ExtractFile( log, strTmp.c_str(), szNameInCabinet ));
  421. // load the XML with the root tag
  422. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.Load( strTmp.c_str(), szTag, fLoaded ));
  423. if(fLoaded == false)
  424. {
  425. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), L"Error invalid XML in %s", szNameInCabinet ));
  426. }
  427. hr = S_OK;
  428. __HCP_FUNC_CLEANUP;
  429. (void)MPC::RemoveTemporaryFile( strTmp );
  430. __HCP_FUNC_EXIT(hr);
  431. }
  432. HRESULT Taxonomy::Package::ExtractPkgDesc( /*[in]*/ Logger& log ,
  433. /*[in]*/ MPC::XmlUtil& xml )
  434. {
  435. return ExtractXMLFile( log, xml, Taxonomy::Strings::s_tag_root_PackageDescription, Taxonomy::Strings::s_file_PackageDescription );
  436. }
  437. ////////////////////////////////////////////////////////////////////////////////
  438. ////////////////////////////////////////////////////////////////////////////////
  439. Taxonomy::ProcessedPackage::ProcessedPackage()
  440. {
  441. m_lSequence = 0; // long m_lSequence;
  442. m_fProcessed = false; // bool m_fProcessed;
  443. m_fDisabled = false; // bool m_fDisabled;
  444. }
  445. HRESULT Taxonomy::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ Taxonomy::ProcessedPackage& val )
  446. {
  447. HRESULT hr;
  448. if(SUCCEEDED(hr = (stream >> val.m_lSequence )) &&
  449. SUCCEEDED(hr = (stream >> val.m_fProcessed)) &&
  450. SUCCEEDED(hr = (stream >> val.m_fDisabled )) )
  451. {
  452. hr = S_OK;
  453. }
  454. return hr;
  455. }
  456. HRESULT Taxonomy::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const Taxonomy::ProcessedPackage& val )
  457. {
  458. HRESULT hr;
  459. if(SUCCEEDED(hr = (stream << val.m_lSequence )) &&
  460. SUCCEEDED(hr = (stream << val.m_fProcessed)) &&
  461. SUCCEEDED(hr = (stream << val.m_fDisabled )) )
  462. {
  463. hr = S_OK;
  464. }
  465. return hr;
  466. }