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