Skip to content

Commit

Permalink
Well... this fixes the failure to register under pure .NET FW 4+
Browse files Browse the repository at this point in the history
It also lets the .NET FW 4+ assemblies actually register.

So.. that's a win.
But it's a bit ugly.


Signed-off-by: Bevan Weiss <[email protected]>
  • Loading branch information
bevanweiss committed Jul 29, 2024
1 parent d361c56 commit a3826e8
Showing 1 changed file with 35 additions and 8 deletions.
43 changes: 35 additions & 8 deletions src/ext/ComPlus/ca/cpasmexec.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

#include "precomp.h"

#include <mscoree.h>

// GAC related declarations

Expand Down Expand Up @@ -61,6 +61,8 @@ IAssemblyCache : public IUnknown

typedef HRESULT (__stdcall *LoadLibraryShimFunc)(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll);
typedef HRESULT (__stdcall *CreateAssemblyCacheFunc)(IAssemblyCache **ppAsmCache, DWORD dwReserved);
typedef HRESULT (__stdcall *GetFileVersionFnPtr)(LPCWSTR szFilename, _Out_writes_to_opt_(cchBuffer, *dwLength) LPWSTR szBuffer, DWORD cchBuffer, DWORD* dwLength);
typedef HRESULT (__stdcall *CorBindToRuntimeExFnPtr)(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv);


// RegistrationHelper related declarations
Expand Down Expand Up @@ -152,7 +154,8 @@ static HRESULT UnregisterAssembly(
static void InitAssemblyExec();
static void UninitAssemblyExec();
static HRESULT GetRegistrationHelper(
IDispatch** ppiRegHlp
IDispatch** ppiRegHlp,
LPCWSTR pwzAssemblyPath
);
static HRESULT GetAssemblyCacheObject(
IAssemblyCache** ppAssemblyCache
Expand Down Expand Up @@ -718,20 +721,44 @@ static void UninitAssemblyExec()
}

static HRESULT GetRegistrationHelper(
IDispatch** ppiRegHlp
IDispatch** ppiRegHlp,
LPCWSTR pwzAssemblyPath
)
{
HRESULT hr = S_OK;
wchar_t pwzVersion[MAX_PATH];
DWORD pcchVersionLen = MAX_PATH;
ICLRRuntimeHost* runtimeHost = NULL;

if (!ghMscoree)
{
ghMscoree = ::LoadLibraryW(L"mscoree.dll");
ExitOnNull(ghMscoree, hr, E_FAIL, "Failed to load mscoree.dll");
}
GetFileVersionFnPtr GetFileVersion = (GetFileVersionFnPtr)::GetProcAddress(ghMscoree, "GetFileVersion");
ExitOnNull(GetFileVersion, hr, E_FAIL, "Failed to GetProcAddress for 'GetFileVersion' from 'mscoree.dll'");
hr = GetFileVersion(pwzAssemblyPath, pwzVersion, pcchVersionLen, &pcchVersionLen);

if (!gpiRegHlp)
{
CLSID CLSID_RegistrationHelper{};
hr = ::CLSIDFromProgID(OLESTR("System.EnterpriseServices.RegistrationHelper"), &CLSID_RegistrationHelper);
ExitOnFailure(hr, "Failed to identify CLSID for 'System.EnterpriseServices.RegistrationHelper'");

// NOTE: The 'CoreBindToRuntimeEx' method is DEPRECATED in .NET v4.
// HOWEVER, we might be running in an earlier context at this point so we don't want to rely upon stuff that is particularly v4 dependent.
// Even if we are about to try to fire up a v4 runtime.
// The .NET v4 runtime with STARTUP_LOADER_SAFEMODE flag (to disable version checking of loaded assemblies) is what lets us launch the
// RegistrationHelper. The v4 RegistrationHelper is able to register both v4 and v3 assemblies however, so if we can get it, we most as well
// use it.
CorBindToRuntimeExFnPtr CorBindToRuntimeEx = (CorBindToRuntimeExFnPtr)::GetProcAddress(ghMscoree, "CorBindToRuntimeEx");
hr = CorBindToRuntimeEx(L"v4.0.30319", L"wks", STARTUP_LOADER_SAFEMODE, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost);
// we ignore the HRESULT here. If it worked, great, we'll use it moving forward. If it didn't work, we'll end up trying to resort to legacy .NET FW
// when we just try the COM Create below

// create registration helper object
// This will fail with Class not registered if only .NET Framework 4.5 is installed, it appears to require
// .NET 3 to get registered into the system correctly.
hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp);
// This will be created in the .NET FW 4 version if we managed to launch it above, or in the .NET FW <4 version based on the COM dispatch otherwise
hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp);
ExitOnFailure(hr, "Failed to create registration helper object");
}

Expand Down Expand Up @@ -884,7 +911,7 @@ static HRESULT RegisterDotNetAssembly(
}

// get registration helper object
hr = GetRegistrationHelper(&piRegHlp);
hr = GetRegistrationHelper(&piRegHlp, pAttrs->pwzDllPath);
ExitOnFailure(hr, "Failed to get registration helper object");

// get dispatch id of InstallAssembly() method
Expand Down Expand Up @@ -1090,7 +1117,7 @@ static HRESULT UnregisterDotNetAssembly(
ExitOnNull(bstrDllPath, hr, E_OUTOFMEMORY, "Failed to allocate BSTR for dll path");

// get registration helper object
hr = GetRegistrationHelper(&piRegHlp);
hr = GetRegistrationHelper(&piRegHlp, pAttrs->pwzDllPath);
ExitOnFailure(hr, "Failed to get registration helper object");

// get dispatch id of UninstallAssembly() method
Expand Down

0 comments on commit a3826e8

Please sign in to comment.