Skip to content

Commit 2d66800

Browse files
committed
Well... this fixes the failure to register under pure .NET FW 4+
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 <bevan.weiss@gmail.com>
1 parent d361c56 commit 2d66800

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

src/ext/ComPlus/ca/cpasmexec.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ IAssemblyCache : public IUnknown
6161

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

6567

6668
// RegistrationHelper related declarations
@@ -152,7 +154,8 @@ static HRESULT UnregisterAssembly(
152154
static void InitAssemblyExec();
153155
static void UninitAssemblyExec();
154156
static HRESULT GetRegistrationHelper(
155-
IDispatch** ppiRegHlp
157+
IDispatch** ppiRegHlp,
158+
LPCWSTR pwzAssemblyPath
156159
);
157160
static HRESULT GetAssemblyCacheObject(
158161
IAssemblyCache** ppAssemblyCache
@@ -718,20 +721,44 @@ static void UninitAssemblyExec()
718721
}
719722

720723
static HRESULT GetRegistrationHelper(
721-
IDispatch** ppiRegHlp
724+
IDispatch** ppiRegHlp,
725+
LPCWSTR pwzAssemblyPath
722726
)
723727
{
724728
HRESULT hr = S_OK;
729+
wchar_t pwzVersion[MAX_PATH];
730+
DWORD pcchVersionLen = MAX_PATH;
731+
ICLRRuntimeHost* runtimeHost = NULL;
732+
733+
if (!ghMscoree)
734+
{
735+
ghMscoree = ::LoadLibraryW(L"mscoree.dll");
736+
ExitOnNull(ghMscoree, hr, E_FAIL, "Failed to load mscoree.dll");
737+
}
738+
GetFileVersionFnPtr GetFileVersion = (GetFileVersionFnPtr)::GetProcAddress(ghMscoree, "GetFileVersion");
739+
ExitOnNull(GetFileVersion, hr, E_FAIL, "Failed to GetProcAddress for 'GetFileVersion' from 'mscoree.dll'");
740+
hr = GetFileVersion(pwzAssemblyPath, pwzVersion, pcchVersionLen, &pcchVersionLen);
725741

726742
if (!gpiRegHlp)
727743
{
728744
CLSID CLSID_RegistrationHelper{};
729745
hr = ::CLSIDFromProgID(OLESTR("System.EnterpriseServices.RegistrationHelper"), &CLSID_RegistrationHelper);
730746
ExitOnFailure(hr, "Failed to identify CLSID for 'System.EnterpriseServices.RegistrationHelper'");
747+
748+
// NOTE: The 'CoreBindToRuntimeEx' method is DEPRECATED in .NET v4.
749+
// 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.
750+
// Even if we are about to try to fire up a v4 runtime.
751+
// The .NET v4 runtime with STARTUP_LOADER_SAFEMODE flag (to disable version checking of loaded assemblies) is what lets us launch the
752+
// RegistrationHelper. The v4 RegistrationHelper is able to register both v4 and v3 assemblies however, so if we can get it, we most as well
753+
// use it.
754+
CorBindToRuntimeExFnPtr CorBindToRuntimeEx = (CorBindToRuntimeExFnPtr)::GetProcAddress(ghMscoree, "CorBindToRuntimeEx");
755+
hr = CorBindToRuntimeEx(L"v4.0.30319", L"wks", STARTUP_LOADER_SAFEMODE, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost);
756+
// 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
757+
// when we just try the COM Create below
758+
731759
// create registration helper object
732-
// This will fail with Class not registered if only .NET Framework 4.5 is installed, it appears to require
733-
// .NET 3 to get registered into the system correctly.
734-
hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp);
760+
// 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
761+
hr = ::CoCreateInstance(CLSID_RegistrationHelper, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&gpiRegHlp);
735762
ExitOnFailure(hr, "Failed to create registration helper object");
736763
}
737764

@@ -884,7 +911,7 @@ static HRESULT RegisterDotNetAssembly(
884911
}
885912

886913
// get registration helper object
887-
hr = GetRegistrationHelper(&piRegHlp);
914+
hr = GetRegistrationHelper(&piRegHlp, pAttrs->pwzDllPath);
888915
ExitOnFailure(hr, "Failed to get registration helper object");
889916

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

10921119
// get registration helper object
1093-
hr = GetRegistrationHelper(&piRegHlp);
1120+
hr = GetRegistrationHelper(&piRegHlp, pAttrs->pwzDllPath);
10941121
ExitOnFailure(hr, "Failed to get registration helper object");
10951122

10961123
// get dispatch id of UninstallAssembly() method

0 commit comments

Comments
 (0)