HRESULT LoadLoaderIntoAppDomain(_AppDomainPtr& pAppDomain, _AssemblyPtr& pLoaderAssembly, bool forceFromBytes) { HRESULT hr; if (!forceFromBytes) { // Try regular load first hr = pAppDomain->Load_2(_bstr_t(L"ExcelDna.Loader"), &pLoaderAssembly); } if (forceFromBytes || FAILED(hr) || pLoaderAssembly == NULL) { // Now try from resource bytes HRSRC hResInfoLoader = FindResource(hModuleCurrent, L"EXCELDNA.LOADER", L"ASSEMBLY"); if (hResInfoLoader == NULL) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_MISSINGEXCELDNALOADER, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } HGLOBAL hLoader = LoadResource(hModuleCurrent, hResInfoLoader); void* pLoader = LockResource(hLoader); ULONG sizeLoader = (ULONG)SizeofResource(hModuleCurrent, hResInfoLoader); SafeByteArray loaderBytes(pLoader, sizeLoader); hr = pAppDomain->Load_3(loaderBytes, &pLoaderAssembly); if (FAILED(hr)) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_EXCELDNALOADER, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } if (FAILED(hr)) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_EXCELDNALOADERNAME, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } } return S_OK; }
DWORD load_assembly(BYTE* assemblyData, DWORD assemblySize) { dprintf("[PSH] loading assembly of size %u", assemblySize); HRESULT hr = S_OK; SAFEARRAY* clrByteArray = NULL; SAFEARRAYBOUND bounds[1]; _AssemblyPtr* loadedAssembly = new _AssemblyPtr(); bounds[0].cElements = assemblySize; bounds[0].lLbound = 0; if (gClrAppDomainInterface == NULL) { dprintf("[PSH] Extension wasn't initialised"); return ERROR_INVALID_HANDLE; } do { clrByteArray = SafeArrayCreate(VT_UI1, 1, bounds); if (clrByteArray == NULL) { dprintf("[PSH] Failed to create a usable safe array"); hr = (HRESULT)ERROR_OUTOFMEMORY; break; } dprintf("[PSH] Safe array created"); if (FAILED(hr = SafeArrayLock(clrByteArray))) { dprintf("[PSH] Safe array lock failed 0x%x", hr); break; } dprintf("[PSH] Copying binary data to target"); memcpy(clrByteArray->pvData, assemblyData, assemblySize); SafeArrayUnlock(clrByteArray); if (FAILED(hr = gClrAppDomainInterface->Load_3(clrByteArray, (_Assembly**)loadedAssembly))) { dprintf("[PSH] Failed to load the assembly 0x%x", hr); break; } dprintf("[PSH] Assembly appears to have been loaded successfully"); list_add(gLoadedAssemblies, loadedAssembly); } while (0); if (SUCCEEDED(hr)) { return ERROR_SUCCESS; } else { delete loadedAssembly; } return (DWORD)hr; }
HRESULT LoadAppDomain(ICorRuntimeHostPtr pHost, std::wstring addInFullPath, bool createSandboxedAppDomain, bool shadowCopyFiles, _AssemblyPtr& pLoaderAssembly , _AppDomainPtr& pAppDomain, bool& unloadAppDomain) { HRESULT hr; std::wstring xllDirectory = addInFullPath; RemoveFileSpecFromPath(xllDirectory); unloadAppDomain = false; if (IsRunningOnCluster()) { // Need to load into default AppDomain due to configuration issues of the cluster host. IUnknown *pAppDomainUnk = NULL; hr = pHost->CurrentDomain(&pAppDomainUnk); if (FAILED(hr) || pAppDomainUnk == NULL) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_APPDOMAIN, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } // Assignment does QueryInterface pAppDomain = pAppDomainUnk; hr = LoadLoaderIntoAppDomain(pAppDomain, pLoaderAssembly, /*forceFromBytes=*/ true); if (FAILED(hr)) { // Already showed error message there. return E_FAIL; } // Since we loaded into the default domain, don't unload the AppDomain later. unloadAppDomain = false; return S_OK; } // End of RunningOnCluster path. // Create and populate AppDomainSetup IUnknownPtr pAppDomainSetupUnk; hr = pHost->CreateDomainSetup(&pAppDomainSetupUnk); if (FAILED(hr) || pAppDomainSetupUnk == NULL) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_APPDOMAINSETUP, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } IAppDomainSetupPtr pAppDomainSetup = pAppDomainSetupUnk; hr = pAppDomainSetup->put_ApplicationBase(_bstr_t(xllDirectory.c_str())); if (FAILED(hr)) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_APPLICATIONBASE, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } hr = pAppDomainSetup->put_ShadowCopyFiles(_bstr_t(shadowCopyFiles ? L"true" : L"false")); if (FAILED(hr)) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_SHADOWCOPYFILES, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } // AppDomainSetup.ApplicationName = "Excel-DNA: c:\MyAddins\MyAddIn.xll"; _bstr_t appDomainName((std::wstring(L"Excel-DNA: ") + addInFullPath).c_str()); pAppDomainSetup->put_ApplicationName(appDomainName); // Check if a .config file exists next to the .xll as MyAddIn.xll.config. Use it if it exists. std::wstring configFileName = addInFullPath + L".config"; if (FileExists(configFileName.c_str())) { pAppDomainSetup->put_ConfigurationFile(_bstr_t(configFileName.c_str())); } else { // Try to load .config file from resources, store into a temp file HRSRC hResConfig = FindResource(hModuleCurrent, L"__MAIN__", L"CONFIG"); if (hResConfig != NULL) { HGLOBAL hConfig = LoadResource(hModuleCurrent, hResConfig); void* pConfig = LockResource(hConfig); DWORD sizeConfig = SizeofResource(hModuleCurrent, hResConfig); std::wstring tempConfigFileName; hr = CreateTempFile(pConfig, sizeConfig, tempConfigFileName); if (SUCCEEDED(hr)) { pAppDomainSetup->put_ConfigurationFile(_bstr_t(tempConfigFileName.c_str())); } // tempConfigFile will be deleted after the AppDomain has been unloaded. } else { // No config file - no problem. } } IUnknown *pAppDomainUnk = NULL; hr = pHost->CreateDomainEx(appDomainName, pAppDomainSetupUnk, 0, &pAppDomainUnk); if (FAILED(hr) || pAppDomainUnk == NULL) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_APPDOMAIN, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } pAppDomain = pAppDomainUnk; hr = LoadLoaderIntoAppDomain(pAppDomain, pLoaderAssembly, /*forceLoadFromBytes=*/ false); if (FAILED(hr)) { // Already showed message. return E_FAIL; } if (createSandboxedAppDomain) { _TypePtr pAppDomainHelperType; hr = pLoaderAssembly->GetType_2(_bstr_t(L"ExcelDna.Loader.AppDomainHelper"), &pAppDomainHelperType); if (FAILED(hr) || pAppDomainHelperType == NULL) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_XLADDIN, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } _variant_t sbRetVal; _variant_t sbTarget; hr = pAppDomainHelperType->InvokeMember_3(_bstr_t("CreateFullTrustSandbox"), (BindingFlags)(BindingFlags_Static | BindingFlags_Public | BindingFlags_InvokeMethod), NULL, sbTarget, NULL, &sbRetVal); if (FAILED(hr)) { ShowMessage(IDS_MSG_HEADER_APPDOMAIN, IDS_MSG_BODY_XLADDININIT, IDS_MSG_FOOTER_UNEXPECTED, hr); return E_FAIL; } _AppDomainPtr pSandbox(sbRetVal.punkVal); if (!IsEqualObject(pAppDomain, pSandbox)) { // Unload the loader AppDomain. pLoaderAssembly.Release(); pHost->UnloadDomain(pAppDomain); pAppDomain.Release(); pAppDomain = pSandbox; // Sort out the LoaderAssembly in the sandbox. hr = LoadLoaderIntoAppDomain(pAppDomain, pLoaderAssembly, /*forceLoadFromBytes=*/ false); if (FAILED(hr)) { // Already showed message. return E_FAIL; } } } unloadAppDomain = true; return S_OK; }