summaryrefslogtreecommitdiff
path: root/src/vm/fusionbind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/fusionbind.cpp')
-rw-r--r--src/vm/fusionbind.cpp661
1 files changed, 0 insertions, 661 deletions
diff --git a/src/vm/fusionbind.cpp b/src/vm/fusionbind.cpp
deleted file mode 100644
index 0a337796bb..0000000000
--- a/src/vm/fusionbind.cpp
+++ /dev/null
@@ -1,661 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*============================================================
-**
-** Header: FusionBind.cpp
-**
-** Purpose: Implements fusion interface
-**
-**
-
-
-===========================================================*/
-
-#include "common.h"
-
-#include <stdlib.h>
-#include "fusionbind.h"
-#include "shimload.h"
-#include "eventtrace.h"
-#include "strongnameholders.h"
-
-HRESULT BaseAssemblySpec::ParseName()
-{
- CONTRACTL
- {
- INSTANCE_CHECK;
- GC_NOTRIGGER;
- NOTHROW;
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- HRESULT hr = S_OK;
-
- if (!m_pAssemblyName)
- return S_OK;
-
- CQuickBytes ssName;
-
- hr = ssName.ConvertUtf8_UnicodeNoThrow(m_pAssemblyName);
-
- if (SUCCEEDED(hr))
- {
- NonVMComHolder<IAssemblyName> pName;
-
- IfFailRet(CreateAssemblyNameObject(&pName, (LPCWSTR) ssName.Ptr(), CANOF_PARSE_DISPLAY_NAME, NULL));
-
- if (m_ownedFlags & NAME_OWNED)
- delete [] m_pAssemblyName;
- m_pAssemblyName = NULL;
-
- hr = Init(pName);
- }
-
- return hr;
-}
-
-void BaseAssemblySpec::GetFileOrDisplayName(DWORD flags, SString &result) const
-{
- CONTRACTL
- {
- INSTANCE_CHECK;
- THROWS;
- INJECT_FAULT(ThrowOutOfMemory());
- PRECONDITION(CheckValue(result));
- PRECONDITION(result.IsEmpty());
- }
- CONTRACTL_END;
-
- if (m_pAssemblyName != NULL) {
- NonVMComHolder<IAssemblyName> pFusionName;
- IfFailThrow(CreateFusionName(&pFusionName));
-
- FusionBind::GetAssemblyNameDisplayName(pFusionName, result, flags);
- }
- else
- result.Set(m_wszCodeBase);
-}
-
-HRESULT AssemblySpec::LoadAssembly(IApplicationContext* pFusionContext,
- FusionSink *pSink,
- IAssembly** ppIAssembly,
- IHostAssembly** ppIHostAssembly,
- IBindResult** ppNativeFusionAssembly,
- BOOL fForIntrospectionOnly,
- BOOL fSuppressSecurityChecks)
-{
- CONTRACTL
- {
- INSTANCE_CHECK;
- THROWS;
- MODE_PREEMPTIVE;
- INJECT_FAULT(ThrowOutOfMemory());
- }
- CONTRACTL_END;
-
- HRESULT hr = E_FAIL;
-
- if (!IsAfContentType_Default(m_dwFlags))
- { // Fusion can process only Default ContentType (non-WindowsRuntime)
- IfFailThrow(COR_E_BADIMAGEFORMAT);
- }
-
- NonVMComHolder<IAssembly> pIAssembly(NULL);
- NonVMComHolder<IBindResult> pNativeFusionAssembly(NULL);
- NonVMComHolder<IHostAssembly> pIHostAssembly(NULL);
- NonVMComHolder<IAssemblyName> pSpecName;
- NonVMComHolder<IAssemblyName> pCodeBaseName;
-
-
- BOOL fFXOnly = FALSE;
- DWORD size = sizeof(fFXOnly);
-
- hr = pFusionContext->Get(ACTAG_FX_ONLY, &fFXOnly, &size, 0);
- if(FAILED(hr))
- {
- /// just in case it corrupted fFXOnly
- fFXOnly = FALSE;
- }
-
- // reset hr
- hr = E_FAIL;
-
- // Make sure we don't have malformed names
-
- if (m_pAssemblyName)
- IfFailGo(FusionBind::VerifyBindingString(m_pAssemblyName));
-
- if (m_context.szLocale)
- IfFailGo(FusionBind::VerifyBindingString(m_context.szLocale));
-
- // If we have assembly name info, first bind using that
- if (m_pAssemblyName != NULL) {
- IfFailGo(CreateFusionName(&pSpecName, FALSE));
-
- if(m_fParentLoadContext == LOADCTX_TYPE_UNKNOWN)
- {
- BOOL bOptionallyRetargetable;
- IfFailGo(IsOptionallyRetargetableAssembly(pSpecName, &bOptionallyRetargetable));
- if (bOptionallyRetargetable)
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // do not propagate to load, let the event handle
- }
-
- hr = FusionBind::RemoteLoad(pFusionContext, pSink,
- pSpecName, GetParentIAssembly(), NULL,
- &pIAssembly, &pIHostAssembly, &pNativeFusionAssembly, fForIntrospectionOnly, fSuppressSecurityChecks);
- }
-
-
- // Now, bind using the codebase.
- if (FAILED(hr) && !fFXOnly && m_wszCodeBase) {
- // No resolution by code base for SQL-hosted environment, except for introspection
- if((!fForIntrospectionOnly) && CorHost2::IsLoadFromBlocked())
- {
- hr = FUSION_E_LOADFROM_BLOCKED;
- goto ErrExit;
- }
- IfFailGo(CreateAssemblyNameObject(&pCodeBaseName, NULL, 0, NULL));
-
- IfFailGo(pCodeBaseName->SetProperty(ASM_NAME_CODEBASE_URL,
- (void*)m_wszCodeBase,
- (DWORD)(wcslen(m_wszCodeBase) + 1) * sizeof(WCHAR)));
-
- // Note that we cannot bind a native image using a codebase, as it will
- // always be in the LoadFrom context which does not support native images.
-
- pSink->Reset();
- hr = FusionBind::RemoteLoad(pFusionContext, pSink,
- pCodeBaseName, NULL, m_wszCodeBase,
- &pIAssembly, &pIHostAssembly, &pNativeFusionAssembly, fForIntrospectionOnly, fSuppressSecurityChecks);
-
- // If we had both name info and codebase, make sure they are consistent.
- if (SUCCEEDED(hr) && m_pAssemblyName != NULL) {
-
- NonVMComHolder<IAssemblyName> pPolicyRefName(NULL);
- if (!fForIntrospectionOnly) {
- // Get post-policy ref, because we'll be comparing
- // it against a post-policy def
- HRESULT policyHr = PreBindAssembly(pFusionContext,
- pSpecName,
- NULL, // pAsmParent
- &pPolicyRefName,
- NULL); // pvReserved
- if (FAILED(policyHr) && (policyHr != FUSION_E_REF_DEF_MISMATCH) &&
- (policyHr != E_INVALIDARG)) // partial ref
- IfFailGo(policyHr);
- }
-
- NonVMComHolder<IAssemblyName> pBoundName;
- if (pIAssembly == NULL)
- IfFailGo(pIHostAssembly->GetAssemblyNameDef(&pBoundName));
- else
- IfFailGo(pIAssembly->GetAssemblyNameDef(&pBoundName));
-
- // Order matters: Ref->IsEqual(Def)
- HRESULT equalHr;
- if (pPolicyRefName)
- equalHr = pPolicyRefName->IsEqual(pBoundName, ASM_CMPF_DEFAULT);
- else
- equalHr = pSpecName->IsEqual(pBoundName, ASM_CMPF_DEFAULT);
- if (equalHr != S_OK)
- {
- // post-policy name is pBoundName and it's not correct for the
- // original name, so we need to clear it
- ReleaseNameAfterPolicy();
- IfFailGo(FUSION_E_REF_DEF_MISMATCH);
- }
- }
- }
-
- // We should have found an assembly by now.
- IfFailGo(hr);
-
- // <NOTE> Comment about the comment below. The work is done in fusion now.
- // But we still keep the comment here to illustrate the problem. </NOTE>
-
- // Until we can create multiple Assembly objects for a single HMODULE
- // we can only store one IAssembly* per Assembly. It is very important
- // to maintain the IAssembly* for an image that is in the load-context.
- // An Assembly in the load-from-context can bind to an assembly in the
- // load-context but not visa-versa. Therefore, if we every get an IAssembly
- // from the load-from-context we must make sure that it will never be
- // found using a load. If it did then we could end up with Assembly dependencies
- // that are wrong. For example, if I do a LoadFrom() on an assembly in the GAC
- // and it requires another Assembly that I have preloaded in the load-from-context
- // then that dependency gets burnt into the Jitted code. Later on a Load() is
- // done on the assembly in the GAC and we single instance it back to the one
- // we have gotten from the load-from-context because the HMODULES are the same.
- // Now the dependency is wrong because it would not have the preloaded assembly
- // if the order was reversed.
-
-#if 0
- if (!fForIntrospectionOnly)
- {
- NonVMComHolder<IFusionLoadContext> pLoadContext;
- if (pIAssembly == NULL)
- IfFailGo(pIHostAssembly->GetFusionLoadContext(&pLoadContext));
- else
- IfFailGo(pIAssembly->GetFusionLoadContext(&pLoadContext));
-
- if (pLoadContext->GetContextType() == LOADCTX_TYPE_LOADFROM) {
- _ASSERTE(pIAssembly != NULL);
- HRESULT hrLocal;
-
- NonVMComHolder<IAssemblyName> pBoundName;
- pIAssembly->GetAssemblyNameDef(&pBoundName);
-
- // We need to copy the bound name to modify it
- IAssemblyName *pClone;
- IfFailGo(pBoundName->Clone(&pClone));
- pBoundName.Release();
- pBoundName = pClone;
-
- // Null out the architecture for the second bind
- IfFailGo(pBoundName->SetProperty(ASM_NAME_ARCHITECTURE, NULL, 0));
-
- NonVMComHolder<IAssembly> pAliasingAssembly;
- NonVMComHolder<IHostAssembly> pIHA;
- pSink->Reset();
- hrLocal = FusionBind::RemoteLoad(pFusionContext, pSink,
- pBoundName, NULL, NULL,
- &pAliasingAssembly, &pIHA, fForIntrospectionOnly);
-
- if(SUCCEEDED(hrLocal)) {
- // If the paths are the same or the loadfrom assembly is in the GAC,
- // then use the non-LoadFrom assembly as the result.
-
- DWORD location;
- hrLocal = pIAssembly->GetAssemblyLocation(&location);
- BOOL alias = (SUCCEEDED(hrLocal) && location == ASMLOC_GAC);
-
- if (!alias) {
- SString boundPath;
- GetAssemblyManifestModulePath(pIAssembly, boundPath);
-
- SString aliasingPath;
- GetAssemblyManifestModulePath(pAliasingAssembly, aliasingPath);
-
- alias = SString::_wcsicmp(boundPath, aliasingPath) == 0;
- }
-
- // Keep the default context's IAssembly if the paths are the same
- if (alias)
- pIAssembly = pAliasingAssembly.Extract();
- }
- }
- }
-#endif
-
- if (SUCCEEDED(hr)) {
- if (pIAssembly == NULL)
- *ppIHostAssembly = pIHostAssembly.Extract();
- else
- *ppIAssembly = pIAssembly.Extract();
- if (ppNativeFusionAssembly) {
- *ppNativeFusionAssembly = pNativeFusionAssembly.Extract();
- }
- }
-
- ErrExit:
- return hr;
-}
-
-
-/* static */
-HRESULT FusionBind::RemoteLoad(IApplicationContext* pFusionContext,
- FusionSink *pSink,
- IAssemblyName *pName,
- IAssembly *pParentAssembly,
- LPCWSTR pCodeBase,
- IAssembly** ppIAssembly,
- IHostAssembly** ppIHostAssembly,
- IBindResult **ppNativeFusionAssembly,
- BOOL fForIntrospectionOnly,
- BOOL fSuppressSecurityChecks)
-{
- CONTRACTL
- {
- THROWS;
- MODE_PREEMPTIVE;
- // The resulting IP must be held so the assembly will not be scavenged.
- PRECONDITION(CheckPointer(ppIAssembly));
- PRECONDITION(CheckPointer(ppIHostAssembly));
-
- PRECONDITION(CheckPointer(pName));
- INJECT_FAULT(return E_OUTOFMEMORY;);
- } CONTRACTL_END;
-
- ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1);
-
- HRESULT hr;
- ASM_BIND_FLAGS dwFlags = ASM_BINDF_NONE;
- DWORD dwReserved = 0;
- LPVOID pReserved = NULL;
-
- // Event Tracing for Windows is used to log data for performance and functional testing purposes.
- // The events below are used to help measure the performance of the download phase of assembly binding (be it download of a remote file or accessing a local file on disk),
- // as well as of lookup scenarios such as from a host store.
- DWORD dwAppDomainId = ETWAppDomainIdNotAvailable;
- if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_PRIVATEBINDING_KEYWORD)) {
- DWORD cbValue = sizeof(dwAppDomainId);
- // Gather data used by ETW events later in this function.
- if (pFusionContext == NULL || FAILED(pFusionContext->Get(ACTAG_APP_DOMAIN_ID, &dwAppDomainId, &cbValue, 0))) {
- dwAppDomainId = ETWAppDomainIdNotAvailable;
- }
- }
-
- NonVMComHolder< IUnknown > pSinkIUnknown(NULL);
- NonVMComHolder< IAssemblyNameBinder> pBinder(NULL);
- *ppNativeFusionAssembly=NULL;
-
- if(pParentAssembly != NULL) {
- // Only use a parent assembly hint when the parent assembly has a load context.
- // Assemblies in anonymous context are not dicoverable by loader's binding rules,
- // thus loader can't find their dependencies.
- // Loader will only try to locate dependencies in default load context.
- if (pParentAssembly->GetFusionLoadContext() != LOADCTX_TYPE_UNKNOWN) {
- dwReserved = sizeof(IAssembly*);
- pReserved = (LPVOID) pParentAssembly;
- dwFlags = ASM_BINDF_PARENT_ASM_HINT;
- }
- }
-
- IfFailRet(pSink->AssemblyResetEvent());
- IfFailRet(pSink->QueryInterface(IID_IUnknown, (void**)&pSinkIUnknown));
- IUnknown *pFusionAssembly=NULL;
- IUnknown *pNativeAssembly=NULL;
- BOOL fCached = TRUE;
-
-
- if (fForIntrospectionOnly)
- {
- dwFlags = (ASM_BIND_FLAGS)(dwFlags | ASM_BINDF_INSPECTION_ONLY);
- }
-
- if (fSuppressSecurityChecks)
- {
- dwFlags = (ASM_BIND_FLAGS)(dwFlags | ASM_BINDF_SUPPRESS_SECURITY_CHECKS);
- }
-
- IfFailRet(pName->QueryInterface(IID_IAssemblyNameBinder, (void **)&pBinder));
- {
- // In SQL, this can call back into the runtime
- CONTRACT_VIOLATION(ThrowsViolation);
- hr = pBinder->BindToObject(IID_IAssembly,
- pSinkIUnknown,
- pFusionContext,
- pCodeBase,
- dwFlags,
- pReserved,
- dwReserved,
- (void**) &pFusionAssembly,
- (void**)&pNativeAssembly);
- }
-
- if(hr == E_PENDING) {
- // If there is an assembly IP then we were successful.
- hr = pSink->Wait();
- if (SUCCEEDED(hr))
- hr = pSink->LastResult();
- if(SUCCEEDED(hr)) {
- if(pSink->m_punk) {
- if (pSink->m_pNIunk)
- pNativeAssembly=pSink->m_pNIunk;
- pFusionAssembly = pSink->m_punk;
- fCached = FALSE;
- }
- else
- hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- }
- }
-
- FireEtwBindingDownloadPhaseEnd(dwAppDomainId, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, pCodeBase, NULL, GetClrInstanceId());
-
- FireEtwBindingLookupAndProbingPhaseEnd(dwAppDomainId, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, pCodeBase, NULL, GetClrInstanceId());
-
- if (SUCCEEDED(hr)) {
- // Keep a handle to ensure it does not disappear from the cache
- // and allow access to modules associated with the assembly.
- hr = pFusionAssembly->QueryInterface(IID_IAssembly,
- (void**) ppIAssembly);
- if (hr == E_NOINTERFACE) // IStream assembly
- hr = pFusionAssembly->QueryInterface(IID_IHostAssembly,
- (void**) ppIHostAssembly);
- if (SUCCEEDED(hr) && pNativeAssembly)
- hr=pNativeAssembly->QueryInterface(IID_IBindResult,
- (void**)ppNativeFusionAssembly);
-
- if (fCached)
- {
- pFusionAssembly->Release();
- if(pNativeAssembly)
- pNativeAssembly->Release();
- }
- }
-
- return hr;
-}
-
-/* static */
-HRESULT FusionBind::RemoteLoadModule(IApplicationContext * pFusionContext,
- IAssemblyModuleImport* pModule,
- FusionSink *pSink,
- IAssemblyModuleImport** pResult)
-{
-
- CONTRACTL
- {
- NOTHROW;
- PRECONDITION(CheckPointer(pFusionContext));
- PRECONDITION(CheckPointer(pModule));
- PRECONDITION(CheckPointer(pSink));
- PRECONDITION(CheckPointer(pResult));
- INJECT_FAULT(return E_OUTOFMEMORY;);
- } CONTRACTL_END;
-
- ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1);
-
- HRESULT hr;
- IfFailGo(pSink->AssemblyResetEvent());
- hr = pModule->BindToObject(pSink,
- pFusionContext,
- ASM_BINDF_NONE,
- (void**) pResult);
- if(hr == E_PENDING) {
- // If there is an assembly IP then we were successful.
- hr = pSink->Wait();
- if (SUCCEEDED(hr))
- hr = pSink->LastResult();
- if (SUCCEEDED(hr)) {
- if(pSink->m_punk)
- hr = pSink->m_punk->QueryInterface(IID_IAssemblyModuleImport,
- (void**) pResult);
- else
- hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- }
- }
-
- ErrExit:
- return hr;
-}
-
-
-/* static */
-HRESULT FusionBind::AddEnvironmentProperty(__in LPCWSTR variable,
- __in LPCWSTR pProperty,
- IApplicationContext* pFusionContext)
-{
- CONTRACTL
- {
- NOTHROW;
- PRECONDITION(CheckPointer(pProperty));
- PRECONDITION(CheckPointer(variable));
- PRECONDITION(CheckPointer(pFusionContext));
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- DWORD size = _MAX_PATH;
- WCHAR rcValue[_MAX_PATH]; // Buffer for the directory.
- WCHAR *pValue = &(rcValue[0]);
- size = WszGetEnvironmentVariable(variable, pValue, size);
- if(size > _MAX_PATH) {
- pValue = (WCHAR*) _alloca(size * sizeof(WCHAR));
- size = WszGetEnvironmentVariable(variable, pValue, size);
- size++; // Add in the null terminator
- }
-
- if(size)
- return pFusionContext->Set(pProperty,
- pValue,
- size * sizeof(WCHAR),
- 0);
- else
- return S_FALSE; // no variable found
-}
-
-// Fusion uses a context class to drive resolution of assemblies.
-// Each application has properties that can be pushed into the
-// fusion context (see fusionp.h). The public api is part of
-// application domains.
-/* static */
-HRESULT FusionBind::SetupFusionContext(LPCWSTR szAppBase,
- LPCWSTR szPrivateBin,
- IApplicationContext** ppFusionContext)
-{
- CONTRACTL
- {
- NOTHROW;
- PRECONDITION(CheckPointer(ppFusionContext));
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- HRESULT hr;
- NonVMComHolder <IApplicationContext> pFusionContext;
-
- LPCWSTR pBase;
- // if the appbase is null then use the current directory
- if (szAppBase == NULL) {
- pBase = (LPCWSTR) _alloca(_MAX_PATH * sizeof(WCHAR));
- if(!WszGetCurrentDirectory(_MAX_PATH, (LPWSTR) pBase))
- IfFailGo(HRESULT_FROM_GetLastError());
- }
- else
- pBase = szAppBase;
-
-
- IfFailGo(CreateFusionContext(pBase, &pFusionContext));
-
-
- IfFailGo((pFusionContext)->Set(ACTAG_APP_BASE_URL,
- (void*) pBase,
- (DWORD)(wcslen(pBase) + 1) * sizeof(WCHAR),
- 0));
-
- if (szPrivateBin)
- IfFailGo((pFusionContext)->Set(ACTAG_APP_PRIVATE_BINPATH,
- (void*) szPrivateBin,
- (DWORD)(wcslen(szPrivateBin) + 1) * sizeof(WCHAR),
- 0));
- else
- IfFailGo(AddEnvironmentProperty(APPENV_RELATIVEPATH, ACTAG_APP_PRIVATE_BINPATH, pFusionContext));
-
- *ppFusionContext=pFusionContext;
- pFusionContext.SuppressRelease();
-
-ErrExit:
- return hr;
-}
-
-/* static */
-HRESULT FusionBind::CreateFusionContext(LPCWSTR pzName, IApplicationContext** ppFusionContext)
-{
- CONTRACTL
- {
- NOTHROW;
- PRECONDITION(CheckPointer(ppFusionContext));
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- // This is a file name not a namespace
- LPCWSTR contextName = NULL;
-
- if(pzName) {
- contextName = wcsrchr( pzName, W('\\') );
- if(contextName)
- contextName++;
- else
- contextName = pzName;
- }
- // We go off and create a fusion context for this application domain.
- // Note, once it is made it can not be modified.
- NonVMComHolder<IAssemblyName> pFusionAssemblyName;
- HRESULT hr = CreateAssemblyNameObject(&pFusionAssemblyName, contextName, 0, NULL);
-
- if(SUCCEEDED(hr))
- hr = CreateApplicationContext(pFusionAssemblyName, ppFusionContext);
-
- return hr;
-}
-
-/* static */
-HRESULT FusionBind::GetVersion(__out_ecount(*pdwVersion) LPWSTR pVersion, __inout DWORD* pdwVersion)
-{
- CONTRACTL
- {
- NOTHROW;
- PRECONDITION(CheckPointer(pdwVersion));
- PRECONDITION(pdwVersion>0 && CheckPointer(pVersion));
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- DWORD dwCORSystem = 0;
-
- LPCWSTR pCORSystem = GetInternalSystemDirectory(&dwCORSystem);
-
- if (dwCORSystem == 0)
- return E_FAIL;
-
- dwCORSystem--; // remove the null character
- if (dwCORSystem && pCORSystem[dwCORSystem-1] == W('\\'))
- dwCORSystem--; // and the trailing slash if it exists
-
- if (dwCORSystem==0)
- return E_FAIL;
-
- const WCHAR* pSeparator;
- const WCHAR* pTail = pCORSystem + dwCORSystem;
-
- for (pSeparator = pCORSystem+dwCORSystem-1; pSeparator > pCORSystem && *pSeparator != W('\\');pSeparator--);
-
- if (*pSeparator == W('\\'))
- pSeparator++;
-
- DWORD lgth = (DWORD)(pTail - pSeparator);
-
- if (lgth > *pdwVersion) {
- *pdwVersion = lgth+1;
- return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
- }
-
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:26000) // "Disable PREFast/espX warning about buffer overflow"
-#endif
- while(pSeparator < pTail)
- *pVersion++ = *pSeparator++;
-
- *pVersion = W('\0');
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
- return S_OK;
-} // FusionBind::GetVersion
-