Пример #1
0
static void InitializeClr(void)
{
	ICorRuntimeHost *runtimeHost;

	if (FAILED(CorBindToRuntimeEx(NULL, NULL,
	    STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_CONCURRENT_GC,
	    CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void **)&runtimeHost))) {
		return;
	}

	runtimeHost->Start();

	IUnknownPtr punkAppDomain = NULL;
	runtimeHost->GetDefaultDomain(&punkAppDomain);

	punkAppDomain->QueryInterface(__uuidof(mscorlib::_AppDomain), (void **)&l_AppDomain);

	runtimeHost->Release();
}
Пример #2
0
/// <summary>
/// Invokes a managed custom action from native code by
/// extracting the package to a temporary working directory
/// then hosting the CLR and locating and calling the entrypoint.
/// </summary>
/// <param name="hSession">Handle to the installation session.
/// Passed to custom action entrypoints by the installer engine.</param>
/// <param name="szWorkingDir">Directory containing the CA binaries
/// and the CustomAction.config file defining the entrypoints.
/// This may be NULL, in which case the current module must have
/// a concatenated cabinet containing those files, which will be
/// extracted to a temporary directory.</param>
/// <param name="szEntryPoint">Name of the CA entrypoint to be invoked.
/// This must be either an explicit &quot;AssemblyName!Namespace.Class.Method&quot;
/// string, or a simple name that maps to a full entrypoint definition
/// in CustomAction.config.</param>
/// <returns>The value returned by the managed custom action method,
/// or ERROR_INSTALL_FAILURE if the CA could not be invoked.</returns>
int InvokeCustomAction(MSIHANDLE hSession,
        const wchar_t* szWorkingDir, const wchar_t* szEntryPoint)
{
#ifdef MANAGED_CAs_OUT_OF_PROC
        if (!g_fRunningOutOfProc && szWorkingDir == NULL)
        {
                return InvokeOutOfProcManagedCustomAction(hSession, szEntryPoint);
        }
#endif

        wchar_t szTempDir[MAX_PATH];
        bool fDeleteTemp = false;
        if (szWorkingDir == NULL)
        {
                if (!ExtractToTempDirectory(hSession, g_hModule, szTempDir, MAX_PATH))
                {
                        return ERROR_INSTALL_FAILURE;
                }
                szWorkingDir = szTempDir;
                fDeleteTemp = true;
        }

        wchar_t szConfigFilePath[MAX_PATH + 20];
        StringCchCopy(szConfigFilePath, MAX_PATH + 20, szWorkingDir);
        StringCchCat(szConfigFilePath, MAX_PATH + 20, L"\\CustomAction.config");

        const wchar_t* szConfigFile = szConfigFilePath;
        if (!::PathFileExists(szConfigFilePath))
        {
                szConfigFile = NULL;
        }

        wchar_t szWIAssembly[MAX_PATH + 50];
        StringCchCopy(szWIAssembly, MAX_PATH + 50, szWorkingDir);
        StringCchCat(szWIAssembly, MAX_PATH + 50, L"\\Microsoft.Deployment.WindowsInstaller.dll");

        int iResult = ERROR_INSTALL_FAILURE;
        ICorRuntimeHost* pHost;
        if (LoadCLR(hSession, NULL, szConfigFile, szWIAssembly, &pHost))
        {
                _AppDomain* pAppDomain;
                if (CreateAppDomain(hSession, pHost, L"CustomAction", szWorkingDir,
                        szConfigFile, &pAppDomain))
                {
                        if (!InvokeManagedCustomAction(hSession, pAppDomain, szEntryPoint, &iResult))
                        {
                                iResult = ERROR_INSTALL_FAILURE;
                        }
                        HRESULT hr = pHost->UnloadDomain(pAppDomain);
                        if (FAILED(hr))
                        {
                                Log(hSession, L"Failed to unload app domain. Error code 0x%X", hr);
                        }
                        pAppDomain->Release();
                }

                pHost->Stop();
                pHost->Release();
        }

        if (fDeleteTemp)
        {
                DeleteDirectory(szTempDir);
        }
        return iResult;
}
Пример #3
0
/// <summary>
/// Binds to the CLR after determining the appropriate version.
/// </summary>
/// <param name="hSession">Handle to the installer session,
/// used just for logging.</param>
/// <param name="version">Specific version of the CLR to load.
/// If null, then the config file and/or primary assembly are
/// used to determine the version.</param>
/// <param name="szConfigFile">XML .config file which may contain
/// a startup section to direct which version of the CLR to use.
/// May be NULL.</param>
/// <param name="szPrimaryAssembly">Assembly to be used to determine
/// the version of the CLR in the absence of other configuration.
/// May be NULL.</param>
/// <param name="ppHost">Returned runtime host interface.</param>
/// <returns>True if the CLR was loaded successfully, false if
/// there was some error.</returns>
/// <remarks>
/// If szPrimaryAssembly is NULL and szConfigFile is also NULL or
/// does not contain any version configuration, the CLR will not be loaded.
/// </remarks>
bool LoadCLR(MSIHANDLE hSession, const wchar_t* szVersion, const wchar_t* szConfigFile,
	const wchar_t* szPrimaryAssembly, ICorRuntimeHost** ppHost)
{
	typedef HRESULT (__stdcall *PGetRequestedRuntimeInfo)(LPCWSTR pExe, LPCWSTR pwszVersion,
		LPCWSTR pConfigurationFile, DWORD startupFlags, DWORD runtimeInfoFlags,
		LPWSTR pDirectory, DWORD dwDirectory, DWORD *dwDirectoryLength,
		LPWSTR pVersion, DWORD cchBuffer, DWORD* dwlength);
	typedef HRESULT (__stdcall *PCorBindToRuntimeEx)(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor,
		DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);

	HMODULE hmodMscoree = LoadLibrary(L"mscoree.dll");
	if (hmodMscoree == NULL)
	{
		Log(hSession, L"Failed to load mscoree.dll (Error code %d). This custom action "
			L"requires the .NET Framework to be installed.", GetLastError());
		return false;
	}
	PGetRequestedRuntimeInfo pGetRequestedRuntimeInfo = (PGetRequestedRuntimeInfo)
		GetProcAddress(hmodMscoree, "GetRequestedRuntimeInfo");
	PCorBindToRuntimeEx pCorBindToRuntimeEx = (PCorBindToRuntimeEx)
		GetProcAddress(hmodMscoree, "CorBindToRuntimeEx");
	if (pGetRequestedRuntimeInfo == NULL || pCorBindToRuntimeEx == NULL)
	{
		Log(hSession, L"Failed to locate functions in mscoree.dll (Error code %d). This custom action "
			L"requires the .NET Framework to be installed.", GetLastError());
		FreeLibrary(hmodMscoree);
		return false;
	}

	wchar_t szClrVersion[20];
	HRESULT hr;

	if (szVersion != NULL && szVersion[0] != L'\0')
	{
		wcsncpy_s(szClrVersion, 20, szVersion, 20);
	}
	else
	{
		wchar_t szVersionDir[MAX_PATH];
		hr = pGetRequestedRuntimeInfo(szPrimaryAssembly, NULL,
			szConfigFile, 0, 0, szVersionDir, MAX_PATH, NULL, szClrVersion, 20, NULL);
		if (FAILED(hr))
		{
			Log(hSession, L"Failed to get requested CLR info. Error code 0x%x", hr);
			Log(hSession, L"Ensure that the proper version of the .NET Framework is installed, or "
				L"that there is a matching supportedRuntime element in CustomAction.config. "
				L"If you are binding to .NET 4 or greater add "
				L"useLegacyV2RuntimeActivationPolicy=true to the <startup> element.");
			FreeLibrary(hmodMscoree);
			return false;
		}
	}

	Log(hSession, L"Binding to CLR version %s", szClrVersion);

	ICorRuntimeHost* pHost;
	hr = pCorBindToRuntimeEx(szClrVersion, NULL,
		STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN,
		CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void**) &pHost);
	if (FAILED(hr))
	{
		Log(hSession, L"Failed to bind to the CLR. Error code 0x%X", hr);
		FreeLibrary(hmodMscoree);
		return false;
	}
	hr = pHost->Start();
	if (FAILED(hr))
	{
		Log(hSession, L"Failed to start the CLR. Error code 0x%X", hr);
		pHost->Release();
		FreeLibrary(hmodMscoree);
		return false;
	}
	*ppHost = pHost;
	FreeLibrary(hmodMscoree);
	return true;
}
Пример #4
0
unsigned __stdcall ThreadProc(void *pArg)
{
    RuntimeAndApp *pContext = (RuntimeAndApp *)pArg;

    HRESULT hr;

#define IfFailGoMsg(MSG)                                                        \
    if (FAILED(hr))                                                             \
    {                                                                           \
        printf("Runtime %d (%S): " MSG " (%x)\n",                               \
            pContext->m_dwRuntimeNo,                                            \
            pContext->m_pwzRuntimeVer,                                          \
            hr);                                                                \
        goto lExit;                                                             \
    }

    ICLRRuntimeHost  *pHost_V2 = NULL;
    ICorRuntimeHost     *pHost = NULL;
    IUnknown             *pUnk = NULL;
    mscorlib::_AppDomain  *pAD = NULL;

    // Get ICorRuntimeHost to execute the app.
    hr = pContext->m_pRuntime->GetInterface(
        CLSID_CorRuntimeHost,
        IID_ICorRuntimeHost,
        (LPVOID *)&pHost);
    IfFailGoMsg("Failed to load the runtime");

	// Also try to get ICLRRuntimeHost which has a useful Stop method. (ICorRuntimeHost::Stop is empty.)
    if (SUCCEEDED(pContext->m_pRuntime->GetInterface(
        CLSID_CLRRuntimeHost,
        IID_ICLRRuntimeHost,
        (LPVOID *)&pHost_V2)))
    {
        hr = pHost_V2->Start();
        IfFailGoMsg("Failed to start ICLRRuntimeHost");
    }

    ReportSyncPoint(SyncPointRuntimeStart, pContext->m_dwRuntimeNo);
    hr = pHost->Start();
    IfFailGoMsg("Failed to start ICorRuntimeHost");

    if(g_options.m_bUseDefaultAppDomain)
    {
        hr = pHost->GetDefaultDomain(&pUnk);
        IfFailGoMsg("Failed to get default domain");
    }
    else
    {
        hr = pHost->CreateDomain(L"AD2",NULL,&pUnk);
        IfFailGoMsg("Failed to create AppDomain");
    }

    hr = pUnk->QueryInterface(__uuidof(mscorlib::_AppDomain), (LPVOID *)&pAD);
    IfFailGoMsg("Failed to QI for _AppDomain");

    BSTR bstrPath = SysAllocString(pContext->m_pwzAppPath);
    SAFEARRAY *rgArgs = CreateArgList(pContext->m_pwzAppArgs);

    ReportSyncPoint(SyncPointApplicationStart, pContext->m_dwRuntimeNo);

    if (g_options.m_bUseLoadByName)
    {
        hr = ExecuteAssemblyByName(pAD, bstrPath, rgArgs, &pContext->m_dwRetCode);
    }
    else
    {
        hr = pAD->ExecuteAssembly_3(bstrPath, NULL, rgArgs, &pContext->m_dwRetCode);
    }

    if (hr == COR_E_NEWER_RUNTIME)
    {
        IfFailGoMsg("Failed to execute assembly\nWas it built by a compiler that is newer than this runtime?");
    }
    else
    {
        // we don't know whether the error comes from the runtime (failed to execute assembly) or
        // the assembly actually ran and threw an unhandled exception that was converted to the HR
        IfFailGoMsg("ExecuteAssembly returned an error code");
    }

    SysFreeString(bstrPath);
    SafeArrayDestroy(rgArgs);


    if(!g_options.m_bUseDefaultAppDomain)
    {	
        ReportSyncPoint(SyncPointAppDomainUnload, pContext->m_dwRuntimeNo);
        hr = pHost->UnloadDomain(pAD);
        IfFailGoMsg("Failed to unload AppDomain");
    }
    pAD->Release();  pAD = NULL;
    pUnk->Release(); pUnk = NULL;

    hr = pHost->Stop();
    IfFailGoMsg("Failed to stop ICorRuntimeHost");

    if (pHost_V2 != NULL)
    {
        hr = pHost_V2->Stop();
        IfFailGoMsg("Failed to stop ICLRRuntimeHost");

        pHost_V2 = NULL;
    }

lExit:
    if (pHost_V2 != NULL)
        pHost_V2->Release();

    if (pAD != NULL)
        pAD->Release();

    if (pUnk != NULL)
        pUnk->Release();

    if (pHost != NULL)
        pHost->Release();

    if (g_options.m_bRunMultithreaded)
    {
        // make sure we don't deadlock the other thread
        // this is also needed if the value of g_options.m_dwADUnloadOrder is SameOrder or ReverseOrder
        // since one of the threads will be waiting for the other one to Unload the AppDomain.
        SetEvent(g_rhndEvents[pContext->m_dwRuntimeNo - 1]);

        _endthreadex(0);
    }
    return 0;

#undef IfFailGoMsg
}
int _tmain(int argc, _TCHAR* argv[])
{
	HRESULT hr;

	ICLRMetaHost *pMetaHost = NULL;
	ICLRRuntimeInfo *pRuntimeInfo = NULL;
	ICorRuntimeHost *pCorRuntimeHost = NULL;

	IUnknownPtr spAppDomainThunk = NULL;
	_AppDomainPtr spDefaultAppDomain = NULL;

	// The .NET assembly to load.
	bstr_t bstrAssemblyName("PowerShellRunner");
	_AssemblyPtr spAssembly = NULL;

	// The .NET class to instantiate.
	bstr_t bstrClassName("PowerShellRunner.PowerShellRunner");
	_TypePtr spType = NULL;


	// Start the runtime
	hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
	if (FAILED(hr))
	{
		wprintf(L"CLRCreateInstance failed w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	hr = pMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&pRuntimeInfo));
	if (FAILED(hr))
	{
		wprintf(L"ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	// Check if the specified runtime can be loaded into the process.
	BOOL fLoadable;
	hr = pRuntimeInfo->IsLoadable(&fLoadable);
	if (FAILED(hr))
	{
		wprintf(L"ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	if (!fLoadable)
	{
		wprintf(L".NET runtime v2.0.50727 cannot be loaded\n");
		goto Cleanup;
	}

	// Load the CLR into the current process and return a runtime interface
	hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost,
		IID_PPV_ARGS(&pCorRuntimeHost));
	if (FAILED(hr))
	{
		wprintf(L"ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	// Start the CLR.
	hr = pCorRuntimeHost->Start();
	if (FAILED(hr))
	{
		wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}


	// Get a pointer to the default AppDomain in the CLR.
	hr = pCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
	if (FAILED(hr))
	{
		wprintf(L"ICorRuntimeHost::GetDefaultDomain failed w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefaultAppDomain));
	if (FAILED(hr))
	{
		wprintf(L"Failed to get default AppDomain w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	// Load the .NET assembly.
	// (Option 1) Load it from disk - usefully when debugging the PowerShellRunner app (you'll have to copy the DLL into the same directory as the exe)
	//hr = spDefaultAppDomain->Load_2(bstrAssemblyName, &spAssembly);
	
	// (Option 2) Load the assembly from memory
	SAFEARRAYBOUND bounds[1];
	bounds[0].cElements = PowerShellRunner_dll_len;
	bounds[0].lLbound = 0;

	SAFEARRAY* arr = SafeArrayCreate(VT_UI1, 1, bounds);
	SafeArrayLock(arr);
	memcpy(arr->pvData, PowerShellRunner_dll, PowerShellRunner_dll_len);
	SafeArrayUnlock(arr);

	hr = spDefaultAppDomain->Load_3(arr, &spAssembly);

	if (FAILED(hr))
	{
		wprintf(L"Failed to load the assembly w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	// Get the Type of PowerShellRunner.
	hr = spAssembly->GetType_2(bstrClassName, &spType);
	if (FAILED(hr))
	{
		wprintf(L"Failed to get the Type interface w/hr 0x%08lx\n", hr);
		goto Cleanup;
	}

	// Call the static method of the class
	wchar_t* argument = L"Get-Process\n\
						 #This is a PowerShell Comment\n\
						 Write-Host \"`n`n*******  The next command is going to throw an exception.  This is planned *********`n`n\"\n\
						 Read-Host\n";
	
	InvokeMethod(spType, L"InvokePS", argument);

Cleanup:

	if (pMetaHost)
	{
		pMetaHost->Release();
		pMetaHost = NULL;
	}
	if (pRuntimeInfo)
	{
		pRuntimeInfo->Release();
		pRuntimeInfo = NULL;
	}
	if (pCorRuntimeHost)
	{
		pCorRuntimeHost->Release();
		pCorRuntimeHost = NULL;
	}

	return 0;
}