PageRenderTime 58ms CodeModel.GetById 36ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Visual Studio 2008/CppOfficeManagedCOMAddInShim/CLRLoader.cpp

#
C++ | 204 lines | 139 code | 29 blank | 36 comment | 17 complexity | 85828ca161f185d3d0c95fa2943d6224 MD5 | raw file
  1#include "StdAfx.h"
  2#include "clrloader.h"
  3
  4using namespace mscorlib;
  5
  6CCLRLoader::CCLRLoader(void) 
  7    : m_pCorRuntimeHost(NULL), m_pAppDomain(NULL)
  8{
  9}
 10
 11// CreateInstance: loads the CLR, creates an AppDomain, and creates an 
 12// aggregated instance of the target managed add-in in that AppDomain.
 13HRESULT CCLRLoader::CreateAggregatedAddIn(
 14    IUnknown* pOuter,
 15    LPCWSTR szAssemblyName, 
 16    LPCWSTR szClassName, 
 17    LPCWSTR szAssemblyConfigName)
 18{
 19    HRESULT hr = E_FAIL;
 20
 21    CComPtr<_ObjectHandle>                              srpObjectHandle;
 22    CComPtr<ManagedHelpers::IManagedAggregator >        srpManagedAggregator;
 23    CComPtr<IComAggregator>                             srpComAggregator;
 24    CComVariant                                         cvarManagedAggregator;
 25 
 26    // Load the CLR, and create an AppDomain for the target assembly.
 27    IfFailGo( LoadCLR() );
 28    IfFailGo( CreateAppDomain(szAssemblyConfigName) );
 29
 30    // Create the managed aggregator in the target AppDomain, and unwrap it.
 31	// This component needs to be in a location where fusion will find it, ie
 32	// either in the GAC or in the same folder as the shim and the add-in.
 33    IfFailGo( m_pAppDomain->CreateInstance(
 34        CComBSTR(L"ManagedAggregator, PublicKeyToken=d51fbf4dbc2f7f14"),
 35        CComBSTR(L"ManagedHelpers.ManagedAggregator"),
 36        &srpObjectHandle) );
 37    IfFailGo( srpObjectHandle->Unwrap(&cvarManagedAggregator) );
 38    IfFailGo( cvarManagedAggregator.pdispVal->QueryInterface(
 39        &srpManagedAggregator) );
 40
 41    // Instantiate and aggregate the inner managed add-in into the outer
 42    // (unmanaged, ConnectProxy) object.
 43    IfFailGo( pOuter->QueryInterface(
 44        __uuidof(IComAggregator), (LPVOID*)&srpComAggregator) );
 45    IfFailGo( srpManagedAggregator->CreateAggregatedInstance(
 46        CComBSTR(szAssemblyName), CComBSTR(szClassName), srpComAggregator) );
 47
 48Error:
 49    return hr;
 50}
 51
 52// LoadCLR: loads and starts the .NET CLR.
 53HRESULT CCLRLoader::LoadCLR()
 54{
 55    HRESULT hr = S_OK;
 56
 57    // Ensure the CLR is only loaded once.
 58    if (m_pCorRuntimeHost != NULL)
 59    {
 60        return hr;
 61    }
 62
 63    // Load the CLR into the process, using the default (latest) version, 
 64    // the default ("wks") flavor, and default (single) domain.
 65    hr = CorBindToRuntimeEx(
 66        0, 0, 0, 
 67        CLSID_CorRuntimeHost, IID_ICorRuntimeHost, 
 68		(LPVOID*)&m_pCorRuntimeHost);
 69
 70    // If CorBindToRuntimeEx returned a failure HRESULT, we failed to 
 71	// load the CLR.
 72    if (!SUCCEEDED(hr)) 
 73    {
 74        return hr;
 75    }
 76
 77    // Start the CLR.
 78    return m_pCorRuntimeHost->Start();
 79}
 80
 81// In order to securely load an assembly, its fully qualified strong name
 82// and not the filename must be used. To do that, the target AppDomain's 
 83// base directory needs to point to the directory where the assembly is.
 84HRESULT CCLRLoader::CreateAppDomain(LPCWSTR szAssemblyConfigName)
 85{
 86    USES_CONVERSION;
 87    HRESULT hr = S_OK;
 88
 89    // Ensure the AppDomain is created only once.
 90    if (m_pAppDomain != NULL)
 91    {
 92        return hr;
 93    }
 94
 95    CComPtr<IUnknown> pUnkDomainSetup;
 96    CComPtr<IAppDomainSetup> pDomainSetup;
 97    CComPtr<IUnknown> pUnkAppDomain;
 98    TCHAR szDirectory[MAX_PATH + 1];
 99    TCHAR szAssemblyConfigPath[MAX_PATH + 1];
100    CComBSTR cbstrAssemblyConfigPath;
101
102    // Create an AppDomainSetup with the base directory pointing to the
103    // location of the managed DLL. We assume that the target assembly
104    // is located in the same directory.
105    IfFailGo( m_pCorRuntimeHost->CreateDomainSetup(&pUnkDomainSetup) );
106    IfFailGo( pUnkDomainSetup->QueryInterface(
107        __uuidof(pDomainSetup), (LPVOID*)&pDomainSetup) );
108
109    // Get the location of the hosting shim DLL, and configure the 
110    // AppDomain to search for assemblies in this location.
111    IfFailGo( GetDllDirectory(
112        szDirectory, sizeof(szDirectory)/sizeof(szDirectory[0])) );
113    pDomainSetup->put_ApplicationBase(CComBSTR(szDirectory));
114
115    // Set the AppDomain to use a local DLL config if there is one.
116    IfFailGo( StringCchCopy(
117        szAssemblyConfigPath, 
118        sizeof(szAssemblyConfigPath)/sizeof(szAssemblyConfigPath[0]), 
119        szDirectory) );
120    if (!PathAppend(szAssemblyConfigPath, szAssemblyConfigName))
121    {
122        hr = E_UNEXPECTED;
123        goto Error;
124    }
125    IfFailGo( cbstrAssemblyConfigPath.Append(szAssemblyConfigPath) );
126    IfFailGo( pDomainSetup->put_ConfigurationFile(cbstrAssemblyConfigPath) );
127
128    // Create an AppDomain that will run the managed assembly, and get the
129    // AppDomain's _AppDomain pointer from its IUnknown pointer.
130    IfFailGo( m_pCorRuntimeHost->CreateDomainEx(T2W(szDirectory), 
131        pUnkDomainSetup, 0, &pUnkAppDomain) );
132    IfFailGo( pUnkAppDomain->QueryInterface(
133        __uuidof(m_pAppDomain), (LPVOID*)&m_pAppDomain) );
134
135Error:
136   return hr;
137}
138
139// GetDllDirectory: gets the directory location of the DLL containing this
140// code - that is, the shim DLL. The target add-in DLL will also be in this
141// directory.
142HRESULT CCLRLoader::GetDllDirectory(TCHAR *szPath, DWORD nPathBufferSize)
143{
144    // Get the shim DLL module instance, or bail.
145    HMODULE hInstance = _AtlBaseModule.GetModuleInstance();
146    if (hInstance == 0)
147    {
148        return E_FAIL;
149    }
150
151    // Get the shim DLL filename, or bail.
152    TCHAR szModule[MAX_PATH + 1];
153    DWORD dwFLen = ::GetModuleFileName(hInstance, szModule, MAX_PATH);
154    if (dwFLen == 0)
155    {
156        return E_FAIL;
157    }
158
159    // Get the full path to the shim DLL, or bail.
160    TCHAR *pszFileName;
161    dwFLen = ::GetFullPathName(
162        szModule, nPathBufferSize, szPath, &pszFileName);
163    if (dwFLen == 0 || dwFLen >= nPathBufferSize)
164    {
165        return E_FAIL;
166    }
167
168    *pszFileName = 0;
169    return S_OK;
170}
171
172// Unload the AppDomain. This will be called by the ConnectProxy
173// in OnDisconnection.
174HRESULT CCLRLoader::Unload(void)
175{
176    HRESULT hr = S_OK;
177    IUnknown* pUnkDomain = NULL;
178    IfFailGo(m_pAppDomain->QueryInterface(
179        __uuidof(IUnknown), (LPVOID*)&pUnkDomain));
180    hr = m_pCorRuntimeHost->UnloadDomain(pUnkDomain);
181
182    // Added in 2.0.2.0, only for Add-ins.
183    m_pAppDomain->Release();
184    m_pAppDomain = NULL;
185    
186Error:
187    if (pUnkDomain != NULL)
188    {
189        pUnkDomain->Release();
190    }
191    return hr;
192}
193
194CCLRLoader::~CCLRLoader(void)
195{
196    if (m_pAppDomain)
197    {
198        m_pAppDomain->Release();
199    }
200    if (m_pCorRuntimeHost)
201    {
202        m_pCorRuntimeHost->Release();
203    }
204}