Leaked source code of windows server 2003
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.

609 lines
19 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. sxsasmname.cpp
  5. Abstract:
  6. CAssemblyName implementation for installation
  7. Author:
  8. Xiaoyu Wu (xiaoyuw) May 2000
  9. Revision History:
  10. xiaoyuw 09/20000 rewrite the code to use Assembly Identity
  11. --*/
  12. #include "stdinc.h"
  13. #include "sxsasmname.h"
  14. #include "fusionparser.h"
  15. #include "sxsp.h"
  16. #include "sxsid.h"
  17. #include "sxsidp.h"
  18. #include "sxsapi.h"
  19. #include "fusiontrace.h"
  20. // ---------------------------------------------------------------------------
  21. // CreateAssemblyNameObject
  22. // ---------------------------------------------------------------------------
  23. STDAPI
  24. CreateAssemblyNameObject(
  25. LPASSEMBLYNAME *ppAssemblyName,
  26. LPCOLESTR szAssemblyName,
  27. DWORD dwFlags,
  28. LPVOID pvReserved
  29. )
  30. {
  31. FN_PROLOG_HR
  32. CSmartPtr<CAssemblyName> pName;
  33. if (ppAssemblyName)
  34. *ppAssemblyName = NULL ;
  35. // validate dwFlags
  36. // BUGBUG : the valid value of dwFlags are CANOF_PARSE_DISPLAY_NAME and CANOF_SET_DEFAULT_VALUES, but CANOF_SET_DEFAULT_VALUES
  37. // is never used...
  38. // xiaoyuw@10/02/2000
  39. //
  40. PARAMETER_CHECK(dwFlags == CANOF_PARSE_DISPLAY_NAME);
  41. PARAMETER_CHECK(ppAssemblyName != NULL);
  42. PARAMETER_CHECK(pvReserved == NULL);
  43. IFW32FALSE_EXIT(pName.Win32Allocate(__FILE__, __LINE__));
  44. if (dwFlags & CANOF_PARSE_DISPLAY_NAME)
  45. IFCOMFAILED_EXIT(pName->Parse((LPWSTR)szAssemblyName));
  46. IFCOMFAILED_EXIT(pName->QueryInterface(IID_IAssemblyName, (PVOID*)ppAssemblyName));
  47. pName.Detach();
  48. FN_EPILOG
  49. }
  50. STDMETHODIMP
  51. CAssemblyName::SetProperty(DWORD PropertyId,
  52. LPVOID pvProperty, DWORD cbProperty)
  53. {
  54. HRESULT hr = NOERROR;
  55. FN_TRACE_HR(hr);
  56. PCSXS_ASSEMBLY_IDENTITY_ATTRIBUTE_REFERENCE Attribute = NULL;
  57. // this function is only called inside fusion, so this fucntion has no impact on Darwin
  58. // maybe more should be added for Assembly Identity, such as StrongName, or random policies
  59. //
  60. if ((!pvProperty) || ((PropertyId != SXS_ASM_NAME_NAME) &&
  61. (PropertyId != SXS_ASM_NAME_VERSION) &&
  62. (PropertyId != SXS_ASM_NAME_TYPE) &&
  63. (PropertyId != SXS_ASM_NAME_PUBLICKEYTOKEN) &&
  64. (PropertyId != SXS_ASM_NAME_PROCESSORARCHITECTURE) &&
  65. (PropertyId != SXS_ASM_NAME_LANGUAGE))){
  66. hr = E_INVALIDARG;
  67. goto Exit;
  68. }
  69. // Fail if finalized.
  70. if (m_fIsFinalized){
  71. hr = E_UNEXPECTED;
  72. goto Exit;
  73. }
  74. switch (PropertyId)
  75. {
  76. case SXS_ASM_NAME_NAME: Attribute = &s_IdentityAttribute_name; break;
  77. case SXS_ASM_NAME_VERSION: Attribute = &s_IdentityAttribute_version; break;
  78. case SXS_ASM_NAME_PROCESSORARCHITECTURE: Attribute = &s_IdentityAttribute_processorArchitecture; break;
  79. case SXS_ASM_NAME_LANGUAGE: Attribute = &s_IdentityAttribute_language; break;
  80. case SXS_ASM_NAME_TYPE: Attribute = &s_IdentityAttribute_type; break;
  81. case SXS_ASM_NAME_PUBLICKEYTOKEN: Attribute = &s_IdentityAttribute_publicKeyToken; break;
  82. }
  83. INTERNAL_ERROR_CHECK(Attribute != NULL);
  84. IFW32FALSE_EXIT(::SxspSetAssemblyIdentityAttributeValue(0, m_pAssemblyIdentity, Attribute, (PCWSTR) pvProperty, cbProperty / sizeof(WCHAR)));
  85. hr = NOERROR;
  86. Exit:
  87. return hr;
  88. }
  89. // ---------------------------------------------------------------------------
  90. // CAssemblyName::GetProperty
  91. // ---------------------------------------------------------------------------
  92. STDMETHODIMP
  93. CAssemblyName::GetProperty(DWORD PropertyId,
  94. /* [in] */ LPVOID pvProperty,
  95. /* [out][in] */ LPDWORD pcbProperty)
  96. {
  97. HRESULT hr = NOERROR;
  98. FN_TRACE_HR(hr);
  99. PCWSTR pszAttributeValue = NULL;
  100. SIZE_T CchAttributeValue = 0;
  101. PCSXS_ASSEMBLY_IDENTITY_ATTRIBUTE_REFERENCE Attribute = NULL;
  102. if ((!pvProperty) || (!pcbProperty) || ((PropertyId != SXS_ASM_NAME_NAME) &&
  103. (PropertyId != SXS_ASM_NAME_VERSION) &&
  104. (PropertyId != SXS_ASM_NAME_TYPE) &&
  105. (PropertyId != SXS_ASM_NAME_PUBLICKEYTOKEN) &&
  106. (PropertyId != SXS_ASM_NAME_PROCESSORARCHITECTURE) &&
  107. (PropertyId != SXS_ASM_NAME_LANGUAGE))){
  108. hr = E_INVALIDARG;
  109. goto Exit;
  110. }
  111. switch (PropertyId)
  112. {
  113. case SXS_ASM_NAME_NAME: Attribute = &s_IdentityAttribute_name; break;
  114. case SXS_ASM_NAME_VERSION: Attribute = &s_IdentityAttribute_version; break;
  115. case SXS_ASM_NAME_PROCESSORARCHITECTURE: Attribute = &s_IdentityAttribute_processorArchitecture; break;
  116. case SXS_ASM_NAME_LANGUAGE: Attribute = &s_IdentityAttribute_language; break;
  117. case SXS_ASM_NAME_TYPE: Attribute = &s_IdentityAttribute_type; break;
  118. case SXS_ASM_NAME_PUBLICKEYTOKEN: Attribute = &s_IdentityAttribute_publicKeyToken; break;
  119. }
  120. INTERNAL_ERROR_CHECK(Attribute != NULL);
  121. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(0, m_pAssemblyIdentity, Attribute, &pszAttributeValue, &CchAttributeValue));
  122. // check whether we have valid attributes
  123. if (pszAttributeValue == NULL){ // attributes not set yet
  124. hr = E_UNEXPECTED;
  125. goto Exit;
  126. }
  127. if (CchAttributeValue * sizeof(WCHAR) > *pcbProperty) { // buffer size is not big enough
  128. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  129. *pcbProperty = static_cast<DWORD>(CchAttributeValue * sizeof(WCHAR));
  130. goto Exit;
  131. }
  132. // copy the string into the output buffer
  133. memcpy(pvProperty, pszAttributeValue, CchAttributeValue *sizeof(WCHAR));
  134. if (pcbProperty)
  135. *pcbProperty = static_cast<DWORD>(CchAttributeValue * sizeof(WCHAR));
  136. hr = NOERROR;
  137. Exit:
  138. return hr;
  139. }
  140. // ---------------------------------------------------------------------------
  141. // CAssemblyName::GetName
  142. // ---------------------------------------------------------------------------
  143. STDMETHODIMP
  144. CAssemblyName::GetName(
  145. /* [out][in] */ LPDWORD lpcwBuffer,
  146. /* [out] */ WCHAR *pwzName)
  147. {
  148. HRESULT hr = NOERROR;
  149. FN_TRACE_HR(hr);
  150. if (!lpcwBuffer || !pwzName){
  151. hr = E_INVALIDARG;
  152. goto Exit;
  153. }
  154. IFCOMFAILED_EXIT(this->GetProperty(SXS_ASM_NAME_NAME, pwzName, lpcwBuffer));
  155. FN_EPILOG
  156. }
  157. // ---------------------------------------------------------------------------
  158. // CAssemblyName::GetVersion
  159. // ---------------------------------------------------------------------------
  160. STDMETHODIMP
  161. CAssemblyName::GetVersion(
  162. /* [out] */ LPDWORD pdwVersionHi,
  163. /* [out] */ LPDWORD pdwVersionLow)
  164. {
  165. HRESULT hr = NOERROR;
  166. FN_TRACE_HR(hr);
  167. PCWSTR pszAttributeValue = NULL;
  168. SIZE_T CchAttributeValue = 0;
  169. ASSEMBLY_VERSION ver;
  170. bool fSyntaxValid = false;
  171. if ((!pdwVersionHi) || (!pdwVersionLow)){
  172. hr = E_INVALIDARG;
  173. goto Exit;
  174. }
  175. IFW32FALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(0, m_pAssemblyIdentity, &s_IdentityAttribute_version, &pszAttributeValue, &CchAttributeValue));
  176. if (pszAttributeValue == NULL)
  177. {
  178. hr = E_UNEXPECTED;
  179. goto Exit;
  180. }
  181. IFW32FALSE_EXIT(CFusionParser::ParseVersion(ver, pszAttributeValue, CchAttributeValue, fSyntaxValid));
  182. if (!fSyntaxValid)
  183. {
  184. hr = HRESULT_FROM_WIN32(ERROR_SXS_MANIFEST_PARSE_ERROR);
  185. goto Exit;
  186. }
  187. *pdwVersionHi = MAKELONG(ver.Minor, ver.Major);
  188. *pdwVersionLow = MAKELONG(ver.Build, ver.Revision);
  189. FN_EPILOG
  190. }
  191. // ---------------------------------------------------------------------------
  192. // CAssemblyName::IsEqual
  193. // ---------------------------------------------------------------------------
  194. STDMETHODIMP
  195. CAssemblyName::IsEqual(LPASSEMBLYNAME pName, DWORD dwCmpFlags)
  196. {
  197. HRESULT hr = NOERROR;
  198. FN_TRACE_HR(hr);
  199. BOOL fEqual = FALSE;
  200. PARAMETER_CHECK(pName != NULL);
  201. IFW32FALSE_EXIT(::SxsAreAssemblyIdentitiesEqual(0, m_pAssemblyIdentity, static_cast<CAssemblyName *>(pName)->m_pAssemblyIdentity, &fEqual));
  202. if (fEqual)
  203. hr = S_OK;
  204. else
  205. hr = E_FAIL; // not acurrate, however, it depends on Darwin caller.
  206. Exit:
  207. return hr;
  208. }
  209. // ---------------------------------------------------------------------------
  210. // CAssemblyName constructor
  211. // ---------------------------------------------------------------------------
  212. CAssemblyName::CAssemblyName():m_cRef(0),
  213. m_fIsFinalized(FALSE),
  214. m_pAssemblyIdentity(NULL)
  215. {
  216. }
  217. // ---------------------------------------------------------------------------
  218. // CAssemblyName destructor
  219. // ---------------------------------------------------------------------------
  220. CAssemblyName::~CAssemblyName()
  221. {
  222. ASSERT_NTC(m_cRef == 0 );
  223. if (m_pAssemblyIdentity)
  224. {
  225. CSxsPreserveLastError ple;
  226. ::SxsDestroyAssemblyIdentity(m_pAssemblyIdentity);
  227. ple.Restore();
  228. }
  229. }
  230. // ---------------------------------------------------------------------------
  231. // CAssemblyName::Init
  232. // ---------------------------------------------------------------------------
  233. HRESULT
  234. CAssemblyName::Init(LPCWSTR pszAssemblyName, PVOID pamd)
  235. {
  236. HRESULT hr = S_OK;
  237. FN_TRACE_HR(hr);
  238. SIZE_T CchAssemblyName = 0;
  239. UNUSED(pamd);
  240. //ASSERT(m_pAssemblyIdentity == NULL);
  241. if (m_pAssemblyIdentity)
  242. {
  243. hr = E_UNEXPECTED;
  244. goto Exit;
  245. }
  246. IFW32FALSE_EXIT(::SxsCreateAssemblyIdentity(0, ASSEMBLY_IDENTITY_TYPE_DEFINITION, &m_pAssemblyIdentity, 0, NULL));
  247. // set name if present
  248. if (pszAssemblyName != NULL)
  249. {
  250. CchAssemblyName = wcslen(pszAssemblyName);
  251. IFW32FALSE_EXIT(::SxspSetAssemblyIdentityAttributeValue(0, m_pAssemblyIdentity, &s_IdentityAttribute_name, pszAssemblyName, wcslen(pszAssemblyName)));
  252. }
  253. hr = NOERROR;
  254. Exit:
  255. return hr;
  256. }
  257. // ---------------------------------------------------------------------------
  258. // CAssemblyName::Init
  259. // ---------------------------------------------------------------------------
  260. HRESULT CAssemblyName::Clone(IAssemblyName **ppName)
  261. {
  262. HRESULT hr = NOERROR;
  263. FN_TRACE_HR(hr);
  264. PASSEMBLY_IDENTITY pAssemblyIdentity = NULL;
  265. CAssemblyName *pName= NULL;
  266. if (ppName)
  267. *ppName = NULL;
  268. if (!ppName){
  269. hr = E_INVALIDARG ;
  270. goto Exit;
  271. }
  272. if (m_pAssemblyIdentity)
  273. {
  274. IFW32FALSE_EXIT(
  275. ::SxsDuplicateAssemblyIdentity(
  276. 0, // DWORD Flags,
  277. m_pAssemblyIdentity, // PCASSEMBLY_IDENTITY Source,
  278. &pAssemblyIdentity)); // PASSEMBLY_IDENTITY *Destination
  279. }
  280. IFALLOCFAILED_EXIT(pName = new CAssemblyName);
  281. pName->m_pAssemblyIdentity = pAssemblyIdentity;
  282. pAssemblyIdentity = NULL;
  283. *ppName = pName;
  284. pName = NULL;
  285. hr = NOERROR;
  286. Exit:
  287. if (pAssemblyIdentity)
  288. ::SxsDestroyAssemblyIdentity(pAssemblyIdentity);
  289. if (pName)
  290. FUSION_DELETE_SINGLETON(pName);
  291. return hr;
  292. }
  293. // ---------------------------------------------------------------------------
  294. // CAssemblyName::BindToObject
  295. // ---------------------------------------------------------------------------
  296. STDMETHODIMP
  297. CAssemblyName::BindToObject(
  298. /* in */ REFIID refIID,
  299. /* in */ IAssemblyBindSink *pAsmBindSink,
  300. /* in */ IApplicationContext *pAppCtx,
  301. /* in */ LPCOLESTR szCodebase,
  302. /* in */ LONGLONG llFlags,
  303. /* in */ LPVOID pvReserved,
  304. /* in */ DWORD cbReserved,
  305. /* out */ VOID **ppv)
  306. {
  307. if (!ppv)
  308. return E_INVALIDARG ;
  309. *ppv = NULL;
  310. return E_NOTIMPL;
  311. }
  312. // ---------------------------------------------------------------------------
  313. // CAssemblyName::Finalize
  314. // ---------------------------------------------------------------------------
  315. STDMETHODIMP
  316. CAssemblyName::Finalize()
  317. {
  318. m_fIsFinalized = TRUE;
  319. return NOERROR;
  320. }
  321. //-----------------------------------------------------------------------------------
  322. // CAssemblyName::GetDisplayName
  323. // it would be name,ns1:n1="v1",ns2:n2="v2",ns3:n3="v3",ns4:n4="v4"
  324. // I have to put name first in order not to change Darwin's code
  325. //
  326. // xiaoyuw@09/29/2000
  327. //-----------------------------------------------------------------------------------
  328. STDMETHODIMP
  329. CAssemblyName::GetDisplayName(LPOLESTR szDisplayName,
  330. LPDWORD pccDisplayName, DWORD dwDisplayFlags)
  331. {
  332. HRESULT hr = NOERROR;
  333. FN_TRACE_HR(hr);
  334. SIZE_T BufferSize;
  335. SIZE_T BytesWrittenOrRequired = 0;
  336. PARAMETER_CHECK(pccDisplayName != NULL);
  337. PARAMETER_CHECK((szDisplayName != NULL) || (*pccDisplayName == 0));
  338. PARAMETER_CHECK(dwDisplayFlags == 0);
  339. // Need buffer size in bytes...
  340. BufferSize = (*pccDisplayName) * sizeof(WCHAR);
  341. IFW32FALSE_EXIT(
  342. ::SxsEncodeAssemblyIdentity(
  343. 0,
  344. m_pAssemblyIdentity,
  345. NULL,
  346. SXS_ASSEMBLY_IDENTITY_ENCODING_DEFAULTGROUP_TEXTUAL,
  347. BufferSize,
  348. szDisplayName,
  349. &BytesWrittenOrRequired));
  350. if ((BufferSize - BytesWrittenOrRequired) < sizeof(WCHAR))
  351. {
  352. // We actually could fit everything but the trailing null character...
  353. // the BytesWrittenOrRequired actually has the right value for the exit path below;
  354. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  355. goto Exit;
  356. }else // add the trailing NULL
  357. {
  358. szDisplayName[BytesWrittenOrRequired / sizeof (*szDisplayName)] = L'\0';
  359. }
  360. hr = NOERROR;
  361. Exit:
  362. if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
  363. *pccDisplayName = static_cast<DWORD>((BytesWrittenOrRequired / sizeof(WCHAR)) + 1);
  364. return hr;
  365. }
  366. HRESULT CAssemblyName::Parse(LPCWSTR szDisplayName)
  367. {
  368. HRESULT hr = NOERROR;
  369. FN_TRACE_HR(hr);
  370. PASSEMBLY_IDENTITY pAssemblyIdentity = NULL;
  371. // Verify display name passed in.
  372. PARAMETER_CHECK(szDisplayName != NULL);
  373. PARAMETER_CHECK(szDisplayName[0] != L'\0');
  374. IFW32FALSE_EXIT(
  375. ::SxspCreateAssemblyIdentityFromTextualString(
  376. szDisplayName,
  377. &pAssemblyIdentity));
  378. if (m_pAssemblyIdentity != NULL)
  379. ::SxsDestroyAssemblyIdentity(m_pAssemblyIdentity);
  380. m_pAssemblyIdentity = pAssemblyIdentity;
  381. pAssemblyIdentity = NULL;
  382. hr = NOERROR;
  383. Exit:
  384. if (pAssemblyIdentity != NULL)
  385. ::SxsDestroyAssemblyIdentity(pAssemblyIdentity);
  386. return hr;
  387. }
  388. // ---------------------------------------------------------------------------
  389. // CAssemblyName::GetInstalledAssemblyName
  390. // ---------------------------------------------------------------------------
  391. HRESULT
  392. CAssemblyName::GetInstalledAssemblyName(
  393. IN DWORD Flags,
  394. IN ULONG PathType,
  395. CBaseStringBuffer &rBufInstallPath
  396. )
  397. {
  398. HRESULT hr = NOERROR;
  399. FN_TRACE_HR(hr);
  400. if (Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT)
  401. {
  402. IFW32FALSE_EXIT(
  403. ::SxspGenerateSxsPath(
  404. Flags,
  405. PathType,
  406. NULL,
  407. 0,
  408. m_pAssemblyIdentity,
  409. NULL,
  410. rBufInstallPath));
  411. ::FusionpDbgPrintEx(
  412. FUSION_DBG_LEVEL_MSI_INSTALL,
  413. "SXS: %s - Generated %Iu character (root omitted) installation path:\n"
  414. " \"%ls\"\n",
  415. __FUNCTION__, rBufInstallPath.Cch(),
  416. static_cast<PCWSTR>(rBufInstallPath));
  417. }
  418. else
  419. {
  420. CStringBuffer bufRootDir;
  421. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(bufRootDir));
  422. IFW32FALSE_EXIT(bufRootDir.Win32EnsureTrailingPathSeparator());
  423. IFW32FALSE_EXIT(
  424. ::SxspGenerateSxsPath(
  425. Flags,
  426. PathType,
  427. bufRootDir,
  428. bufRootDir.Cch(),
  429. m_pAssemblyIdentity,
  430. NULL,
  431. rBufInstallPath));
  432. ::FusionpDbgPrintEx(
  433. FUSION_DBG_LEVEL_MSI_INSTALL,
  434. "SXS: %s - Generated %Iu character installation path:\n"
  435. " \"%ls\"\n",
  436. __FUNCTION__, rBufInstallPath.Cch(),
  437. static_cast<PCWSTR>(rBufInstallPath));
  438. }
  439. FN_EPILOG
  440. }
  441. //
  442. // this function calls SxsProbeAssemblyInstallation to decide whether an assembly installed or not.
  443. // and fInstalled set to be TRUE only if the assembly is both INSTALLed and RESIDENT
  444. //
  445. HRESULT
  446. CAssemblyName::IsAssemblyInstalled(
  447. BOOL &fInstalled)
  448. {
  449. FN_PROLOG_HR
  450. DWORD dwDisposition;
  451. INTERNAL_ERROR_CHECK(m_pAssemblyIdentity != NULL);
  452. //
  453. // SxsProbeAssemblyInstallation knows that if you passed the "precomposed" flag, then
  454. // lpAsmIdentSource really points at a PCASSEMBLY_IDENTITY structure.
  455. //
  456. IFW32FALSE_EXIT(
  457. SxsProbeAssemblyInstallation(
  458. SXS_PROBE_ASSEMBLY_INSTALLATION_IDENTITY_PRECOMPOSED,
  459. reinterpret_cast<PCWSTR>(static_cast<PCASSEMBLY_IDENTITY>(m_pAssemblyIdentity)),
  460. &dwDisposition));
  461. if ((dwDisposition & SXS_PROBE_ASSEMBLY_INSTALLATION_DISPOSITION_INSTALLED) &&
  462. (dwDisposition & SXS_PROBE_ASSEMBLY_INSTALLATION_DISPOSITION_RESIDENT))
  463. {
  464. fInstalled = TRUE;
  465. }else
  466. {
  467. fInstalled = FALSE;
  468. }
  469. FN_EPILOG
  470. }
  471. // IUnknown methods
  472. // ---------------------------------------------------------------------------
  473. // CAssemblyName::AddRef
  474. // ---------------------------------------------------------------------------
  475. STDMETHODIMP_(ULONG)
  476. CAssemblyName::AddRef()
  477. {
  478. return ::SxspInterlockedIncrement(&m_cRef);
  479. }
  480. // ---------------------------------------------------------------------------
  481. // CAssemblyName::Release
  482. // ---------------------------------------------------------------------------
  483. STDMETHODIMP_(ULONG)
  484. CAssemblyName::Release()
  485. {
  486. ULONG lRet = ::SxspInterlockedDecrement(&m_cRef);
  487. if (!lRet)
  488. FUSION_DELETE_SINGLETON(this);
  489. return lRet;
  490. }
  491. // ---------------------------------------------------------------------------
  492. // CAssemblyName::QueryInterface
  493. // ---------------------------------------------------------------------------
  494. STDMETHODIMP
  495. CAssemblyName::QueryInterface(REFIID riid, void** ppv)
  496. {
  497. if ( IsEqualIID(riid, IID_IUnknown)
  498. || IsEqualIID(riid, IID_IAssemblyName)){
  499. *ppv = static_cast<IAssemblyName*> (this);
  500. AddRef();
  501. return S_OK;
  502. }
  503. else{
  504. *ppv = NULL;
  505. return E_NOINTERFACE;
  506. }
  507. }
  508. HRESULT
  509. CAssemblyName::DetermineAssemblyType(BOOL &fIsPolicy)
  510. {
  511. HRESULT hr = E_FAIL;
  512. FN_TRACE_HR(hr);
  513. INTERNAL_ERROR_CHECK( m_pAssemblyIdentity != NULL );
  514. IFW32FALSE_EXIT(::SxspDetermineAssemblyType(m_pAssemblyIdentity, fIsPolicy));
  515. hr = S_OK;
  516. Exit:
  517. return hr;
  518. }