Example #1
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;
}
Example #2
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
}