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.
1828 lines
70 KiB
1828 lines
70 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
actctxgen.cpp
|
|
|
|
Abstract:
|
|
|
|
APIs for generating activation contexts.
|
|
|
|
Author:
|
|
|
|
Michael J. Grier (MGrier) 23-Feb-2000
|
|
|
|
Revision History:
|
|
xiaoyuw 09/2000 replace attributes with assembly identity
|
|
--*/
|
|
|
|
#include "stdinc.h"
|
|
#include <windows.h>
|
|
#include <sxsp.h>
|
|
#include <ole2.h>
|
|
#include <xmlparser.h>
|
|
#include "nodefactory.h"
|
|
#include <wchar.h>
|
|
#include "filestream.h"
|
|
#include "fusionhandle.h"
|
|
#include "cteestream.h"
|
|
#include "cresourcestream.h"
|
|
#include "fusionxml.h"
|
|
#include "util.h"
|
|
#include "sxsexceptionhandling.h"
|
|
#include "csxspreservelasterror.h"
|
|
#include "smartptr.h"
|
|
#include "cstreamtap.h"
|
|
#include "pendingassembly.h"
|
|
#include "actctxgenctx.h"
|
|
|
|
BOOL
|
|
SxspFindAssemblyByName(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PCWSTR AssemblyName,
|
|
SIZE_T AssemblyNameCch,
|
|
PASSEMBLY *AssemblyFound
|
|
);
|
|
|
|
BOOL
|
|
SxspAddAssemblyToActivationContextGenerationContext(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PASSEMBLY Asm
|
|
);
|
|
|
|
_ACTCTXGENCTX::_ACTCTXGENCTX()
|
|
:
|
|
m_Contributors(NULL),
|
|
m_ContributorCount(0),
|
|
m_ProcessorArchitecture(0),
|
|
m_LangID(0),
|
|
m_Flags(0),
|
|
m_ManifestOperation(MANIFEST_OPERATION_INVALID),
|
|
m_ManifestOperationFlags(0),
|
|
m_NextAssemblyRosterIndex(1),
|
|
m_fClsidMapInitialized(FALSE),
|
|
m_InitializedContributorCount(0),
|
|
m_NoInherit(false),
|
|
m_pNodeFactory(NULL),
|
|
m_ulFileCount(0),
|
|
m_fAppApplyPublisherPolicy(SXS_PUBLISHER_POLICY_APPLY_DEFAULT),
|
|
m_ApplicationDirectoryHasBeenProbedForLanguageSubdirs(false),
|
|
m_ApplicationDirectoryHasSpecificLanguageSubdir(false),
|
|
m_ApplicationDirectoryHasGenericLanguageSubdir(false),
|
|
m_ApplicationDirectoryHasSpecificSystemLanguageSubdir(false),
|
|
m_ApplicationDirectoryHasGenericSystemLanguageSubdir(false)
|
|
{
|
|
}
|
|
|
|
_ACTCTXGENCTX::~_ACTCTXGENCTX()
|
|
{
|
|
while (m_InitializedContributorCount)
|
|
{
|
|
m_InitializedContributorCount -= 1;
|
|
CActivationContextGenerationContextContributor *Ctb = &m_Contributors[m_InitializedContributorCount];
|
|
|
|
Ctb->Fire_ParseEnded(this, NULL);
|
|
Ctb->Fire_ActCtxGenEnded(this);
|
|
}
|
|
|
|
FUSION_DELETE_ARRAY(m_Contributors);
|
|
m_Contributors = NULL;
|
|
|
|
m_AssemblyTable.ClearNoCallback();
|
|
m_ComponentPolicyTable.ClearNoCallback();
|
|
m_PendingAssemblyList.Clear(&CPendingAssembly::DeleteYourself);
|
|
m_AssemblyList.Clear(&ASSEMBLY::Release);
|
|
|
|
if (m_fClsidMapInitialized)
|
|
{
|
|
m_fClsidMapInitialized = false;
|
|
VERIFY_NTC(m_ClsidMap.Uninitialize());
|
|
}
|
|
|
|
FUSION_DELETE_SINGLETON(m_pNodeFactory);
|
|
m_pNodeFactory = NULL;
|
|
}
|
|
|
|
BOOL
|
|
SxspInitActCtxGenCtx(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
ULONG ulManifestOperation,
|
|
DWORD dwFlags,
|
|
DWORD dwManifestOperationFlags,
|
|
const CImpersonationData &ImpersonationData,
|
|
USHORT ProcessorArchitecture,
|
|
LANGID LangId,
|
|
ULONG ApplicationDirectoryPathType,
|
|
SIZE_T ApplicationDirectoryCch,
|
|
PCWSTR ApplicationDirectory
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
PACTCTXCTB Ctb = NULL;
|
|
CSxsLockCriticalSection lock(g_ActCtxCtbListCritSec);
|
|
CStringBufferAccessor acc; // used for LangID String buffer
|
|
LANGID SystemLangId = ::GetSystemDefaultUILanguage();
|
|
bool fEqual = false;
|
|
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
PARAMETER_CHECK(
|
|
(ulManifestOperation == SXSP_INIT_ACT_CTX_GEN_CTX_OPERATION_PARSE_ONLY) ||
|
|
(ulManifestOperation == SXSP_INIT_ACT_CTX_GEN_CTX_OPERATION_GENERATE_ACTIVATION_CONTEXT) ||
|
|
(ulManifestOperation == SXSP_INIT_ACT_CTX_GEN_CTX_OPERATION_INSTALL));
|
|
|
|
PARAMETER_CHECK(
|
|
(ApplicationDirectoryPathType == ACTIVATION_CONTEXT_PATH_TYPE_NONE) ||
|
|
(ApplicationDirectoryPathType == ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE));
|
|
|
|
PARAMETER_CHECK((dwFlags & ~(SXS_GENERATE_ACTCTX_SYSTEM_DEFAULT | SXS_GENERATE_ACTCTX_APP_RUNNING_IN_SAFEMODE)) == 0);
|
|
PARAMETER_CHECK((dwFlags == 0) || (dwFlags == SXS_GENERATE_ACTCTX_SYSTEM_DEFAULT) || (dwFlags == SXS_GENERATE_ACTCTX_APP_RUNNING_IN_SAFEMODE));
|
|
|
|
|
|
switch (ulManifestOperation)
|
|
{
|
|
case SXSP_INIT_ACT_CTX_GEN_CTX_OPERATION_PARSE_ONLY:
|
|
PARAMETER_CHECK(dwManifestOperationFlags == 0);
|
|
break;
|
|
|
|
case SXSP_INIT_ACT_CTX_GEN_CTX_OPERATION_GENERATE_ACTIVATION_CONTEXT:
|
|
PARAMETER_CHECK(dwManifestOperationFlags == 0);
|
|
break;
|
|
|
|
case SXSP_INIT_ACT_CTX_GEN_CTX_OPERATION_INSTALL:
|
|
PARAMETER_CHECK(
|
|
(dwManifestOperationFlags & ~(
|
|
MANIFEST_OPERATION_INSTALL_FLAG_NOT_TRANSACTIONAL |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_NO_VERIFY |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_REPLACE_EXISTING |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_ABORT |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_FROM_DIRECTORY |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_MOVE |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_INCLUDE_CODEBASE |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_FROM_RESOURCE |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_DARWIN |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_OSSETUP |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_INSTALLED_BY_MIGRATION |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_CREATE_LOGFILE |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_REFERENCE_VALID |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_REFRESH |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_FROM_CABINET |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_APPLY_PATCHES |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_FORCE_LOOK_FOR_CATALOG |
|
|
MANIFEST_OPERATION_INSTALL_FLAG_COMMIT)) == 0);
|
|
break;
|
|
}
|
|
|
|
pActCtxGenCtx->m_ProcessorArchitecture = ProcessorArchitecture;
|
|
pActCtxGenCtx->m_LangID = LangId;
|
|
pActCtxGenCtx->m_SystemLangID = SystemLangId;
|
|
|
|
pActCtxGenCtx->m_SpecificLanguage.Clear();
|
|
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_ApplicationDirectoryBuffer.Win32Assign(ApplicationDirectory, ApplicationDirectoryCch));
|
|
pActCtxGenCtx->m_ApplicationDirectoryPathType = ApplicationDirectoryPathType;
|
|
|
|
IFW32FALSE_EXIT(::SxspMapLANGIDToCultures(LangId, pActCtxGenCtx->m_GenericLanguage, pActCtxGenCtx->m_SpecificLanguage));
|
|
IFW32FALSE_EXIT(::SxspMapLANGIDToCultures(SystemLangId, pActCtxGenCtx->m_GenericSystemLanguage, pActCtxGenCtx->m_SpecificSystemLanguage));
|
|
|
|
// If these match the user's language, clear them to avoid the probing later on.
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_SpecificSystemLanguage.Win32Equals(pActCtxGenCtx->m_SpecificLanguage, fEqual, true));
|
|
if (fEqual)
|
|
pActCtxGenCtx->m_SpecificSystemLanguage.Clear();
|
|
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_GenericSystemLanguage.Win32Equals(pActCtxGenCtx->m_GenericLanguage, fEqual, true));
|
|
if (fEqual)
|
|
pActCtxGenCtx->m_GenericSystemLanguage.Clear();
|
|
|
|
pActCtxGenCtx->m_ImpersonationData = ImpersonationData;
|
|
pActCtxGenCtx->m_ManifestOperation = ulManifestOperation;
|
|
pActCtxGenCtx->m_Flags = dwFlags;
|
|
pActCtxGenCtx->m_ManifestOperationFlags = dwManifestOperationFlags;
|
|
pActCtxGenCtx->m_fAppApplyPublisherPolicy = SXS_PUBLISHER_POLICY_APPLY_DEFAULT;
|
|
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_AssemblyTable.Initialize());
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_ComponentPolicyTable.Initialize());
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_ApplicationPolicyTable.Initialize());
|
|
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_ClsidMap.Initialize());
|
|
pActCtxGenCtx->m_fClsidMapInitialized = TRUE;
|
|
pActCtxGenCtx->m_ClsidMappingContext.Map = &(pActCtxGenCtx->m_ClsidMap);
|
|
|
|
IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(pActCtxGenCtx->m_AssemblyRootDirectoryBuffer));
|
|
pActCtxGenCtx->m_AssemblyRootDirectoryPathType = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
|
|
|
|
lock.Lock();
|
|
|
|
IFALLOCFAILED_EXIT(pActCtxGenCtx->m_Contributors = FUSION_NEW_ARRAY(CActivationContextGenerationContextContributor, g_ActCtxCtbListCount));
|
|
pActCtxGenCtx->m_ContributorCount = g_ActCtxCtbListCount;
|
|
|
|
for (
|
|
(pActCtxGenCtx->m_InitializedContributorCount = 0), (Ctb=g_ActCtxCtbListHead);
|
|
(Ctb != NULL) && (pActCtxGenCtx->m_InitializedContributorCount < g_ActCtxCtbListCount);
|
|
(pActCtxGenCtx->m_InitializedContributorCount++), (Ctb = Ctb->m_Next)
|
|
)
|
|
{
|
|
ACTCTXCTB_CBACTCTXGENBEGINNING CBData;
|
|
|
|
CBData.Header.Reason = ACTCTXCTB_CBREASON_ACTCTXGENBEGINNING;
|
|
CBData.Header.ExtensionGuid = Ctb->GetExtensionGuidPtr();
|
|
CBData.Header.SectionId = Ctb->m_SectionId;
|
|
CBData.Header.ContributorContext = Ctb->m_ContributorContext;
|
|
CBData.Header.ActCtxGenContext = NULL;
|
|
CBData.Header.ManifestParseContext = NULL;
|
|
CBData.Header.ManifestOperation = ulManifestOperation;
|
|
CBData.Header.ManifestOperationFlags = dwManifestOperationFlags;
|
|
CBData.Header.Flags = dwFlags;
|
|
CBData.Header.pOriginalActCtxGenCtx = pActCtxGenCtx;
|
|
CBData.Header.InstallationContext = &(pActCtxGenCtx->m_InstallationContext);
|
|
CBData.Header.ClsidMappingContext = &(pActCtxGenCtx->m_ClsidMappingContext);
|
|
CBData.ApplicationDirectory = pActCtxGenCtx->m_ApplicationDirectoryBuffer;
|
|
CBData.ApplicationDirectoryCch = pActCtxGenCtx->m_ApplicationDirectoryBuffer.Cch();
|
|
CBData.ApplicationDirectoryPathType = pActCtxGenCtx->m_ApplicationDirectoryPathType;
|
|
CBData.Success = TRUE;
|
|
|
|
(*(Ctb->m_CallbackFunction))((PACTCTXCTB_CALLBACK_DATA) &CBData.Header);
|
|
|
|
if (!CBData.Success)
|
|
{
|
|
ASSERT(::FusionpGetLastWin32Error() != ERROR_SUCCESS);
|
|
if (::FusionpGetLastWin32Error() == ERROR_SUCCESS)
|
|
::FusionpSetLastWin32Error(ERROR_INTERNAL_ERROR);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_Contributors[pActCtxGenCtx->m_InitializedContributorCount].Initialize(Ctb, CBData.Header.ActCtxGenContext));
|
|
}
|
|
// If the list count is correct, we should be both at the end of the list
|
|
// and at the max index.
|
|
ASSERT(pActCtxGenCtx->m_InitializedContributorCount == g_ActCtxCtbListCount);
|
|
ASSERT(Ctb == NULL);
|
|
|
|
qsort(pActCtxGenCtx->m_Contributors, pActCtxGenCtx->m_ContributorCount, sizeof(CActivationContextGenerationContextContributor), &CActivationContextGenerationContextContributor::Compare);
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SxspFireActCtxGenEnding(
|
|
PACTCTXGENCTX pActCtxGenCtx
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG i;
|
|
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
for (i=0; i<pActCtxGenCtx->m_InitializedContributorCount; i++)
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_Contributors[i].Fire_ActCtxGenEnding(pActCtxGenCtx));
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
class CSxspResolvePartialReferenceLocals
|
|
{
|
|
public:
|
|
CProbedAssemblyInformation TestReference;
|
|
CSmallStringBuffer buffProcessorArchitecture;
|
|
};
|
|
|
|
BOOL
|
|
SxspResolvePartialReference(
|
|
DWORD Flags,
|
|
PCASSEMBLY ParsingAssemblyContext,
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
const CAssemblyReference &PartialReference,
|
|
CProbedAssemblyInformation &ProbedAssemblyInformation,
|
|
bool &rfFound,
|
|
CSxspResolvePartialReferenceLocals *Locals
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
CProbedAssemblyInformation &TestReference = Locals->TestReference;
|
|
CSmallStringBuffer &buffProcessorArchitecture = Locals->buffProcessorArchitecture;
|
|
bool fWildcardedLanguage = false;
|
|
bool fWildcardedProcessorArchitecture = false;
|
|
bool fAutoWow64Probing = false;
|
|
bool fHasPKToken = false;
|
|
bool fFound = false;
|
|
USHORT wCurrentProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
|
|
DWORD dwProbeAssemblyFlags = 0;
|
|
PCWSTR pszOriginalProcessorArchitecture = NULL;
|
|
SIZE_T cchOriginalProcessorArchitecture = 0;
|
|
PCWSTR pszOriginalLanguage = NULL;
|
|
SIZE_T cchOriginalLanguage = 0;
|
|
|
|
fHasPKToken = false;
|
|
rfFound = false;
|
|
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
IFINVALID_FLAGS_EXIT_WIN32(Flags, SXSP_RESOLVE_PARTIAL_REFERENCE_FLAG_OPTIONAL |
|
|
SXSP_RESOLVE_PARTIAL_REFERENCE_FLAG_SKIP_WORLDWIDE);
|
|
|
|
//
|
|
// A partial reference needs to have processor architecture, assembly name and
|
|
// assembly version filled in. We only probe based on langid.
|
|
//
|
|
|
|
// Copy the attributes over...
|
|
IFW32FALSE_EXIT(TestReference.Initialize(PartialReference, pActCtxGenCtx));
|
|
|
|
fWildcardedProcessorArchitecture = false;
|
|
fAutoWow64Probing = false;
|
|
|
|
// Find out if we're either processing a processorArchitecture="*" bind or
|
|
// if we're supposed to do wow64 probing
|
|
|
|
IFW32FALSE_EXIT(PartialReference.IsProcessorArchitectureWildcarded(fWildcardedProcessorArchitecture));
|
|
|
|
if (pActCtxGenCtx->m_ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA32_ON_WIN64)
|
|
{
|
|
IFW32FALSE_EXIT(PartialReference.IsProcessorArchitectureX86(fAutoWow64Probing));
|
|
}
|
|
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
{
|
|
wCurrentProcessorArchitecture = pActCtxGenCtx->m_ProcessorArchitecture;
|
|
IFW32FALSE_EXIT(::FusionpFormatProcessorArchitecture(wCurrentProcessorArchitecture, buffProcessorArchitecture));
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
|
|
// We do not probe for private wow64 assemblies.
|
|
if (wCurrentProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA32_ON_WIN64)
|
|
dwProbeAssemblyFlags |= CProbedAssemblyInformation::ProbeAssembly_SkipPrivateAssemblies;
|
|
}
|
|
|
|
IFW32FALSE_EXIT(PartialReference.GetProcessorArchitecture(pszOriginalProcessorArchitecture, cchOriginalProcessorArchitecture));
|
|
IFW32FALSE_EXIT(PartialReference.GetLanguage(pszOriginalLanguage, cchOriginalLanguage));
|
|
|
|
TryItAllAgain:
|
|
|
|
// Let's try the few languages we can.
|
|
|
|
IFW32FALSE_EXIT(PartialReference.IsLanguageWildcarded(fWildcardedLanguage));
|
|
if (!fWildcardedLanguage)
|
|
{
|
|
// If there's no language="*" in the dependency, let's just look for the exact match and
|
|
// call it a day.
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
|
|
IFW32FALSE_EXIT(TestReference.ProbeAssembly(dwProbeAssemblyFlags, pActCtxGenCtx, CProbedAssemblyInformation::eExplicitBind, fFound));
|
|
|
|
if ((!fFound) && (fWildcardedProcessorArchitecture || fAutoWow64Probing))
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(pszOriginalProcessorArchitecture, cchOriginalProcessorArchitecture));
|
|
}
|
|
else
|
|
{
|
|
// Let's try the user's language...
|
|
if (pActCtxGenCtx->m_SpecificLanguage[0] != L'\0')
|
|
{
|
|
// Since this is the first probe, we don't have to reset to original...
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pActCtxGenCtx->m_SpecificLanguage));
|
|
IFW32FALSE_EXIT(TestReference.ProbeAssembly(dwProbeAssemblyFlags, pActCtxGenCtx, CProbedAssemblyInformation::eSpecificLanguage, fFound));
|
|
if (!fFound)
|
|
{
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(
|
|
TestReference.SetProcessorArchitecture(
|
|
pszOriginalProcessorArchitecture,
|
|
cchOriginalProcessorArchitecture));
|
|
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pszOriginalLanguage, cchOriginalLanguage));
|
|
}
|
|
}
|
|
|
|
if (!fFound && (pActCtxGenCtx->m_GenericLanguage[0] != L'\0'))
|
|
{
|
|
// Try the user's slightly more generic version of the language...
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pActCtxGenCtx->m_GenericLanguage));
|
|
|
|
IFW32FALSE_EXIT(TestReference.ProbeAssembly(dwProbeAssemblyFlags, pActCtxGenCtx, CProbedAssemblyInformation::eGenericLanguage, fFound));
|
|
|
|
if (!fFound)
|
|
{
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(
|
|
TestReference.SetProcessorArchitecture(
|
|
pszOriginalProcessorArchitecture,
|
|
cchOriginalProcessorArchitecture));
|
|
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pszOriginalLanguage, cchOriginalLanguage));
|
|
}
|
|
}
|
|
|
|
// Let's try the system's installed language...
|
|
if (!fFound && (pActCtxGenCtx->m_SpecificSystemLanguage[0] != L'\0'))
|
|
{
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pActCtxGenCtx->m_SpecificSystemLanguage));
|
|
IFW32FALSE_EXIT(TestReference.ProbeAssembly(dwProbeAssemblyFlags, pActCtxGenCtx, CProbedAssemblyInformation::eSpecificSystemLanguage, fFound));
|
|
if (!fFound)
|
|
{
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(
|
|
TestReference.SetProcessorArchitecture(
|
|
pszOriginalProcessorArchitecture,
|
|
cchOriginalProcessorArchitecture));
|
|
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pszOriginalLanguage, cchOriginalLanguage));
|
|
}
|
|
}
|
|
|
|
if (!fFound && (pActCtxGenCtx->m_GenericSystemLanguage[0] != L'\0'))
|
|
{
|
|
// Try the user's slightly more generic version of the language...
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pActCtxGenCtx->m_GenericSystemLanguage));
|
|
IFW32FALSE_EXIT(TestReference.ProbeAssembly(dwProbeAssemblyFlags, pActCtxGenCtx, CProbedAssemblyInformation::eGenericSystemLanguage, fFound));
|
|
if (!fFound)
|
|
{
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(
|
|
TestReference.SetProcessorArchitecture(
|
|
pszOriginalProcessorArchitecture,
|
|
cchOriginalProcessorArchitecture));
|
|
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pszOriginalLanguage, cchOriginalLanguage));
|
|
}
|
|
}
|
|
|
|
// If we haven't found a language specific one and the caller did not
|
|
// request us to skip the language-dependent ones, try for a language neutral
|
|
if (!fFound &&
|
|
((Flags & SXSP_RESOLVE_PARTIAL_REFERENCE_FLAG_SKIP_WORLDWIDE) == 0))
|
|
{
|
|
// Try with no language!
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
IFW32FALSE_EXIT(TestReference.ClearLanguage());
|
|
IFW32FALSE_EXIT(TestReference.ProbeAssembly(dwProbeAssemblyFlags, pActCtxGenCtx, CProbedAssemblyInformation::eLanguageNeutral, fFound));
|
|
if (!fFound)
|
|
{
|
|
if (fWildcardedProcessorArchitecture || fAutoWow64Probing)
|
|
IFW32FALSE_EXIT(
|
|
TestReference.SetProcessorArchitecture(
|
|
pszOriginalProcessorArchitecture,
|
|
cchOriginalProcessorArchitecture));
|
|
|
|
IFW32FALSE_EXIT(TestReference.SetLanguage(pszOriginalLanguage, cchOriginalLanguage));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fFound)
|
|
{
|
|
// If we're automatically searching for wow64 assemblies and the processor architecture we just tried
|
|
// was ia32-on-win64, try again with plain PROCESSOR_ARCHITECTURE_INTEL.
|
|
if (fAutoWow64Probing && (wCurrentProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA32_ON_WIN64))
|
|
{
|
|
wCurrentProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
|
|
dwProbeAssemblyFlags &= ~(CProbedAssemblyInformation::ProbeAssembly_SkipPrivateAssemblies);
|
|
|
|
IFW32FALSE_EXIT(::FusionpFormatProcessorArchitecture(wCurrentProcessorArchitecture, buffProcessorArchitecture));
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
pszOriginalProcessorArchitecture = buffProcessorArchitecture;
|
|
cchOriginalProcessorArchitecture = buffProcessorArchitecture.Cch();
|
|
goto TryItAllAgain;
|
|
}
|
|
|
|
// If we're handling a processorArchitecture="*" bind and the current processor architecture hasn't fallen
|
|
// back to PROCESSOR_ARCHITECTURE_UNKNOWN ( == data-only assemblies), fall back now.
|
|
if (fWildcardedProcessorArchitecture && (wCurrentProcessorArchitecture != PROCESSOR_ARCHITECTURE_UNKNOWN))
|
|
{
|
|
wCurrentProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
|
|
// data-only private assemblies cannot be found with processorArchitecture="*"
|
|
dwProbeAssemblyFlags |= CProbedAssemblyInformation::ProbeAssembly_SkipPrivateAssemblies;
|
|
|
|
IFW32FALSE_EXIT(::FusionpFormatProcessorArchitecture(wCurrentProcessorArchitecture, buffProcessorArchitecture));
|
|
IFW32FALSE_EXIT(TestReference.SetProcessorArchitecture(buffProcessorArchitecture, buffProcessorArchitecture.Cch()));
|
|
pszOriginalProcessorArchitecture = buffProcessorArchitecture;
|
|
cchOriginalProcessorArchitecture = buffProcessorArchitecture.Cch();
|
|
goto TryItAllAgain;
|
|
}
|
|
|
|
// If it wasn't optional, declare an error.
|
|
if ((Flags & SXSP_RESOLVE_PARTIAL_REFERENCE_FLAG_OPTIONAL) == 0)
|
|
{
|
|
// NTRAID#NTBUG9 - 571854 - 2002/03/26 - xiaoyuw
|
|
// the default value would never get used since GetAssemblyName always reset the input parameter to be NULL;
|
|
|
|
PCWSTR AssemblyName = L"<error retrieving assembly name>";
|
|
SIZE_T AssemblyNameCch = NUMBER_OF(L"<error retrieving assembly name>") - 1;
|
|
|
|
TestReference.GetAssemblyName(&AssemblyName, &AssemblyNameCch);
|
|
|
|
::FusionpLogError(
|
|
MSG_SXS_MANIFEST_PARSE_DEPENDENCY,
|
|
CUnicodeString(AssemblyName, AssemblyNameCch),
|
|
CEventLogLastError(ERROR_SXS_ASSEMBLY_NOT_FOUND));
|
|
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(AssemblyProbingFailed, ERROR_SXS_ASSEMBLY_NOT_FOUND);
|
|
}
|
|
}
|
|
else
|
|
IFW32FALSE_EXIT(ProbedAssemblyInformation.TakeValue(TestReference));
|
|
|
|
rfFound = fFound;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
if (!fSuccess)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
PCWSTR pszAssemblyName = NULL;
|
|
SIZE_T AssemblyNameCch = 0;
|
|
|
|
PartialReference.GetAssemblyName(&pszAssemblyName, &AssemblyNameCch);
|
|
|
|
::FusionpLogError(
|
|
MSG_SXS_FUNCTION_CALL_FAIL,
|
|
CEventLogString(L"Resolve Partial Assembly"),
|
|
(pszAssemblyName != NULL) ? CEventLogString(static_cast<PCWSTR>(pszAssemblyName)) : CEventLogString(L"Assembly Name Unknown"),
|
|
CEventLogLastError(ple.LastError()));
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SxspResolvePartialReference(
|
|
DWORD Flags,
|
|
PCASSEMBLY ParsingAssemblyContext,
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
const CAssemblyReference &PartialReference,
|
|
CProbedAssemblyInformation &ProbedAssemblyInformation,
|
|
bool &rfFound
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CSmartPtr<CSxspResolvePartialReferenceLocals> Locals;
|
|
|
|
IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
|
|
|
|
IFW32FALSE_EXIT(
|
|
SxspResolvePartialReference(
|
|
Flags,
|
|
ParsingAssemblyContext,
|
|
pActCtxGenCtx,
|
|
PartialReference,
|
|
ProbedAssemblyInformation,
|
|
rfFound,
|
|
Locals
|
|
));
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL
|
|
SxspAddManifestToActCtxGenCtx(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
CProbedAssemblyInformation &ProbedInformation,
|
|
PASSEMBLY *AssemblyOut
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
PASSEMBLY Asm = NULL;
|
|
PCWSTR ProbedAssemblyName = 0;
|
|
SIZE_T ProbedAssemblyNameCch = 0;
|
|
|
|
if (AssemblyOut != NULL)
|
|
*AssemblyOut = NULL;
|
|
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
IFW32FALSE_EXIT(ProbedInformation.GetAssemblyName(&ProbedAssemblyName, &ProbedAssemblyNameCch));
|
|
|
|
// NTRAID#NTBUG9 - 571854 - 2002/03/26 - xiaoyuw:
|
|
// INTERNAL_ERROR_CHECK or ASSERT should be added here
|
|
|
|
// INTERNAL_ERROR_CHECK(ProbedAssemblyName != NULL && ProbedAssemblyNameCch != 0);
|
|
|
|
// First, let's see if we've already found this assembly.
|
|
IFW32FALSE_EXIT(::SxspFindAssemblyByName(pActCtxGenCtx, ProbedAssemblyName, ProbedAssemblyNameCch, &Asm));
|
|
// Same name... if the metadata is different, we're in trouble.
|
|
if (Asm != NULL)
|
|
{
|
|
BOOL fEqualIdentity;
|
|
|
|
// Both identities should be definitions, so no need to set the ref-matches-def flag...
|
|
IFW32FALSE_EXIT(
|
|
::SxsAreAssemblyIdentitiesEqual(
|
|
SXS_ARE_ASSEMBLY_IDENTITIES_EQUAL_FLAG_ALLOW_REF_TO_MATCH_DEF,
|
|
Asm->GetAssemblyIdentity(),
|
|
ProbedInformation.GetAssemblyIdentity(),
|
|
&fEqualIdentity));
|
|
|
|
if (!fEqualIdentity)
|
|
{
|
|
PCWSTR MP1 = L"<unavailable>";
|
|
PCWSTR MP2 = MP1;
|
|
|
|
ProbedInformation.GetManifestPath(&MP1, NULL);
|
|
Asm->m_ProbedAssemblyInformation.GetManifestPath(&MP2, NULL);
|
|
|
|
Asm = NULL;
|
|
::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: Failing to add new manifest %S to activation context because it conflicts with existing %S\n", MP1, MP2);
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(VersionConflict, ERROR_SXS_VERSION_CONFLICT);
|
|
}
|
|
}
|
|
|
|
if (Asm == NULL)
|
|
{
|
|
IFALLOCFAILED_EXIT(Asm = FUSION_NEW_SINGLETON(ASSEMBLY));
|
|
IFW32FALSE_EXIT(::SxspInitAssembly(Asm, ProbedInformation));
|
|
IFW32FALSE_EXIT(::SxspAddAssemblyToActivationContextGenerationContext(pActCtxGenCtx, Asm));
|
|
}
|
|
|
|
if (AssemblyOut != NULL)
|
|
{
|
|
*AssemblyOut = Asm;
|
|
Asm = NULL;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
if (Asm != NULL)
|
|
Asm->Release();
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SxspAddAssemblyToActivationContextGenerationContext(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PASSEMBLY Asm
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
PARAMETER_CHECK(Asm != NULL);
|
|
|
|
// If you hit either of these asserts, either the assembly structure has been trashed or
|
|
// it's already been added to the generation context.
|
|
ASSERT(Asm->m_AssemblyRosterIndex == 0);
|
|
Asm->m_AssemblyRosterIndex = pActCtxGenCtx->m_NextAssemblyRosterIndex++;
|
|
pActCtxGenCtx->m_AssemblyList.AddToTail(Asm);
|
|
Asm->AddRef();
|
|
if (pActCtxGenCtx->m_ManifestOperation != MANIFEST_OPERATION_INSTALL)
|
|
{
|
|
PCWSTR AssemblyName = NULL;
|
|
IFW32FALSE_EXIT(Asm->GetAssemblyName(&AssemblyName, NULL));
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_AssemblyTable.Insert(AssemblyName, Asm, ERROR_SXS_DUPLICATE_ASSEMBLY_NAME));
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SxspFindAssemblyByName(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PCWSTR AssemblyName,
|
|
SIZE_T AssemblyNameCch,
|
|
PASSEMBLY *AssemblyOut
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
CSmallStringBuffer AssemblyNameBuffer;
|
|
PASSEMBLY Result = NULL;
|
|
|
|
if (AssemblyOut != NULL)
|
|
*AssemblyOut = NULL;
|
|
|
|
PARAMETER_CHECK(AssemblyOut != NULL);
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
// Unfortunately, we really need the string to be null terminated...
|
|
IFW32FALSE_EXIT(AssemblyNameBuffer.Win32Assign(AssemblyName, AssemblyNameCch));
|
|
AssemblyName = AssemblyNameBuffer;
|
|
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_AssemblyTable.Find(AssemblyName, Result));
|
|
|
|
if (Result != NULL)
|
|
Result->AddRef();
|
|
|
|
*AssemblyOut = Result;
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SxspAddRootManifestToActCtxGenCtx(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PCSXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS Parameters
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
CProbedAssemblyInformation AssemblyInfo;
|
|
|
|
PARAMETER_CHECK(Parameters != NULL);
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
#define IS_NT_DOS_PATH(_x) (IS_PATH_SEPARATOR_U((_x)[0]) && ((_x)[1] == L'?') && ((_x)[2] == L'?') && IS_PATH_SEPARATOR_U((_x)[3]))
|
|
|
|
PARAMETER_CHECK((Parameters->AssemblyDirectory == NULL) || (IS_NT_DOS_PATH(Parameters->AssemblyDirectory) == FALSE));
|
|
PARAMETER_CHECK((Parameters->AssemblyDirectory == NULL) || (IS_NT_DOS_PATH(Parameters->AssemblyDirectory) == FALSE));
|
|
PARAMETER_CHECK((Parameters->Manifest.Path == NULL) || (IS_NT_DOS_PATH(Parameters->Manifest.Path) == FALSE));
|
|
PARAMETER_CHECK((Parameters->Policy.Path == NULL) || (IS_NT_DOS_PATH(Parameters->Policy.Path) == FALSE));
|
|
|
|
IFW32FALSE_EXIT(AssemblyInfo.Initialize(pActCtxGenCtx));
|
|
IFW32FALSE_EXIT(AssemblyInfo.SetManifestPath(
|
|
ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE,
|
|
Parameters->Manifest.Path,
|
|
(Parameters->Manifest.Path != NULL) ? ::wcslen(Parameters->Manifest.Path) : 0));
|
|
ASSERT(Parameters->Manifest.Stream != NULL);
|
|
IFW32FALSE_EXIT(AssemblyInfo.SetManifestStream(Parameters->Manifest.Stream));
|
|
IFW32FALSE_EXIT(AssemblyInfo.SetManifestFlags(ASSEMBLY_MANIFEST_FILETYPE_STREAM));
|
|
|
|
IFW32FALSE_EXIT(AssemblyInfo.SetPolicyPath(
|
|
ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE,
|
|
Parameters->Policy.Path,
|
|
(Parameters->Policy.Path != NULL) ? ::wcslen(Parameters->Policy.Path) : 0));
|
|
IFW32FALSE_EXIT(AssemblyInfo.SetPolicyStream(Parameters->Policy.Stream));
|
|
IFW32FALSE_EXIT(AssemblyInfo.SetPolicyFlags(ASSEMBLY_POLICY_FILETYPE_STREAM));
|
|
|
|
IFW32FALSE_EXIT(::SxspAddManifestToActCtxGenCtx(pActCtxGenCtx, AssemblyInfo, NULL));
|
|
|
|
FN_EPILOG
|
|
#undef IS_NT_DOS_PATH
|
|
}
|
|
|
|
BOOL
|
|
SxspInitAssembly(
|
|
PASSEMBLY Asm,
|
|
CProbedAssemblyInformation &AssemblyInfo
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
PARAMETER_CHECK(Asm != NULL);
|
|
|
|
IFW32FALSE_EXIT(Asm->m_ProbedAssemblyInformation.InitializeTakeValue(AssemblyInfo));
|
|
Asm->m_Incorporated = FALSE;
|
|
Asm->m_ManifestVersionMajor = 0;
|
|
Asm->m_ManifestVersionMinor = 0;
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
class CSxspIncorporateAssemblyLocals
|
|
{
|
|
public:
|
|
#if FUSION_XML_TREE
|
|
SXS_XML_STRING LocalStringArray[128];
|
|
PSXS_XML_STRING ActualStringArray;
|
|
#endif
|
|
STATSTG statstg;
|
|
ACTCTXCTB_ASSEMBLY_CONTEXT AssemblyContext;
|
|
CStringBuffer TextuallyEncodedIdentityBuffer;
|
|
CFileStream ProbeFileTypeStream;
|
|
CFileStream FileStream;
|
|
};
|
|
|
|
BOOL
|
|
SxspIncorporateAssembly(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PASSEMBLY Asm,
|
|
CSxspIncorporateAssemblyLocals *Locals
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
HRESULT hr = 0;
|
|
ULONG i = 0;
|
|
ACTCTXCTB_ASSEMBLY_CONTEXT &AssemblyContext = Locals->AssemblyContext;
|
|
const bool fInstalling = (pActCtxGenCtx->m_ManifestOperation == MANIFEST_OPERATION_INSTALL);
|
|
ULONG ManifestType = (Asm->m_ProbedAssemblyInformation.GetManifestFlags() & ASSEMBLY_MANIFEST_FILETYPE_MASK);
|
|
CImpersonate impersonate(pActCtxGenCtx->m_ImpersonationData);
|
|
SXS_POLICY_SOURCE s;
|
|
#if FUSION_XML_TREE
|
|
PSXS_XML_STRING ActualStringArray = Locals->LocalStringArray;
|
|
#endif
|
|
STATSTG &statstg = Locals->statstg;
|
|
|
|
// declaration order here is partially deliberate, to control cleanup order.
|
|
// normally, declaration order is determined by not declaring until you have
|
|
// the data to initialize with the ctor, but the use of goto messes that up
|
|
CFileStream &FileStream = Locals->FileStream;
|
|
CSmartPtr<CResourceStream> ResourceStream;
|
|
CSmartPtr<CTeeStreamWithHash> TeeStreamForManifestInstall;
|
|
|
|
#if FUSION_PRECOMPILED_MANIFEST
|
|
CSmartPtr<CPrecompiledManifestWriterStream> pcmWriterStream;
|
|
#endif
|
|
CNodeFactory *pNodeFactory = NULL;
|
|
CSmartRef<IXMLParser> pIXMLParser;
|
|
PASSEMBLY_IDENTITY AssemblyIdentity = NULL;
|
|
|
|
CStringBuffer &TextuallyEncodedIdentityBuffer = Locals->TextuallyEncodedIdentityBuffer;
|
|
PCWSTR ManifestPath = NULL;
|
|
|
|
PARAMETER_CHECK(Asm != NULL);
|
|
PARAMETER_CHECK(!Asm->m_Incorporated);
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
// set flags
|
|
AssemblyContext.Flags = 0;
|
|
s = Asm->m_ProbedAssemblyInformation.GetPolicySource();
|
|
|
|
if ( s == SXS_POLICY_SYSTEM_POLICY)
|
|
AssemblyContext.Flags |= ACTCTXCTB_ASSEMBLY_CONTEXT_ASSEMBLY_POLICY_APPLIED;
|
|
else if (s == SXS_POLICY_ROOT_POLICY)
|
|
AssemblyContext.Flags |= ACTCTXCTB_ASSEMBLY_CONTEXT_ROOT_POLICY_APPLIED;
|
|
|
|
if (Asm->IsRoot())
|
|
AssemblyContext.Flags |= ACTCTXCTB_ASSEMBLY_CONTEXT_IS_ROOT_ASSEMBLY;
|
|
|
|
if (Asm->m_ProbedAssemblyInformation.IsPrivateAssembly())
|
|
AssemblyContext.Flags |= ACTCTXCTB_ASSEMBLY_CONTEXT_IS_PRIVATE_ASSEMBLY;
|
|
|
|
if (Asm->m_ProbedAssemblyInformation.GetAssemblyIdentity() != NULL)
|
|
{
|
|
// Convert the identity into a somewhat human-readable form that we can log etc.
|
|
IFW32FALSE_EXIT(
|
|
::SxspGenerateTextualIdentity(
|
|
0,
|
|
Asm->m_ProbedAssemblyInformation.GetAssemblyIdentity(),
|
|
TextuallyEncodedIdentityBuffer));
|
|
|
|
AssemblyContext.TextuallyEncodedIdentity = TextuallyEncodedIdentityBuffer;
|
|
AssemblyContext.TextuallyEncodedIdentityCch = TextuallyEncodedIdentityBuffer.Cch();
|
|
}
|
|
else
|
|
{
|
|
AssemblyContext.TextuallyEncodedIdentity = L"<identity unavailable>";
|
|
AssemblyContext.TextuallyEncodedIdentityCch = 22;
|
|
}
|
|
|
|
// copy assembly-identity info
|
|
IFW32FALSE_EXIT(::SxsDuplicateAssemblyIdentity(SXS_DUPLICATE_ASSEMBLY_IDENTITY_FLAG_ALLOW_NULL, Asm->m_ProbedAssemblyInformation.GetAssemblyIdentity(), &AssemblyIdentity));
|
|
AssemblyContext.AssemblyIdentity = AssemblyIdentity; // assign to pointer-to-const in the struct; can't pass struct member pointer directly
|
|
|
|
IFW32FALSE_EXIT(Asm->m_ProbedAssemblyInformation.GetManifestPath(&AssemblyContext.ManifestPath, &AssemblyContext.ManifestPathCch));
|
|
AssemblyContext.ManifestPathType = Asm->GetManifestPathType();
|
|
IFW32FALSE_EXIT(Asm->m_ProbedAssemblyInformation.GetPolicyPath(AssemblyContext.PolicyPath, AssemblyContext.PolicyPathCch));
|
|
AssemblyContext.PolicyPathType = Asm->GetPolicyPathType();
|
|
AssemblyContext.AssemblyRosterIndex = Asm->m_AssemblyRosterIndex;
|
|
|
|
if (fInstalling)
|
|
{
|
|
IFW32FALSE_EXIT(TeeStreamForManifestInstall.Win32Allocate(__FILE__, __LINE__));
|
|
AssemblyContext.TeeStreamForManifestInstall = TeeStreamForManifestInstall;
|
|
AssemblyContext.InstallationInfo = pActCtxGenCtx->m_InstallationContext.InstallSource;
|
|
AssemblyContext.SecurityMetaData = pActCtxGenCtx->m_InstallationContext.SecurityMetaData;
|
|
AssemblyContext.InstallReferenceData = pActCtxGenCtx->m_InstallationContext.InstallReferenceData;
|
|
#if FUSION_PRECOMPILED_MANIFEST
|
|
IFW32FALSE_EXIT(pcmWriterStream.Win32Allocate(__FILE__, __LINE__);
|
|
AssemblyContext.pcmWriterStream = pcmWriterStream ;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
AssemblyContext.SecurityMetaData = NULL;
|
|
AssemblyContext.TeeStreamForManifestInstall = NULL;
|
|
AssemblyContext.InstallationInfo = NULL;
|
|
#if FUSION_PRECOMPILED_MANIFEST
|
|
AssemblyContext.pcmWriterStream = NULL;
|
|
#endif
|
|
}
|
|
|
|
if (pActCtxGenCtx->m_pNodeFactory == NULL)
|
|
{
|
|
IFALLOCFAILED_EXIT(pActCtxGenCtx->m_pNodeFactory = new CNodeFactory);
|
|
pActCtxGenCtx->m_pNodeFactory->AddRef(); // faked function
|
|
}
|
|
else
|
|
pActCtxGenCtx->m_pNodeFactory->ResetParseState();
|
|
|
|
IFW32FALSE_EXIT(pActCtxGenCtx->m_pNodeFactory->Initialize(pActCtxGenCtx, Asm, &AssemblyContext));
|
|
pNodeFactory = pActCtxGenCtx->m_pNodeFactory;
|
|
ASSERT(pNodeFactory != NULL);
|
|
|
|
// Everyone's ready; let's get the XML parser:
|
|
IFW32FALSE_EXIT(::SxspGetXMLParser(IID_IXMLParser, (LPVOID *) &pIXMLParser));
|
|
IFCOMFAILED_EXIT(pIXMLParser->SetFactory(pNodeFactory));
|
|
|
|
//
|
|
// open the file or map the resource into memory
|
|
//
|
|
IStream* Stream; // deliberatly not "smart", we don't refcount it
|
|
Stream = NULL;
|
|
{ // scope for impersonation for file open
|
|
|
|
IFW32FALSE_EXIT(impersonate.Impersonate());
|
|
|
|
if (ManifestType == ASSEMBLY_MANIFEST_FILETYPE_AUTO_DETECT)
|
|
{
|
|
//
|
|
// decide between xml in its own text file or a resource
|
|
// in a "portable executable" by checking for the portable executable
|
|
// signature, "MZ".
|
|
//
|
|
BYTE buffer[2] = {0,0};
|
|
ULONG cbRead = 0;
|
|
CFileStream &ProbeFileTypeStream = Locals->ProbeFileTypeStream;
|
|
|
|
IFW32FALSE_EXIT(Asm->m_ProbedAssemblyInformation.GetManifestPath(&ManifestPath, NULL));
|
|
IFW32FALSE_EXIT(
|
|
ProbeFileTypeStream.OpenForRead(
|
|
ManifestPath,
|
|
CImpersonationData(),
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN));
|
|
|
|
IFCOMFAILED_EXIT(ProbeFileTypeStream.Read(buffer, 2, &cbRead));
|
|
|
|
if (cbRead != 2)
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(ManifestLessThanTwoBytesLong, ERROR_SXS_MANIFEST_FORMAT_ERROR);
|
|
|
|
IFW32FALSE_EXIT(ProbeFileTypeStream.Close());
|
|
|
|
// MS-DOS stub, Mark Zbikowski
|
|
if (buffer[0] == 'M' && buffer[1] == 'Z')
|
|
{
|
|
// should we do further checking, like that PE\0\0 occurs
|
|
// where the MS-DOS header says it is?
|
|
ManifestType = ASSEMBLY_MANIFEST_FILETYPE_RESOURCE;
|
|
}
|
|
else
|
|
{
|
|
ManifestType = ASSEMBLY_MANIFEST_FILETYPE_FILE;
|
|
}
|
|
}
|
|
switch (ManifestType)
|
|
{
|
|
case ASSEMBLY_MANIFEST_FILETYPE_RESOURCE:
|
|
{
|
|
if (ManifestPath == NULL)
|
|
IFW32FALSE_EXIT(Asm->m_ProbedAssemblyInformation.GetManifestPath(&ManifestPath, NULL));
|
|
IFW32FALSE_EXIT(ResourceStream.Win32Allocate(__FILE__, __LINE__));
|
|
IFW32FALSE_EXIT(ResourceStream->Initialize(ManifestPath, MAKEINTRESOURCEW(RT_MANIFEST)));
|
|
Stream = ResourceStream;
|
|
break;
|
|
}
|
|
case ASSEMBLY_MANIFEST_FILETYPE_FILE:
|
|
{
|
|
if (ManifestPath == NULL)
|
|
IFW32FALSE_EXIT(Asm->m_ProbedAssemblyInformation.GetManifestPath(&ManifestPath, NULL));
|
|
IFW32FALSE_EXIT(
|
|
FileStream.OpenForRead(
|
|
ManifestPath,
|
|
CImpersonationData(),
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN));
|
|
Stream = &FileStream;
|
|
break;
|
|
}
|
|
case ASSEMBLY_MANIFEST_FILETYPE_STREAM:
|
|
Stream = Asm->m_ProbedAssemblyInformation.GetManifestStream();
|
|
break;
|
|
default:
|
|
ASSERT2(FALSE, "unknown manifest file type");
|
|
break;
|
|
}
|
|
|
|
IFW32FALSE_EXIT(impersonate.Unimpersonate());
|
|
}
|
|
|
|
//
|
|
// Optionally "tee" the manifest so it gets copied into
|
|
// the store while we read it, buffering until we know where in
|
|
// the store it goes. The manifest itself is not referenced
|
|
// in the manifest.
|
|
//
|
|
if (fInstalling)
|
|
{
|
|
IFW32FALSE_EXIT(TeeStreamForManifestInstall->InitCryptHash(CALG_SHA1));
|
|
TeeStreamForManifestInstall->SetSource(Stream);
|
|
Stream = TeeStreamForManifestInstall;
|
|
}
|
|
|
|
//
|
|
// We get E_NOTIMPL on the OutOfProcessMemoryStreams in the AppCompat case.
|
|
//
|
|
IFCOMFAILED_EXIT(((hr = Stream->Stat(&statstg, STATFLAG_NONAME)) != E_NOTIMPL) ? hr : NOERROR);
|
|
if (hr == E_NOTIMPL)
|
|
{
|
|
statstg.mtime.dwLowDateTime = 0;
|
|
statstg.mtime.dwHighDateTime = 0;
|
|
}
|
|
|
|
IFW32FALSE_EXIT(
|
|
pNodeFactory->SetParseType(
|
|
XML_FILE_TYPE_MANIFEST,
|
|
Asm->m_ProbedAssemblyInformation.GetManifestPathType(),
|
|
Asm->m_ProbedAssemblyInformation.GetManifestPath(),
|
|
statstg.mtime));
|
|
|
|
INTERNAL_ERROR_CHECK(Stream != NULL);
|
|
|
|
IFCOMFAILED_EXIT(pIXMLParser->SetInput(Stream));
|
|
IFCOMFAILED_EXIT(pIXMLParser->Run(-1));
|
|
IFW32FALSE_EXIT(FileStream.Close());
|
|
|
|
#if FUSION_PRECOMPILED_MANIFEST
|
|
IFW32FALSE_EXIT((AssemblyContext.pcmWriterStream == NULL) || (pcmWriterStream.Close()));
|
|
#endif
|
|
|
|
// Tell the contributors we're done parsing this file
|
|
for (i=0; i<pActCtxGenCtx->m_ContributorCount; i++)
|
|
IFW32FALSE_EXIT(
|
|
pActCtxGenCtx->m_Contributors[i].Fire_ParseEnding(
|
|
pActCtxGenCtx,
|
|
&AssemblyContext));
|
|
|
|
#if FUSION_XML_TREE
|
|
// Now let's fill in the document's string table.
|
|
StringTableEntryCount = pNodeFactory->m_ParseTreeStringPool.GetEntryCount() + 1;
|
|
|
|
if (StringTableEntryCount > NUMBER_OF(Locals->LocalStringArray))
|
|
IFALLOCFAILED_EXIT(ActualStringArray = FUSION_NEW_ARRAY(SXS_XML_STRING, StringTableEntryCount));
|
|
|
|
IFW32FALSE_EXIT(pNodeFactory->m_ParseTreeStringPool.FillInStringArray(StringTableEntryCount, ActualStringArray, EntriesFilledIn));
|
|
// The size should have been an exact match.
|
|
ASSERT(EntriesFilledIn == StringTableEntryCount);
|
|
|
|
pNodeFactory->m_XmlDocument.StringCount = EntriesFilledIn;
|
|
pNodeFactory->m_XmlDocument.Strings = ActualStringArray;
|
|
|
|
::SxspDumpXmlTree(0, &(pNodeFactory->m_XmlDocument));
|
|
|
|
pNodeFactory->m_XmlDocument.StringCount = 0;
|
|
pNodeFactory->m_XmlDocument.Strings = NULL;
|
|
|
|
if (ActualStringArray != Locals->LocalStringArray)
|
|
{
|
|
FUSION_DELETE_ARRAY(ActualStringArray);
|
|
ActualStringArray = NULL;
|
|
}
|
|
#endif // FUSION_XML_TREE
|
|
|
|
Asm->m_Incorporated = TRUE;
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
// And tell them we're done.
|
|
for (i=0; i<pActCtxGenCtx->m_ContributorCount; i++)
|
|
pActCtxGenCtx->m_Contributors[i].Fire_ParseEnded(pActCtxGenCtx, &AssemblyContext);
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SxspIncorporateAssembly(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PASSEMBLY Asm
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CSmartPtr<CSxspIncorporateAssemblyLocals> Locals;
|
|
|
|
PARAMETER_CHECK(Asm != NULL);
|
|
PARAMETER_CHECK(!Asm->m_Incorporated);
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
|
|
|
|
IFW32FALSE_EXIT(::SxspIncorporateAssembly(pActCtxGenCtx, Asm, Locals));
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL
|
|
SxspEnqueueAssemblyReference(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PASSEMBLY SourceAssembly,
|
|
PCASSEMBLY_IDENTITY Identity,
|
|
bool Optional,
|
|
bool MetadataSatellite
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CSmartPtr<CPendingAssembly> PendingAssembly;
|
|
|
|
PARAMETER_CHECK(Identity != NULL);
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
IFW32FALSE_EXIT(PendingAssembly.Win32Allocate(__FILE__, __LINE__));
|
|
IFW32FALSE_EXIT(PendingAssembly->Initialize(SourceAssembly, Identity, Optional, MetadataSatellite));
|
|
|
|
pActCtxGenCtx->m_PendingAssemblyList.AddToTail(PendingAssembly.Detach());
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
class CSxspProcessPendingAssembliesLocals
|
|
{
|
|
public:
|
|
|
|
CSmallStringBuffer buffName;
|
|
CProbedAssemblyInformation MuiAssemblyFound;
|
|
CProbedAssemblyInformation AssemblyFound;
|
|
};
|
|
|
|
BOOL
|
|
SxspProcessPendingAssemblies(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
CSxspProcessPendingAssembliesLocals *Locals
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CPendingAssembly *EntryToDelete = NULL;
|
|
CSmartPtrWithNamedDestructor<ASSEMBLY_IDENTITY, SxsDestroyAssemblyIdentity> MuiAssemblyIdentity;
|
|
|
|
CDequeIterator<CPendingAssembly, offsetof(CPendingAssembly, m_Linkage)> Iter(&pActCtxGenCtx->m_PendingAssemblyList);
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
for (Iter.Reset(); Iter.More(); Iter.Next())
|
|
{
|
|
bool fFound = false;
|
|
CAssemblyReference TargetAssemblyRef;
|
|
CProbedAssemblyInformation &AssemblyFound = Locals->AssemblyFound;
|
|
AssemblyFound.Reinitialize();
|
|
CSmartRef<ASSEMBLY> Assembly;
|
|
|
|
if (EntryToDelete != NULL)
|
|
{
|
|
pActCtxGenCtx->m_PendingAssemblyList.Remove(EntryToDelete);
|
|
FUSION_DELETE_SINGLETON(EntryToDelete);
|
|
}
|
|
|
|
EntryToDelete = NULL;
|
|
|
|
IFW32FALSE_EXIT(AssemblyFound.Initialize(pActCtxGenCtx));
|
|
IFW32FALSE_EXIT(TargetAssemblyRef.Initialize(Iter->GetIdentity()));
|
|
|
|
IFW32FALSE_EXIT(
|
|
::SxspResolvePartialReference(
|
|
Iter->IsOptional() ? SXSP_RESOLVE_PARTIAL_REFERENCE_FLAG_OPTIONAL : 0,
|
|
Iter->SourceAssembly(),
|
|
pActCtxGenCtx,
|
|
TargetAssemblyRef,
|
|
AssemblyFound,
|
|
fFound));
|
|
|
|
INTERNAL_ERROR_CHECK(fFound || Iter->IsOptional());
|
|
|
|
if (fFound)
|
|
{
|
|
PCASSEMBLY_IDENTITY pAssemblyIdentity = NULL;
|
|
PCWSTR szLanguage;
|
|
SIZE_T cchLanguage;
|
|
|
|
IFW32FALSE_EXIT(::SxspAddManifestToActCtxGenCtx(pActCtxGenCtx, AssemblyFound, &Assembly));
|
|
|
|
// Note that AssemblyFound is no longer intact; this is to avoid duplication of
|
|
// the assembly identity inside the SxspAddManifestToActCtxGenCtx() call.
|
|
|
|
if (Iter->IsMetadataSatellite())
|
|
Iter->SourceAssembly()->m_MetadataSatelliteRosterIndex = Assembly->m_AssemblyRosterIndex;
|
|
|
|
// If it's a worldwide assembly, we want to auto-probe for the MUI assembly
|
|
IFW32FALSE_EXIT(
|
|
::SxspGetAssemblyIdentityAttributeValue(
|
|
SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
|
|
Assembly->m_ProbedAssemblyInformation.GetAssemblyIdentity(),
|
|
&s_IdentityAttribute_language,
|
|
&szLanguage,
|
|
&cchLanguage));
|
|
|
|
if (cchLanguage == 0)
|
|
{
|
|
CSmallStringBuffer &buffName = Locals->buffName;
|
|
PCWSTR szName;
|
|
SIZE_T cchName;
|
|
CProbedAssemblyInformation &MuiAssemblyFound = Locals->MuiAssemblyFound;
|
|
MuiAssemblyFound.Reinitialize();
|
|
CAssemblyReference MuiAssemblyRef;
|
|
|
|
::SxsDestroyAssemblyIdentity(MuiAssemblyIdentity.Detach());
|
|
|
|
IFW32FALSE_EXIT(
|
|
::SxsDuplicateAssemblyIdentity(
|
|
0,
|
|
Assembly->m_ProbedAssemblyInformation.GetAssemblyIdentity(), // PCASSEMBLY_IDENTITY Source,
|
|
&MuiAssemblyIdentity));
|
|
|
|
IFW32FALSE_EXIT(
|
|
::SxspSetAssemblyIdentityAttributeValue(
|
|
SXSP_SET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_OVERWRITE_EXISTING,
|
|
MuiAssemblyIdentity,
|
|
&s_IdentityAttribute_language,
|
|
L"*",
|
|
1));
|
|
|
|
IFW32FALSE_EXIT(
|
|
::SxspGetAssemblyIdentityAttributeValue(
|
|
0,
|
|
MuiAssemblyIdentity,
|
|
&s_IdentityAttribute_name,
|
|
&szName,
|
|
&cchName));
|
|
|
|
IFW32FALSE_EXIT(buffName.Win32Assign(szName, cchName));
|
|
IFW32FALSE_EXIT(buffName.Win32Append(L".mui", 4));
|
|
|
|
IFW32FALSE_EXIT(
|
|
::SxspSetAssemblyIdentityAttributeValue(
|
|
SXSP_SET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_OVERWRITE_EXISTING,
|
|
MuiAssemblyIdentity,
|
|
&s_IdentityAttribute_name,
|
|
buffName,
|
|
buffName.Cch()));
|
|
|
|
IFW32FALSE_EXIT(MuiAssemblyFound.Initialize(pActCtxGenCtx));
|
|
IFW32FALSE_EXIT(MuiAssemblyRef.Initialize(MuiAssemblyIdentity));
|
|
|
|
IFW32FALSE_EXIT(
|
|
::SxspResolvePartialReference(
|
|
SXSP_RESOLVE_PARTIAL_REFERENCE_FLAG_OPTIONAL |
|
|
SXSP_RESOLVE_PARTIAL_REFERENCE_FLAG_SKIP_WORLDWIDE,
|
|
Iter->SourceAssembly(),
|
|
pActCtxGenCtx,
|
|
MuiAssemblyRef,
|
|
MuiAssemblyFound,
|
|
fFound));
|
|
|
|
if (fFound)
|
|
IFW32FALSE_EXIT(::SxspAddManifestToActCtxGenCtx(pActCtxGenCtx, MuiAssemblyFound, NULL));
|
|
}
|
|
|
|
}
|
|
|
|
EntryToDelete = Iter;
|
|
}
|
|
|
|
if (EntryToDelete != NULL)
|
|
{
|
|
pActCtxGenCtx->m_PendingAssemblyList.Remove(EntryToDelete);
|
|
FUSION_DELETE_SINGLETON(EntryToDelete);
|
|
}
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL
|
|
SxspProcessPendingAssemblies(
|
|
PACTCTXGENCTX pActCtxGenCtx
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CSmartPtr<CSxspProcessPendingAssembliesLocals> Locals;
|
|
|
|
IFW32FALSE_EXIT(Locals.Win32Allocate(__FILE__, __LINE__));
|
|
IFW32FALSE_EXIT(::SxspProcessPendingAssemblies(pActCtxGenCtx, Locals));
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL
|
|
SxspCloseManifestGraph(
|
|
PACTCTXGENCTX pActCtxGenCtx
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CDequeIterator<ASSEMBLY, offsetof(ASSEMBLY, m_Linkage)> Iter(&pActCtxGenCtx->m_AssemblyList);
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
|
|
// We need to just walk the list of assemblies, incorporating any that aren't already
|
|
// incorporated into the actctx data. New ones found during incorporation are appended
|
|
// to the end of the list, so we should complete everything with a single walk.
|
|
for (Iter.Reset(); Iter.More(); Iter.Next())
|
|
{
|
|
if (!Iter->m_Incorporated)
|
|
{
|
|
IFW32FALSE_EXIT(::SxspIncorporateAssembly(pActCtxGenCtx, Iter));
|
|
}
|
|
else
|
|
{
|
|
PCWSTR AssemblyName = L"<assembly name unavailable>";
|
|
PCWSTR ManifestPath = L"<manifest path unavailable>";
|
|
Iter->m_ProbedAssemblyInformation.GetAssemblyName(&AssemblyName, NULL);
|
|
Iter->m_ProbedAssemblyInformation.GetManifestPath(&ManifestPath, NULL);
|
|
#if DBG
|
|
::FusionpDbgPrintEx(FUSION_DBG_LEVEL_INFO, "SXS.DLL: Skipping already incorporated assembly %S (manifest: %S)\n", AssemblyName, ManifestPath);
|
|
#endif
|
|
}
|
|
|
|
IFW32FALSE_EXIT(::SxspProcessPendingAssemblies(pActCtxGenCtx));
|
|
}
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
BOOL
|
|
SxspBuildActCtxData(
|
|
PACTCTXGENCTX pActCtxGenCtx,
|
|
PHANDLE SectionHandle
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CActivationContextGenerationContextContributor *Ctb = NULL;
|
|
SIZE_T SectionTotalSize = 0;
|
|
SIZE_T TotalHeaderSize = 0;
|
|
SIZE_T AssemblyRosterSize = 0;
|
|
ULONG SectionCount = 0;
|
|
ULONG ExtendedSectionCount = 0;
|
|
ULONG NonExtendedSectionCount = 0;
|
|
CSmartArrayPtr<GUID> ExtendedSectionGuids;
|
|
ULONG ExtensionGuidCount = 0;
|
|
PACTIVATION_CONTEXT_DATA ActCtxData = NULL;
|
|
CMappedViewOfFile VoidActCtxData;
|
|
CFileMapping TempMappingHandle;
|
|
BYTE *Cursor = NULL;
|
|
ULONG i;
|
|
CDequeIterator<ASSEMBLY, offsetof(ASSEMBLY, m_Linkage)> AssemblyIter(&pActCtxGenCtx->m_AssemblyList);
|
|
PACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader = NULL;
|
|
PACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY AssemblyRosterEntry = NULL;
|
|
PCACTIVATION_CONTEXT_STRING_SECTION_HEADER AssemblyInformationSection = NULL; // we use this after the main part of
|
|
// processing to fill in the assembly roster
|
|
PARAMETER_CHECK(pActCtxGenCtx != NULL);
|
|
INTERNAL_ERROR_CHECK(pActCtxGenCtx->m_ManifestOperation == MANIFEST_OPERATION_GENERATE_ACTIVATION_CONTEXT);
|
|
|
|
// Let's see how big this whole thing is going to be now.
|
|
|
|
for (i=0; i<pActCtxGenCtx->m_ContributorCount; i++)
|
|
{
|
|
Ctb = &pActCtxGenCtx->m_Contributors[i];
|
|
|
|
IFW32FALSE_EXIT(Ctb->Fire_AllParsingDone(pActCtxGenCtx));
|
|
IFW32FALSE_EXIT(Ctb->Fire_GetSectionSize(pActCtxGenCtx));
|
|
|
|
if (Ctb->SectionSize() > ULONG_MAX)
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Contributor %S wants more than ULONG_MAX bytes for its section; failing activation context creation.\n",
|
|
Ctb->Name());
|
|
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(ContributorNeedsMoreThan2ToThe32ndBytes, ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
SectionTotalSize += Ctb->SectionSize();
|
|
|
|
if (Ctb->SectionSize() != 0)
|
|
{
|
|
SectionCount++;
|
|
|
|
if (Ctb->IsExtendedSection())
|
|
ExtendedSectionCount++;
|
|
else
|
|
NonExtendedSectionCount++;
|
|
}
|
|
}
|
|
|
|
ASSERT(SectionCount == (ExtendedSectionCount + NonExtendedSectionCount));
|
|
|
|
// If we had any extended sections, we need to figure out how many
|
|
// unique extension GUIDs were present.
|
|
|
|
ExtensionGuidCount = 0;
|
|
|
|
if (ExtendedSectionCount != 0)
|
|
{
|
|
// There may only be one GUID with 1000 instances, but for the sake of
|
|
// simplicity, we'll just allocate an array equal in size to the number
|
|
// of extended sections, and do a linear search to find dups. This
|
|
// is a clear candidate for rewriting if the extensibility story
|
|
// takes off. -mgrier 2/24/2000
|
|
IFW32FALSE_EXIT(ExtendedSectionGuids.Win32Allocate(ExtendedSectionCount, __FILE__, __LINE__));
|
|
// IFALLOCFAILED_EXIT(ExtendedSectionGuids = FUSION_NEW_ARRAY(GUID, ExtendedSectionCount));
|
|
|
|
for (i=0; i<pActCtxGenCtx->m_ContributorCount; i++)
|
|
{
|
|
Ctb = &pActCtxGenCtx->m_Contributors[i];
|
|
|
|
if ((Ctb->SectionSize() != 0) &&
|
|
Ctb->IsExtendedSection())
|
|
{
|
|
ULONG j;
|
|
|
|
for (j=0; j<ExtensionGuidCount; j++)
|
|
{
|
|
if (ExtendedSectionGuids[j] == Ctb->ExtensionGuid())
|
|
break;
|
|
}
|
|
|
|
if (j == ExtensionGuidCount)
|
|
ExtendedSectionGuids[ExtensionGuidCount++] = Ctb->ExtensionGuid();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Figure out the entire size. SectionTotalSize already includes all the
|
|
// particular data from the sections; now we need to add in space for the
|
|
// headers etc.
|
|
|
|
TotalHeaderSize = 0;
|
|
|
|
// The header for the whole thing
|
|
TotalHeaderSize += sizeof(ACTIVATION_CONTEXT_DATA);
|
|
|
|
if (NonExtendedSectionCount != 0)
|
|
{
|
|
// The header for the default section TOC
|
|
TotalHeaderSize += sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER);
|
|
// The entry for each non-extended section entry in the TOC. For now we'll
|
|
// just put the entries in whatever order they're in in the contributor list.
|
|
// the code is in place to do the linear searches and we can optimize this
|
|
// later.
|
|
TotalHeaderSize += (sizeof(ACTIVATION_CONTEXT_DATA_TOC_ENTRY) * NonExtendedSectionCount);
|
|
}
|
|
|
|
if (ExtensionGuidCount != 0)
|
|
{
|
|
ULONG j;
|
|
|
|
// The header for the extension GUID TOC
|
|
TotalHeaderSize += sizeof(ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_HEADER);
|
|
// The entry for each extension GUID
|
|
TotalHeaderSize += (sizeof(ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_ENTRY) * ExtensionGuidCount);
|
|
|
|
for (j=0; j<ExtensionGuidCount; j++)
|
|
{
|
|
ULONG SectionCountForThisExtension = 0;
|
|
for (j=0; j<pActCtxGenCtx->m_ContributorCount; j++)
|
|
{
|
|
Ctb = &pActCtxGenCtx->m_Contributors[j];
|
|
|
|
if ((Ctb->SectionSize() != 0) &&
|
|
Ctb->IsExtendedSection() &&
|
|
(Ctb->ExtensionGuid() == ExtendedSectionGuids[j]))
|
|
SectionCountForThisExtension++;
|
|
}
|
|
|
|
TotalHeaderSize += sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER);
|
|
TotalHeaderSize += (sizeof(ACTIVATION_CONTEXT_DATA_TOC_ENTRY) * SectionCountForThisExtension);
|
|
}
|
|
}
|
|
|
|
SectionTotalSize += TotalHeaderSize;
|
|
|
|
// Allocate space for the assembly roster and the one dead entry at the beginning of the array.
|
|
AssemblyRosterSize =
|
|
sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)
|
|
+ sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY)
|
|
+ (sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY) * pActCtxGenCtx->m_AssemblyList.GetEntryCount());
|
|
|
|
SectionTotalSize += AssemblyRosterSize;
|
|
|
|
if (SectionTotalSize > ULONG_MAX)
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"SXS.DLL: Total size of activation context exceeds ULONG_MAX; failing activation context creation.\n");
|
|
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(SectionSizeTotalMoreThan2ToThe32nd, ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ACTCTX,
|
|
"SXS.DLL: Creating %lu byte file mapping\n", static_cast<ULONG>(SectionTotalSize));
|
|
|
|
|
|
|
|
IFW32NULL_EXIT(
|
|
TempMappingHandle.Win32CreateFileMapping(
|
|
INVALID_HANDLE_VALUE, // Pagefile backed section
|
|
PAGE_READWRITE,
|
|
SectionTotalSize));
|
|
|
|
IFW32NULL_EXIT(VoidActCtxData.Win32MapViewOfFile(TempMappingHandle, FILE_MAP_WRITE));
|
|
ActCtxData = reinterpret_cast<PACTIVATION_CONTEXT_DATA>(static_cast<PVOID>(VoidActCtxData));
|
|
|
|
ActCtxData->Magic = ACTIVATION_CONTEXT_DATA_MAGIC;
|
|
ActCtxData->HeaderSize = sizeof(ACTIVATION_CONTEXT_DATA);
|
|
ActCtxData->FormatVersion = ACTIVATION_CONTEXT_DATA_FORMAT_WHISTLER;
|
|
ActCtxData->TotalSize = static_cast<ULONG>(SectionTotalSize);
|
|
ActCtxData->Flags = 0;
|
|
|
|
if (pActCtxGenCtx->m_NoInherit)
|
|
ActCtxData->Flags |= ACTIVATION_CONTEXT_FLAG_NO_INHERIT;
|
|
|
|
Cursor = (BYTE *) (ActCtxData + 1);
|
|
|
|
AssemblyRosterHeader = (PACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) Cursor;
|
|
|
|
Cursor = (BYTE *) (AssemblyRosterHeader + 1);
|
|
|
|
AssemblyRosterHeader->HeaderSize = sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER);
|
|
AssemblyRosterHeader->HashAlgorithm = FUSION_HASH_ALGORITHM;
|
|
AssemblyRosterHeader->EntryCount = static_cast<ULONG>(pActCtxGenCtx->m_AssemblyList.GetEntryCount() + 1);
|
|
AssemblyRosterHeader->FirstEntryOffset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) ActCtxData));
|
|
|
|
AssemblyRosterEntry = (PACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY) Cursor;
|
|
Cursor = (BYTE *) (AssemblyRosterEntry + AssemblyRosterHeader->EntryCount);
|
|
|
|
// First assembly roster entry is a blank one for index 0
|
|
AssemblyRosterEntry[0].Flags = ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY_INVALID;
|
|
AssemblyRosterEntry[0].AssemblyNameLength = 0;
|
|
AssemblyRosterEntry[0].AssemblyNameOffset = 0;
|
|
AssemblyRosterEntry[0].PseudoKey = 0;
|
|
|
|
// Fill in the roster with bogus data to start with; we'll fill it in for real after
|
|
// we've found the assembly information section.
|
|
for (AssemblyIter.Reset(), i = 1; AssemblyIter.More(); AssemblyIter.Next(), i++)
|
|
{
|
|
AssemblyRosterEntry[i].Flags = ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY_INVALID;
|
|
|
|
if (AssemblyIter->IsRoot())
|
|
AssemblyRosterEntry[i].Flags |= ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY_ROOT;
|
|
}
|
|
|
|
ActCtxData->AssemblyRosterOffset = static_cast<LONG>(((LONG_PTR) AssemblyRosterHeader) - ((LONG_PTR) ActCtxData));
|
|
|
|
if (NonExtendedSectionCount != 0)
|
|
{
|
|
PACTIVATION_CONTEXT_DATA_TOC_HEADER Toc = (PACTIVATION_CONTEXT_DATA_TOC_HEADER) Cursor;
|
|
PACTIVATION_CONTEXT_DATA_TOC_ENTRY Entry = (PACTIVATION_CONTEXT_DATA_TOC_ENTRY) (Toc + 1);
|
|
ULONG iEntry = 0;
|
|
ULONG j;
|
|
ULONG LastSectionId;
|
|
|
|
Toc->HeaderSize = sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER);
|
|
Toc->EntryCount = NonExtendedSectionCount;
|
|
Toc->FirstEntryOffset = static_cast<LONG>(((LONG_PTR) Entry) - ((LONG_PTR) ActCtxData));
|
|
|
|
Cursor = (BYTE *) (Entry + NonExtendedSectionCount);
|
|
|
|
// Since we sorted the providers prior to building the array, we can set the
|
|
// inorder bit so that we at least do a binary search at runtime.
|
|
// We'll assume it's dense also; if we find out that it isn't while we're
|
|
// building, we'll clear the dense bit.
|
|
Toc->Flags = ACTIVATION_CONTEXT_DATA_TOC_HEADER_INORDER | ACTIVATION_CONTEXT_DATA_TOC_HEADER_DENSE;
|
|
|
|
for (j=0; j<pActCtxGenCtx->m_ContributorCount; j++)
|
|
{
|
|
Ctb = &pActCtxGenCtx->m_Contributors[j];
|
|
|
|
LastSectionId = 0;
|
|
|
|
if ((Ctb->SectionSize() != 0) &&
|
|
!Ctb->IsExtendedSection())
|
|
{
|
|
if (iEntry != 0)
|
|
{
|
|
if (Ctb->SectionId() != (LastSectionId + 1))
|
|
Toc->Flags &= ~ACTIVATION_CONTEXT_DATA_TOC_HEADER_DENSE;
|
|
}
|
|
|
|
LastSectionId = Ctb->SectionId();
|
|
|
|
Entry->Id = Ctb->SectionId();
|
|
Entry->Offset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) ActCtxData));
|
|
Entry->Length = static_cast<ULONG>(Ctb->SectionSize());
|
|
Entry->Format = Ctb->SectionFormat();
|
|
|
|
IFW32FALSE_EXIT(Ctb->Fire_GetSectionData(pActCtxGenCtx, Cursor));
|
|
|
|
// We have special knowledge about the assembly metadata section; we reference it
|
|
// in the assembly roster.
|
|
if (Ctb->SectionId() == ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION)
|
|
AssemblyInformationSection = (PCACTIVATION_CONTEXT_STRING_SECTION_HEADER) Cursor;
|
|
|
|
Cursor = (BYTE *) (((ULONG_PTR) Cursor) + Ctb->SectionSize());
|
|
Entry++;
|
|
iEntry++;
|
|
}
|
|
}
|
|
|
|
ActCtxData->DefaultTocOffset = static_cast<LONG>(((LONG_PTR) Toc) - ((LONG_PTR) ActCtxData));
|
|
}
|
|
else
|
|
ActCtxData->DefaultTocOffset = 0;
|
|
|
|
if (ExtensionGuidCount != 0)
|
|
{
|
|
ULONG j;
|
|
PACTIVATION_CONTEXT_DATA_EXTENDED_TOC_HEADER ExtToc = (PACTIVATION_CONTEXT_DATA_EXTENDED_TOC_HEADER) Cursor;
|
|
PACTIVATION_CONTEXT_DATA_EXTENDED_TOC_ENTRY ExtTocEntry = (PACTIVATION_CONTEXT_DATA_EXTENDED_TOC_ENTRY) (ExtToc + 1);
|
|
|
|
Cursor = (BYTE *) (ExtTocEntry + ExtensionGuidCount);
|
|
|
|
ExtToc->HeaderSize = sizeof(ACTIVATION_CONTEXT_DATA_EXTENDED_TOC_HEADER);
|
|
ExtToc->EntryCount = ExtensionGuidCount;
|
|
ExtToc->FirstEntryOffset = static_cast<LONG>(((LONG_PTR) ExtTocEntry) - ((LONG_PTR) ActCtxData));
|
|
ExtToc->Flags = 0;
|
|
|
|
for (j=0; j<ExtensionGuidCount; j++)
|
|
{
|
|
ULONG k;
|
|
ULONG SectionCountForThisExtension = 0;
|
|
PACTIVATION_CONTEXT_DATA_TOC_HEADER Toc = (PACTIVATION_CONTEXT_DATA_TOC_HEADER) Cursor;
|
|
PACTIVATION_CONTEXT_DATA_TOC_ENTRY Entry = (PACTIVATION_CONTEXT_DATA_TOC_ENTRY) (Toc + 1);
|
|
|
|
ExtTocEntry->ExtensionGuid = ExtendedSectionGuids[i];
|
|
|
|
for (k=0; k<pActCtxGenCtx->m_ContributorCount; k++)
|
|
{
|
|
Ctb = &pActCtxGenCtx->m_Contributors[k];
|
|
|
|
if ((Ctb->SectionSize() != 0) &&
|
|
Ctb->IsExtendedSection() &&
|
|
(Ctb->ExtensionGuid() == ExtendedSectionGuids[j]))
|
|
{
|
|
SectionCountForThisExtension++;
|
|
}
|
|
}
|
|
|
|
Cursor = (BYTE *) (Entry + SectionCountForThisExtension);
|
|
|
|
Toc->HeaderSize = sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER);
|
|
Toc->EntryCount = SectionCountForThisExtension;
|
|
Toc->FirstEntryOffset = static_cast<LONG>(((LONG_PTR) Entry) - ((LONG_PTR) ActCtxData));
|
|
Toc->Flags = 0;
|
|
|
|
for (k=0; k<pActCtxGenCtx->m_ContributorCount; k++)
|
|
{
|
|
Ctb = &pActCtxGenCtx->m_Contributors[k];
|
|
|
|
if ((Ctb->SectionSize() != 0) &&
|
|
Ctb->IsExtendedSection() &&
|
|
(Ctb->ExtensionGuid() == ExtendedSectionGuids[k]) &&
|
|
(Ctb->SectionId() != 0) )
|
|
{
|
|
SIZE_T SectionSize = Ctb->SectionSize();
|
|
|
|
Entry->Id = Ctb->SectionId();
|
|
Entry->Offset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) ActCtxData));
|
|
Entry->Length = static_cast<ULONG>(SectionSize);
|
|
Entry->Format = Ctb->SectionFormat();
|
|
|
|
IFW32FALSE_EXIT(Ctb->Fire_GetSectionData(pActCtxGenCtx, Cursor));
|
|
|
|
Cursor = (BYTE *) (((ULONG_PTR) Cursor) + SectionSize);
|
|
Entry++;
|
|
}
|
|
}
|
|
}
|
|
|
|
ActCtxData->ExtendedTocOffset = static_cast<LONG>(((LONG_PTR) ExtToc) - ((LONG_PTR) ActCtxData));
|
|
}
|
|
else
|
|
ActCtxData->ExtendedTocOffset = 0;
|
|
|
|
ASSERT(AssemblyInformationSection != NULL);
|
|
// Go back and fill in the assembly roster...
|
|
if (AssemblyInformationSection != NULL)
|
|
{
|
|
PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY Entries = (PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY)
|
|
(((ULONG_PTR) AssemblyInformationSection) + AssemblyInformationSection->ElementListOffset);
|
|
LONG_PTR SectionOffset = ((LONG_PTR) AssemblyInformationSection) - ((LONG_PTR) ActCtxData);
|
|
|
|
AssemblyRosterHeader->HashAlgorithm = AssemblyInformationSection->HashAlgorithm;
|
|
AssemblyRosterHeader->AssemblyInformationSectionOffset = static_cast<ULONG>(SectionOffset);
|
|
|
|
// If there are 3 assemblies, there must be 3 entries in the section and 4 roster entries
|
|
// (counting the bogus entry 0).
|
|
ASSERT(AssemblyInformationSection->ElementCount == (AssemblyRosterHeader->EntryCount - 1));
|
|
if (AssemblyInformationSection->ElementCount != (AssemblyRosterHeader->EntryCount - 1))
|
|
{
|
|
::FusionpSetLastWin32Error(ERROR_INTERNAL_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
for (i=0; i<AssemblyInformationSection->ElementCount; i++)
|
|
{
|
|
ULONG iRoster = Entries[i].AssemblyRosterIndex;
|
|
|
|
ASSERT(iRoster != 0);
|
|
ASSERT(iRoster < AssemblyRosterHeader->EntryCount);
|
|
|
|
if ((iRoster == 0) ||
|
|
(iRoster >= AssemblyRosterHeader->EntryCount))
|
|
{
|
|
::FusionpSetLastWin32Error(ERROR_INTERNAL_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure that we're not repeating an index somehow...
|
|
ASSERT(AssemblyRosterEntry[iRoster].Flags & ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY_INVALID);
|
|
if ((AssemblyRosterEntry[iRoster].Flags & ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY_INVALID) == 0)
|
|
{
|
|
::FusionpSetLastWin32Error(ERROR_INTERNAL_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// Turn off the invalid flag...
|
|
AssemblyRosterEntry[iRoster].Flags &= ~ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_ENTRY_INVALID;
|
|
|
|
// Point to the data already in the string section header
|
|
AssemblyRosterEntry[iRoster].AssemblyNameLength = Entries[i].KeyLength;
|
|
|
|
if (Entries[i].KeyOffset != 0)
|
|
AssemblyRosterEntry[iRoster].AssemblyNameOffset = static_cast<LONG>(Entries[i].KeyOffset + SectionOffset);
|
|
else
|
|
AssemblyRosterEntry[iRoster].AssemblyNameOffset = 0;
|
|
|
|
AssemblyRosterEntry[iRoster].AssemblyInformationLength = Entries[i].Length;
|
|
AssemblyRosterEntry[iRoster].AssemblyInformationOffset = static_cast<LONG>(Entries[i].Offset + SectionOffset);
|
|
AssemblyRosterEntry[iRoster].PseudoKey = Entries[i].PseudoKey;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the assembly metadata section provider should have contributed *something*
|
|
::FusionpSetLastWin32Error(ERROR_INTERNAL_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if (::FusionpDbgWouldPrintAtFilterLevel(FUSION_DBG_LEVEL_ACTCTX))
|
|
{
|
|
CTinyStringBuffer buffPrefix;
|
|
::SxspDbgPrintActivationContextData(FUSION_DBG_LEVEL_ACTCTX, ActCtxData, buffPrefix);
|
|
}
|
|
|
|
IFW32FALSE_EXIT(VoidActCtxData.Win32Close());
|
|
*SectionHandle = TempMappingHandle.Detach();
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
CPendingAssembly::CPendingAssembly() :
|
|
m_SourceAssembly(NULL),
|
|
m_Identity(NULL),
|
|
m_Optional(false),
|
|
m_MetadataSatellite(false)
|
|
{
|
|
}
|
|
|
|
CPendingAssembly::~CPendingAssembly()
|
|
{
|
|
if (m_Identity != NULL)
|
|
{
|
|
::SxsDestroyAssemblyIdentity(m_Identity);
|
|
m_Identity = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CPendingAssembly::Initialize(
|
|
PASSEMBLY Assembly,
|
|
PCASSEMBLY_IDENTITY Identity,
|
|
bool Optional,
|
|
bool MetadataSatellite
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
INTERNAL_ERROR_CHECK(m_Identity == NULL);
|
|
|
|
PARAMETER_CHECK(Identity != NULL);
|
|
|
|
IFW32FALSE_EXIT(::SxsDuplicateAssemblyIdentity(0, Identity, &m_Identity));
|
|
m_SourceAssembly = Assembly;
|
|
m_Optional = Optional;
|
|
m_MetadataSatellite = MetadataSatellite;
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|