Exemple #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();
}
DWORD initialize_dotnet_host()
{
	HRESULT hr = S_OK;
	ICLRMetaHost* clrMetaHost = NULL;
	ICLRRuntimeInfo* clrRuntimeInfo = NULL;
	ICorRuntimeHost* clrCorRuntimeHost = NULL;
	IUnknownPtr clrAppDomain = NULL;
	_AppDomainPtr clrAppDomainInterface = NULL;
	_AssemblyPtr clrPowershellAssembly = NULL;
	_TypePtr clrPowershellType = NULL;
	SAFEARRAY* clrByteArray = NULL;
	HMODULE hMsCoree = NULL;

	do
	{
		dprintf("[PSH] Locating CLR instance ...");
		hMsCoree = LoadLibraryA("mscoree.dll");
		if (hMsCoree == NULL)
		{
			hr = (HRESULT)GetLastError();
			dprintf("[PSH] Failed to load mscoree, .NET probably isn't installed. 0x%x", hr);
			break;
		}

		pClrCreateInstance clrCreateInstance = (pClrCreateInstance)GetProcAddress(hMsCoree, "CLRCreateInstance");
		if (clrCreateInstance != NULL)
		{
			dprintf("[PSH] .NET 4 method in use");

			if (FAILED(hr = clrCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&clrMetaHost))))
			{
				dprintf("[PSH] Failed to create instace of the CLR metahost 0x%x", hr);
				break;
			}

			dprintf("[PSH] Getting a reference to the .NET runtime");
			if (FAILED(hr = clrMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&clrRuntimeInfo))))
			{
				dprintf("[PSH] Failed to get runtime v2.0.50727 instance 0x%x", hr);
				if (FAILED(hr = clrMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&clrRuntimeInfo))))
				{
					dprintf("[PSH] Failed to get runtime v4.0.30319 instance 0x%x", hr);
					break;
				}
			}

			dprintf("[PSH] Determining loadablility");
			BOOL loadable = FALSE;
			if (FAILED(hr = clrRuntimeInfo->IsLoadable(&loadable)))
			{
				dprintf("[PSH] Unable to determine of runtime is loadable 0x%x", hr);
				break;
			}

			if (!loadable)
			{
				dprintf("[PSH] Chosen runtime isn't loadable, exiting.");
				break;
			}

			dprintf("[PSH] Instantiating the COR runtime host");
			hr = clrRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&clrCorRuntimeHost));
			if (FAILED(hr))
			{
				dprintf("[PSH] Unable to get a reference to the COR runtime host 0x%x", hr);
				break;
			}
		}
		else
		{
			dprintf("[PSH] .NET 4 method is missing, attempting to locate .NEt 2 method");
			pCorBindToRuntime corBindToRuntime = (pCorBindToRuntime)GetProcAddress(hMsCoree, "CorBindToRuntime");
			if (corBindToRuntime == NULL)
			{
				dprintf("[PSH] Unable to find .NET clr instance loader");
				hr = E_NOTIMPL;
				break;
			}

			if (FAILED(hr = corBindToRuntime(L"v2.0.50727", L"wks", CLSID_CorRuntimeHost, IID_PPV_ARGS(&clrCorRuntimeHost))))
			{
				dprintf("[PSH] Unable to bind to .NET 2 runtime host: 0x%x", hr);
				break;
			}
		}

		dprintf("[PSH] Starting the COR runtime host");
		if (FAILED(hr = clrCorRuntimeHost->Start()))
		{
			dprintf("[PSH] Unable to start the COR runtime host 0x%x", hr);
			break;
		}

		dprintf("[PSH] Getting a ref to the app domain");
		if (FAILED(hr = clrCorRuntimeHost->GetDefaultDomain(&clrAppDomain)))
		{
			dprintf("[PSH] Unable to get the app domain 0x%x", hr);
			break;
		}

		dprintf("[PSH] Getting a ref to the app domain interface");
		if (FAILED(hr = clrAppDomain->QueryInterface(IID_PPV_ARGS(&clrAppDomainInterface))))
		{
			dprintf("[PSH] Unable to get the app domain interface 0x%x", hr);
			break;
		}

		dprintf("[PSH] CLR app domain ready to run, now loading the powershell runner");
		SAFEARRAYBOUND bounds[1];
		bounds[0].cElements = PSHRUNNER_DLL_LEN;
		bounds[0].lLbound = 0;

		clrByteArray = SafeArrayCreate(VT_UI1, 1, bounds);
		if (clrByteArray == NULL)
		{
			dprintf("[PSH] Failed to create a usable safe array");
			hr = ERROR_OUTOFMEMORY;
			break;
		}

		if (FAILED(hr = SafeArrayLock(clrByteArray)))
		{
			dprintf("[PSH] Safe array lock failed 0x%x", hr);
			break;
		}
		memcpy(clrByteArray->pvData, PowerShellRunnerDll, PSHRUNNER_DLL_LEN);
		SafeArrayUnlock(clrByteArray);

		if (FAILED(hr = clrAppDomainInterface->Load_3(clrByteArray, &clrPowershellAssembly)))
		{
			dprintf("[PSH] Failed to load the powershell runner assembly 0x%x", hr);
			break;
		}

		dprintf("[PSH] Loading the type from memory");
		_bstr_t pshClassName("MSF.Powershell.Runner");
		if (FAILED(hr = clrPowershellAssembly->GetType_2(pshClassName, &clrPowershellType)))
		{
			dprintf("[PSH] Unable to locate the powershell class type 0x%x", hr);
			break;
		}

		dprintf("[PSH] Runtime has been initialized successfully");

	} while(0);

	if (clrByteArray != NULL)
	{
		SafeArrayDestroy(clrByteArray);
	}

	if (FAILED(hr))
	{
		SAFE_RELEASE(clrPowershellAssembly);
		SAFE_RELEASE(clrAppDomainInterface);
		SAFE_RELEASE(clrCorRuntimeHost);
		SAFE_RELEASE(clrRuntimeInfo);
		SAFE_RELEASE(clrMetaHost);
		return (DWORD)hr;
	}

	gClrMetaHost = clrMetaHost;
	gClrRuntimeInfo = clrRuntimeInfo;
	gClrCorRuntimeHost = clrCorRuntimeHost;
	gClrAppDomainInterface = clrAppDomainInterface;
	gClrAppDomain = clrAppDomain;
	gClrPowershellAssembly = clrPowershellAssembly;
	gClrPowershellType = clrPowershellType;
	return ERROR_SUCCESS;
}
Exemple #3
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;
}
Exemple #4
0
// Gets the custom AppDomain for loading managed BA.
static HRESULT GetAppDomain(
    __out _AppDomain **ppAppDomain
    )
{
    HRESULT hr = S_OK;
    ICorRuntimeHost *pCLRHost = NULL;
    IUnknown *pUnk = NULL;
    LPWSTR sczAppBase = NULL;
    LPWSTR sczConfigPath = NULL;
    IAppDomainSetup *pAppDomainSetup;
    BSTR bstrAppBase = NULL;
    BSTR bstrConfigPath = NULL;

    hr = GetAppBase(&sczAppBase);
    ExitOnFailure(hr, "Failed to get the host base path.");

    hr = PathConcat(sczAppBase, L"BootstrapperCore.config", &sczConfigPath);
    ExitOnFailure(hr, "Failed to get the full path to the application configuration file.");

    // Check that the supported framework is installed.
    hr = CheckSupportedFrameworks(sczConfigPath);
    ExitOnFailure(hr, "Failed to find supported framework.");

    // Load the CLR.
    hr = GetCLRHost(sczConfigPath, &pCLRHost);
    ExitOnFailure(hr, "Failed to create the CLR host.");

    hr = pCLRHost->Start();
    ExitOnRootFailure(hr, "Failed to start the CLR host.");

    // Create the setup information for a new AppDomain to set the app base and config.
    hr = pCLRHost->CreateDomainSetup(&pUnk);
    ExitOnRootFailure(hr, "Failed to create the AppDomainSetup object.");

    hr = pUnk->QueryInterface(__uuidof(IAppDomainSetup), reinterpret_cast<LPVOID*>(&pAppDomainSetup));
    ExitOnRootFailure(hr, "Failed to query for the IAppDomainSetup interface.");
    ReleaseNullObject(pUnk);

    // Set properties on the AppDomainSetup object.
    bstrAppBase = ::SysAllocString(sczAppBase);
    ExitOnNull(bstrAppBase, hr, E_OUTOFMEMORY, "Failed to allocate the application base path for the AppDomainSetup.");

    hr = pAppDomainSetup->put_ApplicationBase(bstrAppBase);
    ExitOnRootFailure(hr, "Failed to set the application base path for the AppDomainSetup.");

    bstrConfigPath = ::SysAllocString(sczConfigPath);
    ExitOnNull(bstrConfigPath, hr, E_OUTOFMEMORY, "Failed to allocate the application configuration file for the AppDomainSetup.");

    hr = pAppDomainSetup->put_ConfigurationFile(bstrConfigPath);
    ExitOnRootFailure(hr, "Failed to set the configuration file path for the AppDomainSetup.");

    // Create the AppDomain to load the factory type.
    hr = pCLRHost->CreateDomainEx(L"MBA", pAppDomainSetup, NULL, &pUnk);
    ExitOnRootFailure(hr, "Failed to create the MBA AppDomain.");

    hr = pUnk->QueryInterface(__uuidof(_AppDomain), reinterpret_cast<LPVOID*>(ppAppDomain));
    ExitOnRootFailure(hr, "Failed to query for the _AppDomain interface.");

LExit:
    ReleaseBSTR(bstrConfigPath);
    ReleaseBSTR(bstrAppBase);
    ReleaseStr(sczConfigPath);
    ReleaseStr(sczAppBase);
    ReleaseNullObject(pUnk);
    ReleaseNullObject(pCLRHost);

    return hr;
}
Exemple #5
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;
}
Exemple #6
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
}
Exemple #7
0
int __stdcall invokeCLR( WCHAR* wszApplication){

    //Initializes the COM library

    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

    ICorRuntimeHost* pHost           = NULL;
    IUnknown*        pAppDomainThunk = NULL;
    _AppDomain*      pAppDomain      = NULL;
    long             lReturn         = 0;

    // Load CLR into the process

    HRESULT hr = CorBindToRuntimeEx(NULL,NULL,0,CLSID_CorRuntimeHost,IID_ICorRuntimeHost,(VOID**)&pHost);

    if(!FAILED(hr)) {

        // Start the CLR

        hr = pHost->Start();
        if(!FAILED(hr)) {

            // Get the _AppDomain interface

            hr = pHost->GetDefaultDomain(&pAppDomainThunk);
            if(!FAILED(hr)) {

                hr = pAppDomainThunk->QueryInterface(__uuidof(_AppDomain), (void**)&pAppDomain);
                if(!FAILED(hr)) {

                    // Execute assembly

                    hr = pAppDomain->ExecuteAssembly_2(_bstr_t(wszApplication), &lReturn);
                    if (FAILED(hr)) {

                        printf("_AppDomain::ExecuteAssembly_2 failed with hr=0x%x.\n", hr);
                        lReturn = -1;
                    }

                }else{
                    printf("Can't get System::_AppDomain interface\n");
                    lReturn = -2;
                }

            }else{
                printf("ICorRuntimeHost->GetDefaultDomain failed with hr=0x%x.\n", hr);
                lReturn = -3;
            }
        }else{
            printf("ICorRuntimeHost->Start failed with hr=0x%x.\n", hr);
            lReturn = -4;
        }

    }else{
        printf("CorBindToRuntimeHost failed with hr=0x%x.\n", hr);
        lReturn = -5;
    }

    // print the error message description if needed

    if(FAILED(hr)){
        LPVOID lpMsgBuf = NULL;

        FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                hr,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR) &lpMsgBuf,
                0,
                NULL );
        if(lpMsgBuf != NULL)
            printf("Message:%s\n",lpMsgBuf);
        else
            printf("No translation of 0x%x\n",hr);
    }

    // close COM library

    CoUninitialize();

    return lReturn;
}
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;
}