Beispiel #1
0
inline HRESULT LoadCabinetDll()
{
    HRESULT hr = S_OK;
    if (!vhCabinetDll)
    {
        hr = LoadSystemLibrary(L"cabinet.dll", &vhCabinetDll);
        ExitOnFailure(hr, "failed to load cabinet.dll");

        // retrieve all address functions
        vpfnFDICreate = reinterpret_cast<PFNFDICREATE>(::GetProcAddress(vhCabinetDll, "FDICreate"));
        ExitOnNullWithLastError(vpfnFDICreate, hr, "failed to import FDICreate from CABINET.DLL");
        vpfnFDICopy = reinterpret_cast<PFNFDICOPY>(::GetProcAddress(vhCabinetDll, "FDICopy"));
        ExitOnNullWithLastError(vpfnFDICopy, hr, "failed to import FDICopy from CABINET.DLL");
        vpfnFDIIsCabinet = reinterpret_cast<PFNFDIISCABINET>(::GetProcAddress(vhCabinetDll, "FDIIsCabinet"));
        ExitOnNullWithLastError(vpfnFDIIsCabinet, hr, "failed to import FDIIsCabinetfrom CABINET.DLL");
        vpfnFDIDestroy = reinterpret_cast<PFNFDIDESTROY>(::GetProcAddress(vhCabinetDll, "FDIDestroy"));
        ExitOnNullWithLastError(vpfnFDIDestroy, hr, "failed to import FDIDestroyfrom CABINET.DLL");

        vhfdi = vpfnFDICreate(CabExtractAlloc, CabExtractFree, CabExtractOpen, CabExtractRead, CabExtractWrite, CabExtractClose, CabExtractSeek, cpuUNKNOWN, &verf);
        ExitOnNull(vhfdi, hr, E_FAIL, "failed to initialize cabinet.dll");
    }

LExit:
    if (FAILED(hr) && vhCabinetDll)
    {
        ::FreeLibrary(vhCabinetDll);
        vhCabinetDll = NULL;
    }

    return hr;
}
Beispiel #2
0
/********************************************************************
 SetVerboseLoggingAtom() - Sets one of two global Atoms to specify
                           if the install should do verbose logging.
                           Communicates the verbose setting to 
                           deferred CAs.
                           Set a negative case atom so that we can
                           distinguish between an unset atom and the
                           non-verbose case.  This helps prevent the
                           expensive regkey lookup for non-verbose.
********************************************************************/
HRESULT WIXAPI SetVerboseLoggingAtom(BOOL bValue)
{
    HRESULT hr = S_OK;
    ATOM atomVerbose = 0;

    atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging");
    if (0 == atomVerbose &&  bValue)
    {
        atomVerbose = ::GlobalAddAtomW(L"WcaVerboseLogging");
        ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaVerboseLogging global atom.");
    }
    else if (0 != atomVerbose && !bValue)
    {
        ::SetLastError(ERROR_SUCCESS);
        ::GlobalDeleteAtom(atomVerbose);
        ExitOnLastError(hr, "Failed to delete WcaVerboseLogging global atom.");
    }

    atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging");
    if (0 == atomVerbose && !bValue)
    {
        atomVerbose = ::GlobalAddAtomW(L"WcaNotVerboseLogging");
        ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaNotVerboseLogging global atom.");
    }
    else if (0 != atomVerbose && bValue)
    {
        ::SetLastError(ERROR_SUCCESS);
        ::GlobalDeleteAtom(atomVerbose);
        ExitOnLastError(hr, "Failed to delete WcaNotVerboseLogging global atom.");
    }

LExit:
    return hr;
}
Beispiel #3
0
static HRESULT CreateMessageWindow(
    __out HWND* phWnd
    )
{
    HRESULT hr = S_OK;
    HANDLE rgWaitHandles[2] = { };
    UITHREAD_CONTEXT context = { };

    // Create event to signal after the UI thread / window is initialized.
    rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL);
    ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event.");

    // Pass necessary information to create the window.
    context.hInitializedEvent = rgWaitHandles[0];
    context.hInstance = (HINSTANCE)g_hInstCADLL;

    // Create our separate UI thread.
    rgWaitHandles[1] = ::CreateThread(NULL, 0, ThreadProc, &context, 0, NULL);
    ExitOnNullWithLastError(rgWaitHandles[1], hr, "Failed to create the UI thread.");

    // Wait for either the thread to be initialized or the window to exit / fail prematurely.
    ::WaitForMultipleObjects(countof(rgWaitHandles), rgWaitHandles, FALSE, INFINITE);

    // Pass the window back to the caller.
    *phWnd = context.hWnd;

LExit:
    ReleaseHandle(rgWaitHandles[1]);
    ReleaseHandle(rgWaitHandles[0]);

    return hr;
}
Beispiel #4
0
static HRESULT RmuInitialize()
{
    HRESULT hr = S_OK;
    HMODULE hModule = NULL;

    LONG iRef = ::InterlockedIncrement(&vcRmuInitialized);
    if (1 == iRef && !vhModule)
    {
        hr = LoadSystemLibrary(L"rstrtmgr.dll", &hModule);
        ExitOnFailure(hr, "Failed to load the rstrtmgr.dll module.");

        vpfnRmJoinSession = reinterpret_cast<PFNRMJOINSESSION>(::GetProcAddress(hModule, "RmJoinSession"));
        ExitOnNullWithLastError(vpfnRmJoinSession, hr, "Failed to get the RmJoinSession procedure from rstrtmgr.dll.");

        vpfnRmRegisterResources = reinterpret_cast<PFNRMREGISTERRESOURCES>(::GetProcAddress(hModule, "RmRegisterResources"));
        ExitOnNullWithLastError(vpfnRmRegisterResources, hr, "Failed to get the RmRegisterResources procedure from rstrtmgr.dll.");

        vpfnRmEndSession = reinterpret_cast<PFNRMENDSESSION>(::GetProcAddress(hModule, "RmEndSession"));
        ExitOnNullWithLastError(vpfnRmEndSession, hr, "Failed to get the RmEndSession procedure from rstrtmgr.dll.");

        vhModule = hModule;
    }

LExit:
    return hr;
}
Beispiel #5
0
extern "C" HRESULT DisplayStart(
    __in HINSTANCE hInstance,
    __in HWND hWnd,
    __out HANDLE *phThread,
    __out DWORD* pdwThreadId
    )
{
    HRESULT hr = S_OK;
    HANDLE rgHandles[2] = { };
    DISPLAY_THREAD_CONTEXT context = { };

    rgHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL);
    ExitOnNullWithLastError(rgHandles[0], hr, "Failed to create load init event.");

    context.hWnd = hWnd;
    context.hInstance = hInstance;
    context.hInit = rgHandles[0];

    rgHandles[1] = ::CreateThread(NULL, 0, DisplayThreadProc, reinterpret_cast<LPVOID>(&context), 0, pdwThreadId);
    ExitOnNullWithLastError(rgHandles[1], hr, "Failed to create display thread.");

    ::WaitForMultipleObjects(countof(rgHandles), rgHandles, FALSE, INFINITE);

    *phThread = rgHandles[1];
    rgHandles[1] = NULL;

LExit:
    ReleaseHandle(rgHandles[1]);
    ReleaseHandle(rgHandles[0]);
    return hr;
}
Beispiel #6
0
static HRESULT EnsureWUServiceEnabled(
    __in BOOL fStopWusaService,
    __out SC_HANDLE* pschWu,
    __out BOOL* pfPreviouslyDisabled
    )
{
    HRESULT hr = S_OK;
    SC_HANDLE schSCM = NULL;
    SC_HANDLE schWu = NULL;
    SERVICE_STATUS serviceStatus = { };
    QUERY_SERVICE_CONFIGW* pConfig = NULL;

    schSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    ExitOnNullWithLastError(schSCM, hr, "Failed to open service control manager.");

    schWu = ::OpenServiceW(schSCM, L"wuauserv", SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_STOP );
    ExitOnNullWithLastError(schWu, hr, "Failed to open WU service.");

    if (!::QueryServiceStatus(schWu, &serviceStatus) )
    {
        ExitWithLastError(hr, "Failed to query status of WU service.");
    }

    // Stop service if requested to.
    if (SERVICE_STOPPED != serviceStatus.dwCurrentState && fStopWusaService)
    {
        hr = StopWUService(schWu);
    }

    // If the service is not running then it might be disabled so let's check.
    if (SERVICE_RUNNING != serviceStatus.dwCurrentState)
    {
        hr = SvcQueryConfig(schWu, &pConfig);
        ExitOnFailure(hr, "Failed to read configuration for WU service.");

        // If WU is disabled, change it to a demand start service (but touch nothing else).
        if (SERVICE_DISABLED == pConfig->dwStartType)
        {
            hr = SetServiceStartType(schWu, SERVICE_DEMAND_START);
            ExitOnFailure(hr, "Failed to mark WU service to start on demand.");

            *pfPreviouslyDisabled = TRUE;
        }
    }

    *pschWu = schWu;
    schWu = NULL;

LExit:
    ReleaseMem(pConfig);
    ReleaseServiceHandle(schWu);
    ReleaseServiceHandle(schSCM);

    return hr;
}
Beispiel #7
0
DAPI_(HRESULT) SrpInitialize(
    __in BOOL fInitializeComSecurity
    )
{
    HRESULT hr = S_OK;

    hr = LoadSystemLibrary(L"srclient.dll", &vhSrClientDll);
    if (FAILED(hr))
    {
        ExitFunction1(hr = E_NOTIMPL);
    }

    vpfnSRSetRestorePointW = reinterpret_cast<PFN_SETRESTOREPTW>(::GetProcAddress(vhSrClientDll, "SRSetRestorePointW"));
    ExitOnNullWithLastError(vpfnSRSetRestorePointW, hr, "Failed to find set restore point proc address.");

    // If allowed, initialize COM security to enable NetworkService,
    // LocalService and System to make callbacks to the process
    // calling System Restore. This is required for any process
    // that calls SRSetRestorePoint.
    if (fInitializeComSecurity)
    {
        hr = InitializeComSecurity();
        ExitOnFailure(hr, "Failed to initialize security for COM to talk to system restore.");
    }

LExit:
    if (FAILED(hr) && vhSrClientDll)
    {
        SrpUninitialize();
    }

    return hr;
}
Beispiel #8
0
/*******************************************************************
 LoadSystemLibraryWithPath - Fully qualifies the path to a module in
                             the Windows system directory and loads it
                             and returns the path

 Returns
   E_MODNOTFOUND - The module could not be found.
   * - Another error occured.
********************************************************************/
extern "C" HRESULT DAPI LoadSystemLibraryWithPath(
    __in_z LPCWSTR wzModuleName,
    __out HMODULE *phModule,
    __deref_out_z_opt LPWSTR* psczPath
    )
{
    HRESULT hr = S_OK;
    DWORD cch = 0;
    WCHAR wzPath[MAX_PATH] = { };

    cch = ::GetSystemDirectoryW(wzPath, MAX_PATH);
    ExitOnNullWithLastError(cch, hr, "Failed to get the Windows system directory.");

    if (L'\\' != wzPath[cch - 1])
    {
        hr = ::StringCchCatNW(wzPath, MAX_PATH, L"\\", 1);
        ExitOnRootFailure(hr, "Failed to terminate the string with a backslash.");
    }

    hr = ::StringCchCatW(wzPath, MAX_PATH, wzModuleName);
    ExitOnRootFailure1(hr, "Failed to create the fully-qualified path to %ls.", wzModuleName);

    *phModule = ::LoadLibraryW(wzPath);
    ExitOnNullWithLastError1(*phModule, hr, "Failed to load the library %ls.", wzModuleName);

    if (psczPath)
    {
        hr = StrAllocString(psczPath, wzPath, MAX_PATH);
        ExitOnFailure(hr, "Failed to copy the path to library.");
    }

LExit:
    return hr;
}
Beispiel #9
0
static DWORD WINAPI ThreadProc(
    __in LPVOID pvContext
    )
{
    HRESULT hr = S_OK;
    UITHREAD_CONTEXT* pContext = static_cast<UITHREAD_CONTEXT*>(pvContext);

    WNDCLASSW wc = { };
    BOOL fRegistered = TRUE;
    HWND hWnd = NULL;

    BOOL fRet = FALSE;
    MSG msg = { };

    wc.lpfnWndProc = WndProc;
    wc.hInstance = pContext->hInstance;
    wc.lpszClassName = WIXCA_UITHREAD_CLASS_WINDOW;

    if (!::RegisterClassW(&wc))
    {
        ExitWithLastError(hr, "Failed to register window.");
    }

    fRegistered = TRUE;

    // Create the window to handle reboots without activating it.
    hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, SW_SHOWNA, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, NULL);
    ExitOnNullWithLastError(hWnd, hr, "Failed to create window.");

    // Persist the window handle and let the caller know we've initialized.
    pContext->hWnd = hWnd;
    ::SetEvent(pContext->hInitializedEvent);

    // Pump messages until the window is closed.
    while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
    {
        if (-1 == fRet)
        {
            hr = E_UNEXPECTED;
            ExitOnFailure(hr, "Unexpected return value from message pump.");
        }
        else if (!::IsDialogMessageW(msg.hwnd, &msg))
        {
            ::TranslateMessage(&msg);
            ::DispatchMessageW(&msg);
        }
    }

LExit:
    if (fRegistered)
    {
        ::UnregisterClassW(WIXCA_UITHREAD_CLASS_WINDOW, pContext->hInstance);
    }

    return hr;
}
Beispiel #10
0
/********************************************************************
CreateRichTextWindow - Creates Window and Child RichText control.

********************************************************************/
HRESULT CreateRichTextWindow(
    __out HWND* phWndMain,
    __out BOOL* pfRegisteredClass
    )
{
    HRESULT hr = S_OK;
    HWND hWndMain = NULL;
    WNDCLASSEXW wcex;

    //
    // Register the window class
    //
    wcex.cbSize = sizeof(WNDCLASSEXW);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = (WNDPROC)WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = NULL;
    wcex.hIcon = NULL;
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = WINDOW_CLASS;
    wcex.hIconSm = NULL;

    if (0 == ::RegisterClassExW(&wcex))
    {
        DWORD  dwResult = ::GetLastError();

        // If we get "Class already exists" error ignore it. We might
        // encounter this when the user tries to print more than once
        // in the same setup instance and we are unable to clean up fully.
        if (dwResult != ERROR_CLASS_ALREADY_EXISTS)
        {
            ExitOnFailure(hr = HRESULT_FROM_WIN32(dwResult), "failed to register window class");
        }
    }

    *pfRegisteredClass = TRUE;

    // Perform application initialization:
    hWndMain = ::CreateWindowW(WINDOW_CLASS, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, NULL, NULL);
    ExitOnNullWithLastError(hWndMain, hr, "failed to create window for printing");

    ::ShowWindow(hWndMain, SW_HIDE);
    if (!::UpdateWindow(hWndMain))
    {
        ExitWithLastError(hr, "failed to update window");
    }

    *phWndMain = hWndMain;

LExit:
    return hr;
}
Beispiel #11
0
extern "C" HRESULT WINAPI UpdateThreadCheck(
    __in LPCWSTR wzAppId,
    __in BOOL fTryExecuteUpdate
    )
{
    HRESULT hr = S_OK;
    BOOL fLocked = FALSE;
    BACKGROUND_UPDATE_THREAD_CONTEXT* pContext = NULL;

    ::EnterCriticalSection(&vUpdateThreadLock);
    fLocked = TRUE;

    if (vhUpdateThread)
    {
        DWORD er = ::WaitForSingleObject(vhUpdateThread, 0);
        if (WAIT_OBJECT_0 == er)
        {
            ::CloseHandle(vhUpdateThread);
            vhUpdateThread = NULL;
        }
        else
        {
            hr = S_FALSE;
            ExitFunction();
        }
    }

    pContext = static_cast<BACKGROUND_UPDATE_THREAD_CONTEXT*>(MemAlloc(sizeof(BACKGROUND_UPDATE_THREAD_CONTEXT), TRUE));
    ExitOnNull(pContext, hr, E_OUTOFMEMORY, "Failed to allocate memory for context.");

    hr= StrAllocString(&pContext->pwzApplicationId, wzAppId, 0);
    ExitOnFailure(hr, "Failed to copy app id into context.");

    pContext->fExecuteUpdate = fTryExecuteUpdate;

    vhUpdateThread = ::CreateThread(NULL, 0, BackgroundUpdateThread, reinterpret_cast<LPVOID>(pContext), 0, NULL);
    ExitOnNullWithLastError(vhUpdateThread, hr, "Failed to create background update thread.");

    pContext = NULL;

LExit:
    if (pContext)
    {
        ReleaseStr(pContext->pwzApplicationId);
        MemFree(pContext);
    }

    if (fLocked)
    {
        ::LeaveCriticalSection(&vUpdateThreadLock);
    }

   return hr;
}
Beispiel #12
0
static HRESULT OpenRequest(
    __in HINTERNET hConnect,
    __in_z_opt LPCWSTR wzMethod,
    __in INTERNET_SCHEME scheme,
    __in_z LPCWSTR wzResource,
    __in_z_opt LPCWSTR wzQueryString,
    __in_z_opt LPCWSTR wzHeader,
    __out HINTERNET* phUrl
    )
{
    HRESULT hr = S_OK;
    DWORD dwRequestFlags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;
    LPWSTR sczResource = NULL;
    HINTERNET hUrl = NULL;

    if (INTERNET_SCHEME_HTTPS == scheme)
    {
        dwRequestFlags |= INTERNET_FLAG_SECURE;
    }

    // Allocate the resource name.
    hr = StrAllocString(&sczResource, wzResource, 0);
    ExitOnFailure(hr, "Failed to allocate string for resource URI.");

    if (wzQueryString && *wzQueryString)
    {
        hr = StrAllocConcat(&sczResource, wzQueryString, 0);
        ExitOnFailure(hr, "Failed to append query strong to resource from URI.");
    }

    // Open the request and add the header if provided.
    hUrl = ::HttpOpenRequestW(hConnect, wzMethod, sczResource, NULL, NULL, BURN_DOWNLOAD_ENGINE_ACCEPT_TYPES, dwRequestFlags, NULL);
    ExitOnNullWithLastError(hUrl, hr, "Failed to open internet request.");

    if (wzHeader && *wzHeader)
    {
        if (!::HttpAddRequestHeadersW(hUrl, wzHeader, static_cast<DWORD>(-1), HTTP_ADDREQ_FLAG_COALESCE))
        {
            ExitWithLastError(hr, "Failed to add header to HTTP request.");
        }
    }

    *phUrl = hUrl;
    hUrl = NULL;

LExit:
    ReleaseInternet(hUrl);
    ReleaseStr(sczResource);
    return hr;
}
Beispiel #13
0
extern "C" HRESULT LoadStart(
    __in_z LPCWSTR wzThemePath,
    __in HWND hWnd,
    __out HANDLE* phThread
    )
{
    HRESULT hr = S_OK;
    HANDLE rgHandles[2] = { };
    LPWSTR sczThemePath = NULL;
    LOAD_THREAD_CONTEXT context = { };

    rgHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL);
    ExitOnNullWithLastError(rgHandles[0], hr, "Failed to create load init event.");

    hr = StrAllocString(&sczThemePath, wzThemePath, 0);
    ExitOnFailure(hr, "Failed to copy path to initial theme file.");

    context.hWnd = hWnd;
    context.sczThemePath = sczThemePath;
    context.hInit = rgHandles[0];

    rgHandles[1] = ::CreateThread(NULL, 0, LoadThreadProc, &context, 0, NULL);
    ExitOnNullWithLastError(rgHandles[1], hr, "Failed to create load thread.");

    ::WaitForMultipleObjects(countof(rgHandles), rgHandles, FALSE, INFINITE);

    *phThread = rgHandles[1];
    rgHandles[1] = NULL;
    sczThemePath = NULL;

LExit:
    ReleaseHandle(rgHandles[1]);
    ReleaseHandle(rgHandles[0]);
    ReleaseStr(sczThemePath);
    return hr;
}
Beispiel #14
0
static HRESULT RunRunOnce(
    __in_z_opt LPCWSTR wzCommandLine,
    __in int nCmdShow
    )
{
    HRESULT hr = S_OK;
    LPWSTR sczNewCommandLine = NULL;
    LPWSTR sczBurnPath = NULL;
    HANDLE hProcess = NULL;
    int argc = 0;
    LPWSTR* argv = NULL;

    // rebuild the command line without the runonce switch
    if (wzCommandLine && *wzCommandLine)
    {
        argv = ::CommandLineToArgvW(wzCommandLine, &argc);
        ExitOnNullWithLastError(argv, hr, "Failed to get command line.");

        for (int i = 0; i < argc; ++i)
        {
            if (!((argv[i][0] == L'-' || argv[i][0] == L'/') && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RUNONCE, -1)))
            {
                PathCommandLineAppend(&sczNewCommandLine, argv[i]);
            }
        }
    }

    // and re-launch
    hr = PathForCurrentProcess(&sczBurnPath, NULL);
    ExitOnFailure(hr, "Failed to get current process path.");

    hr = ProcExec(sczBurnPath, 0 < sczNewCommandLine ? sczNewCommandLine : L"", nCmdShow, &hProcess);
    ExitOnFailure1(hr, "Failed to re-launch bundle process after RunOnce: %ls", sczBurnPath);

LExit:
    if (argv)
    {
        ::LocalFree(argv);
    }

    ReleaseHandle(hProcess);
    ReleaseStr(sczNewCommandLine);
    ReleaseStr(sczBurnPath);

    return hr;
}
Beispiel #15
0
//
// ProcessCommandLine - process the provided command line arguments.
//
static HRESULT ProcessCommandLine(
    __in_z_opt LPCWSTR wzCommandLine,
    __out_z LPWSTR* psczThemeFile
    )
{
    HRESULT hr = S_OK;
    int argc = 0;
    LPWSTR* argv = NULL;

    if (wzCommandLine && *wzCommandLine)
    {
        argv = ::CommandLineToArgvW(wzCommandLine, &argc);
        ExitOnNullWithLastError(argv, hr, "Failed to get command line.");

        for (int i = 0; i < argc; ++i)
        {
            if (argv[i][0] == L'-' || argv[i][0] == L'/')
            {
                if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"lang", -1))
                {
                    if (i + 1 >= argc)
                    {
                        ExitOnRootFailure(hr = E_INVALIDARG, "Must specify a language.");
                    }

                    ++i;
                }
            }
            else
            {
                hr = StrAllocString(psczThemeFile, argv[i], 0);
                ExitOnFailure(hr, "Failed to copy path to theme file.");
            }
        }
    }

LExit:
    if (argv)
    {
        ::LocalFree(argv);
    }

    return hr;
}
Beispiel #16
0
HRESULT MqiInitialize()
{
    HRESULT hr = S_OK;

    // load mqrt.dll
    ghMQRT = ::LoadLibraryW(L"mqrt.dll");
    if (!ghMQRT)
    {
        ExitFunction1(hr = S_FALSE);
    }

    // get MQPathNameToFormatName function address
    gpfnMQPathNameToFormatName = (MQPathNameToFormatNameFunc)::GetProcAddress(ghMQRT, "MQPathNameToFormatName");
    ExitOnNullWithLastError(gpfnMQPathNameToFormatName, hr, "Failed get address for MQPathNameToFormatName() function");

    hr = S_OK;

LExit:
    return hr;
}
Beispiel #17
0
extern "C" HRESULT DAPI GetProvSecurityDesc(
    __in HCRYPTPROV hProv,
    __deref_out SECURITY_DESCRIPTOR** ppSecurity)
{
    HRESULT hr = S_OK;
    ULONG ulSize = 0;
    SECURITY_DESCRIPTOR* pSecurity = NULL;

    // Get the size of the security descriptor.
    if (!::CryptGetProvParam(
                             hProv,
                             PP_KEYSET_SEC_DESCR,
                             NULL,
                             &ulSize,
                             DACL_SECURITY_INFORMATION))
    {
        ExitWithLastError(hr, "Error getting security descriptor size for CSP.");
    }

    // Allocate the memory for the security descriptor.
    pSecurity = static_cast<SECURITY_DESCRIPTOR *>(MemAlloc(ulSize, TRUE));
    ExitOnNullWithLastError(pSecurity, hr, "Error allocating memory for CSP DACL");

    // Get the security descriptor.
    if (!::CryptGetProvParam(
                             hProv,
                             PP_KEYSET_SEC_DESCR,
                             (BYTE*)pSecurity,
                             &ulSize,
                             DACL_SECURITY_INFORMATION))
    {
        MemFree(pSecurity);
        ExitWithLastError(hr, "Error getting security descriptor for CSP.");
    }
    *ppSecurity = pSecurity;

LExit:
    return hr;
}
Beispiel #18
0
extern "C" HRESULT DAPI GetCryptProvFromCert(
      __in_opt HWND hwnd,
      __in PCCERT_CONTEXT pCert,
      __out HCRYPTPROV *phCryptProv,
      __out DWORD *pdwKeySpec,
      __in BOOL *pfDidCryptAcquire,
      __deref_opt_out LPWSTR *ppwszTmpContainer,
      __deref_opt_out LPWSTR *ppwszProviderName,
      __out DWORD *pdwProviderType
      )
{
    HRESULT hr = S_OK;
    HMODULE hMsSign32 = NULL;

    typedef BOOL (WINAPI *GETCRYPTPROVFROMCERTPTR)(HWND, PCCERT_CONTEXT, HCRYPTPROV*, DWORD*,BOOL*,LPWSTR*,LPWSTR*,DWORD*);
    GETCRYPTPROVFROMCERTPTR pGetCryptProvFromCert = NULL;

    hr = LoadSystemLibrary(L"MsSign32.dll", &hMsSign32);
    ExitOnFailure(hr, "Failed to get handle to MsSign32.dll");

    pGetCryptProvFromCert = (GETCRYPTPROVFROMCERTPTR)::GetProcAddress(hMsSign32, "GetCryptProvFromCert");
    ExitOnNullWithLastError(hMsSign32, hr, "Failed to get handle to MsSign32.dll");

    if (!pGetCryptProvFromCert(hwnd,
                               pCert,
                               phCryptProv,
                               pdwKeySpec,
                               pfDidCryptAcquire,
                               ppwszTmpContainer,
                               ppwszProviderName,
                               pdwProviderType))
    {
        ExitWithLastError(hr, "Failed to get CSP from cert.");
    }
LExit:
    return hr;
}
Beispiel #19
0
extern "C" HRESULT DAPI FreeCryptProvFromCert(
    __in BOOL fAcquired,
    __in HCRYPTPROV hProv,
    __in_opt LPWSTR pwszCapiProvider,
    __in DWORD dwProviderType,
    __in_opt LPWSTR pwszTmpContainer
    )
{
    HRESULT hr = S_OK;
    HMODULE hMsSign32 = NULL;

    typedef void (WINAPI *FREECRYPTPROVFROMCERT)(BOOL, HCRYPTPROV, LPWSTR, DWORD, LPWSTR);
    FREECRYPTPROVFROMCERT pFreeCryptProvFromCert = NULL;

    hr = LoadSystemLibrary(L"MsSign32.dll", &hMsSign32);
    ExitOnFailure(hr, "Failed to get handle to MsSign32.dll");

    pFreeCryptProvFromCert = (FREECRYPTPROVFROMCERT)::GetProcAddress(hMsSign32, "FreeCryptProvFromCert");
    ExitOnNullWithLastError(hMsSign32, hr, "Failed to get handle to MsSign32.dll");

    pFreeCryptProvFromCert(fAcquired, hProv, pwszCapiProvider, dwProviderType, pwszTmpContainer);
LExit:
    return hr;
}
Beispiel #20
0
int WINAPI wWinMain(
    __in HINSTANCE hInstance,
    __in_opt HINSTANCE /* hPrevInstance */,
    __in_z_opt LPWSTR lpCmdLine,
    __in int /*nCmdShow*/
    )
{
    ::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

    HRESULT hr = S_OK;
    BOOL fComInitialized = FALSE;
    LPWSTR sczThemeFile = NULL;
    ATOM atom = 0;
    HWND hWnd = NULL;

    HANDLE hDisplayThread = NULL;
    HANDLE hLoadThread = NULL;

    BOOL fRet = FALSE;
    MSG msg = { };

    hr = ::CoInitialize(NULL);
    ExitOnFailure(hr, "Failed to initialize COM.");
    fComInitialized = TRUE;

    hr = ProcessCommandLine(lpCmdLine, &sczThemeFile);
    ExitOnFailure(hr, "Failed to process command line.");

    hr = CreateTheme(hInstance, &vpTheme);
    ExitOnFailure(hr, "Failed to create theme.");

    hr = CreateMainWindowClass(hInstance, vpTheme, &atom);
    ExitOnFailure(hr, "Failed to create main window.");

    hWnd = ::CreateWindowExW(0, reinterpret_cast<LPCWSTR>(atom), vpTheme->sczCaption, vpTheme->dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, vpTheme->nWidth, vpTheme->nHeight, HWND_DESKTOP, NULL, hInstance, NULL);
    ExitOnNullWithLastError(hWnd, hr, "Failed to create window.");

    if (!sczThemeFile)
    {
        // Prompt for a path to the theme file.
        OPENFILENAMEW ofn = { };
        WCHAR wzFile[MAX_PATH] = { };

        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hWnd;
        ofn.lpstrFile = wzFile;
        ofn.nMaxFile = countof(wzFile);
        ofn.lpstrFilter = L"Theme Files\0*.thm\0XML Files\0*.xml\0All Files\0*.*\0";
        ofn.nFilterIndex = 1;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
        ofn.lpstrTitle = vpTheme->sczCaption;

        if (::GetOpenFileNameW(&ofn))
        {
            hr = StrAllocString(&sczThemeFile, wzFile, 0);
            ExitOnFailure(hr, "Failed to copy opened file to theme file.");
        }
        else
        {
            ::MessageBoxW(hWnd, L"Must specify a path to theme file.", vpTheme->sczCaption, MB_OK | MB_ICONERROR);
            ExitFunction1(hr = E_INVALIDARG);
        }
    }

    hr = DisplayStart(hInstance, hWnd, &hDisplayThread, &vdwDisplayThreadId);
    ExitOnFailure(hr, "Failed to start display.");

    hr = LoadStart(sczThemeFile, hWnd, &hLoadThread);
    ExitOnFailure(hr, "Failed to start load.");

    // message pump
    while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
    {
        if (-1 == fRet)
        {
            hr = E_UNEXPECTED;
            ExitOnFailure(hr, "Unexpected return value from message pump.");
        }
        else if (!ThemeHandleKeyboardMessage(vpTheme, msg.hwnd, &msg))
        {
            ::TranslateMessage(&msg);
            ::DispatchMessageW(&msg);
        }
    }

LExit:
    if (::IsWindow(hWnd))
    {
        ::DestroyWindow(hWnd);
    }

    if (hDisplayThread)
    {
        ::PostThreadMessageW(vdwDisplayThreadId, WM_QUIT, 0, 0);
        ::WaitForSingleObject(hDisplayThread, 10000);
        ::CloseHandle(hDisplayThread);
    }

    // TODO: come up with a good way to kill the load thread, probably need to switch
    // the ReadDirectoryW() to overlapped mode.
    ReleaseHandle(hLoadThread);

    if (atom && !::UnregisterClassW(reinterpret_cast<LPCWSTR>(atom), hInstance))
    {
        DWORD er = ::GetLastError();
        er = er;
    }

    ThemeFree(vpTheme);
    ThemeUninitialize();

    // uninitialize COM
    if (fComInitialized)
    {
        ::CoUninitialize();
    }

    ReleaseStr(sczThemeFile);
    return hr;
}
Beispiel #21
0
static HRESULT InstallCertificate(
	__in HCERTSTORE hStore,
	__in BOOL fUserCertificateStore,
	__in LPCWSTR wzName,
	__in_opt BYTE* rgbData,
	__in DWORD cbData,
	__in_opt LPCWSTR wzPFXPassword
	)
{
	HRESULT hr = S_OK;

	HCERTSTORE hPfxCertStore = NULL;
	PCCERT_CONTEXT pCertContext = NULL;
	PCCERT_CONTEXT pCertContextDelete = NULL;
	CERT_BLOB blob = { 0 };
	DWORD dwEncodingType;
	DWORD dwContentType;
	DWORD dwFormatType;

	// Figure out what type of blob (certificate or PFX) we're dealing with here.
	blob.pbData = rgbData;
	blob.cbData = cbData;

	if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext))
	{
		ExitWithLastError1(hr, "Failed to parse the certificate blob: %S", wzName);
	}

	if (!pCertContext)
	{
		// If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
		if (dwContentType & CERT_QUERY_CONTENT_PFX)
		{
			hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET);
			ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file.");

			// There should be at least one certificate in the PFX.
			pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, NULL);
			ExitOnNullWithLastError(pCertContext, hr, "Failed to read first certificate out of PFX file.");
		}
		else
		{
			hr = E_UNEXPECTED;
			ExitOnFailure(hr, "Unexpected certificate type processed.");
		}
	}


	// Update the friendly name of the certificate to be configured.
	blob.pbData = (BYTE*)wzName;
	blob.cbData = (lstrlenW(wzName) + 1) * sizeof(WCHAR); // including terminating null

	if (!::CertSetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, 0, &blob))
	{
		ExitWithLastError1(hr, "Failed to set the friendly name of the certificate: %S", wzName);
	}

	WcaLog(LOGMSG_STANDARD, "Adding certificate: %S", wzName);
	if (!::CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL))
	{
		MessageExitOnLastError(hr, msierrCERTFailedAdd, "Failed to add certificate to the store.");
	}

	hr = WcaProgressMessage(COST_CERT_ADD, FALSE);
	ExitOnFailure(hr, "Failed to send install progress message.");

LExit:
	if (pCertContext)
	{
		::CertFreeCertificateContext(pCertContext);
	}

	// Close the stores after the context's are released.
	if (hPfxCertStore)
	{
		::CertCloseStore(hPfxCertStore, 0);
	}

	return hr;
}
Beispiel #22
0
static HRESULT InstallCertificatePackage(
    __in HCERTSTORE hStore,
    __in BOOL fUserCertificateStore,
    __in LPCWSTR wzName,
    __in_opt BYTE* rgbData,
    __in DWORD cbData,
    __in_opt LPCWSTR wzPFXPassword
    )
{
    HRESULT hr = S_OK;

    HCERTSTORE hPfxCertStore = NULL;
    PCCERT_CONTEXT pCertContext = NULL;
    CERT_BLOB blob = { 0 };
    DWORD dwKeyset = fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET;
    DWORD dwEncodingType;
    DWORD dwContentType;
    DWORD dwFormatType;
    LPWSTR pwzUniqueName = NULL;
    int iUniqueId = 0;

    // Figure out what type of blob (certificate or PFX) we're dealing with here.
    blob.pbData = rgbData;
    blob.cbData = cbData;

    if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext))
    {
        ExitWithLastError1(hr, "Failed to parse the certificate blob: %ls", wzName);
    }

    hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId);
    ExitOnFailure(hr, "Failed to format unique name");

    if (!pCertContext)
    {
        // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
        if (dwContentType & CERT_QUERY_CONTENT_PFX)
        {
            ExitOnNull(wzPFXPassword, hr, E_INVALIDARG, "Failed to import PFX blob because no password was provided");

            // If we fail and our password is blank, also try passing in NULL for the password (according to the docs)
            hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, dwKeyset);
            if (NULL == hPfxCertStore && !*wzPFXPassword)
            {
                hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, NULL, dwKeyset);
            }
            ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file.");

            // Install all certificates in the PFX
            for (pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext);
                 pCertContext;
                 pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext))
            {
                WcaLog(LOGMSG_STANDARD, "Adding certificate: %ls", pwzUniqueName);
                hr = CertInstallSingleCertificate(hStore, pCertContext, pwzUniqueName);
                MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store.");

                hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId);
                ExitOnFailure(hr, "Failed to format unique name");
            }
        }
        else
        {
            hr = E_UNEXPECTED;
            ExitOnFailure(hr, "Unexpected certificate type processed.");
        }
    }
    else
    {
        WcaLog(LOGMSG_STANDARD, "Adding certificate: %ls", pwzUniqueName);
        hr = CertInstallSingleCertificate(hStore, pCertContext, pwzUniqueName);
        MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store.");
    }

    hr = WcaProgressMessage(COST_CERT_ADD, FALSE);
    ExitOnFailure(hr, "Failed to send install progress message.");

LExit:
    ReleaseStr(pwzUniqueName);

    if (pCertContext)
    {
        ::CertFreeCertificateContext(pCertContext);
    }

    // Close the stores after the context's are released.
    if (hPfxCertStore)
    {
        if (!::CertCloseStore(hPfxCertStore, CERT_CLOSE_STORE_CHECK_FLAG))
        {
            WcaLog(LOGMSG_VERBOSE, "PFX cert store was closed but not all resources were freed.  Error 0x%x", GetLastError());
        }
    }

    return hr;
}
Beispiel #23
0
static HRESULT DownloadResource(
    __in BURN_USER_EXPERIENCE* pUX,
    __in_z LPCWSTR wzPackageOrContainerId,
    __in_z LPCWSTR wzPayloadId,
    __in HINTERNET hSession,
    __inout_z LPWSTR* psczUrl,
    __in_z_opt LPCWSTR wzUser,
    __in_z_opt LPCWSTR wzPassword,
    __in_z LPCWSTR wzDestinationPath,
    __in DWORD64 dw64AuthoredResourceLength,
    __in DWORD64 dw64ResourceLength,
    __in DWORD64 dw64ResumeOffset,
    __in HANDLE hResumeFile,
    __in_opt BURN_CACHE_CALLBACK* pCallback
    )
{
    HRESULT hr = S_OK;
    HANDLE hPayloadFile = INVALID_HANDLE_VALUE;
    DWORD cbMaxData = 64 * 1024; // 64 KB
    BYTE* pbData = NULL;
    BOOL fRangeRequestsAccepted = TRUE;
    LPWSTR sczRangeRequestHeader = NULL;
    HINTERNET hConnect = NULL;
    HINTERNET hUrl = NULL;
    LONGLONG llLength = 0;

    hPayloadFile = ::CreateFileW(wzDestinationPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hPayloadFile)
    {
        ExitWithLastError1(hr, "Failed to create download destination file: %ls", wzDestinationPath);
    }

    // Allocate a memory block on a page boundary in case we want to do optimal writing.
    pbData = static_cast<BYTE*>(::VirtualAlloc(NULL, cbMaxData, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
    ExitOnNullWithLastError(pbData, hr, "Failed to allocate buffer to download files into.");

    // Let's try downloading the file assuming that range requests are accepted. If range requests
    // are not supported we'll have to start over and accept the fact that we only get one shot
    // downloading the file however big it is. Hopefully, not more than 2 GB since wininet doesn't
    // like files that big.
    while (fRangeRequestsAccepted && (0 == dw64ResourceLength || dw64ResumeOffset < dw64ResourceLength))
    {
        hr = AllocateRangeRequestHeader(dw64ResumeOffset, 0 == dw64ResourceLength ? dw64AuthoredResourceLength : dw64ResourceLength, &sczRangeRequestHeader);
        ExitOnFailure(hr, "Failed to allocate range request header.");

        ReleaseNullInternet(hConnect);
        ReleaseNullInternet(hUrl);

        hr = MakeRequest(pUX, wzPackageOrContainerId, wzPayloadId, hSession, psczUrl, L"GET", sczRangeRequestHeader, wzUser, wzPassword, &hConnect, &hUrl, &fRangeRequestsAccepted);
        ExitOnFailure1(hr, "Failed to request URL for download: %ls", *psczUrl);

        // If we didn't get the size of the resource from the initial "HEAD" request
        // then let's try to get the size from this "GET" request.
        if (0 == dw64ResourceLength)
        {
            hr = InternetGetSizeByHandle(hUrl, &llLength);
            if (SUCCEEDED(hr))
            {
                dw64ResourceLength = llLength;
            }
            else // server didn't tell us the resource length.
            {
                // Fallback to the authored size of the resource. However, since we
                // don't really know the size on the server, don't try to use
                // range requests either.
                dw64ResourceLength = dw64AuthoredResourceLength;
                fRangeRequestsAccepted = FALSE;
            }
        }

        // If we just tried to do a range request and found out that it isn't supported, start over.
        if (!fRangeRequestsAccepted)
        {
            // TODO: log a message that the server did not accept range requests.
            dw64ResumeOffset = 0;
        }

        hr = WriteToFile(hUrl, hPayloadFile, &dw64ResumeOffset, hResumeFile, dw64ResourceLength, pbData, cbMaxData, pCallback);
        ExitOnFailure1(hr, "Failed while reading from internet and writing to: %ls", wzDestinationPath);
    }

LExit:
    ReleaseInternet(hUrl);
    ReleaseInternet(hConnect);
    ReleaseStr(sczRangeRequestHeader);
    if (pbData)
    {
        ::VirtualFree(pbData, 0, MEM_RELEASE);
    }
    ReleaseFileHandle(hPayloadFile);

    return hr;
}
Beispiel #24
0
extern "C" HRESULT WininetDownloadUrl(
    __in BURN_USER_EXPERIENCE* pUX,
    __in BURN_CACHE_CALLBACK* pCallback,
    __in_z LPCWSTR wzPackageOrContainerId,
    __in_z LPCWSTR wzPayloadId,
    __in BURN_DOWNLOAD_SOURCE* pDownloadSource,
    __in DWORD64 dw64AuthoredDownloadSize,
    __in LPCWSTR wzDestinationPath
    )
{
    HRESULT hr = S_OK;
    LPWSTR sczUrl = NULL;
    HINTERNET hSession = NULL;
    DWORD dwTimeout = 0;
    LPWSTR sczResumePath = NULL;
    HANDLE hResumeFile = INVALID_HANDLE_VALUE;
    DWORD64 dw64ResumeOffset = 0;
    DWORD64 dw64Size = 0;
    FILETIME ftCreated = { };

    // Copy the download source into a working variable to handle redirects then
    // open the internet session.
    hr = StrAllocString(&sczUrl, pDownloadSource->sczUrl, 0);
    ExitOnFailure(hr, "Failed to copy download source URL.");

    hSession = ::InternetOpenW(L"Burn", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    ExitOnNullWithLastError(hSession, hr, "Failed to open internet session");

    // Make a best effort to set the download timeouts to 2 minutes or whatever policy says.
    PolcReadNumber(BURN_POLICY_REGISTRY_PATH, L"DownloadTimeout", 2 * 60, &dwTimeout);
    if (0 < dwTimeout)
    {
        dwTimeout *= 1000; // convert to milliseconds.
        ::InternetSetOptionW(hSession, INTERNET_OPTION_CONNECT_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
        ::InternetSetOptionW(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
        ::InternetSetOptionW(hSession, INTERNET_OPTION_SEND_TIMEOUT, &dwTimeout, sizeof(dwTimeout));
    }

    // Get the resource size and creation time from the internet.
    hr = GetResourceMetadata(pUX, wzPackageOrContainerId, wzPayloadId, hSession, &sczUrl, pDownloadSource->sczUser, pDownloadSource->sczPassword, &dw64Size, &ftCreated);
    ExitOnFailure1(hr, "Failed to get size and time for URL: %ls", sczUrl);

    // Ignore failure to initialize resume because we will fall back to full download then
    // download.
    InitializeResume(wzDestinationPath, &sczResumePath, &hResumeFile, &dw64ResumeOffset);

    hr = DownloadResource(pUX, wzPackageOrContainerId, wzPayloadId, hSession, &sczUrl, pDownloadSource->sczUser, pDownloadSource->sczPassword, wzDestinationPath, dw64AuthoredDownloadSize, dw64Size, dw64ResumeOffset, hResumeFile, pCallback);
    ExitOnFailure1(hr, "Failed to download URL: %ls", sczUrl);

    // Cleanup the resume file because we successfully downloaded the whole file.
    if (sczResumePath && *sczResumePath)
    {
        ::DeleteFileW(sczResumePath);
    }

LExit:
    ReleaseFileHandle(hResumeFile);
    ReleaseStr(sczResumePath);
    ReleaseInternet(hSession);
    ReleaseStr(sczUrl);

    return hr;
}
Beispiel #25
0
/*******************************************************************
 PipeChildConnect - Called from the child process to connect back
                    to the pipe provided by the parent process.

*******************************************************************/
extern "C" HRESULT PipeChildConnect(
    __in BURN_PIPE_CONNECTION* pConnection,
    __in BOOL fConnectCachePipe
    )
{
    Assert(pConnection->sczName);
    Assert(pConnection->sczSecret);
    Assert(!pConnection->hProcess);
    Assert(INVALID_HANDLE_VALUE == pConnection->hPipe);
    Assert(INVALID_HANDLE_VALUE == pConnection->hCachePipe);

    HRESULT hr = S_OK;
    LPWSTR sczPipeName = NULL;

    // Try to connect to the parent.
    hr = StrAllocFormatted(&sczPipeName, PIPE_NAME_FORMAT_STRING, pConnection->sczName);
    ExitOnFailure(hr, "Failed to allocate name of parent pipe.");

    hr = E_UNEXPECTED;
    for (DWORD cRetry = 0; FAILED(hr) && cRetry < PIPE_RETRY_FOR_CONNECTION; ++cRetry)
    {
        pConnection->hPipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
        if (INVALID_HANDLE_VALUE == pConnection->hPipe)
        {
            hr = HRESULT_FROM_WIN32(::GetLastError());
            if (E_FILENOTFOUND == hr) // if the pipe isn't created, call it a timeout waiting on the parent.
            {
                hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
            }

            ::Sleep(PIPE_WAIT_FOR_CONNECTION);
        }
        else // we have a connection, go with it.
        {
            hr = S_OK;
        }
    }
    ExitOnRootFailure(hr, "Failed to open parent pipe: %ls", sczPipeName)

    // Verify the parent and notify it that the child connected.
    hr = ChildPipeConnected(pConnection->hPipe, pConnection->sczSecret, &pConnection->dwProcessId);
    ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName);

    if (fConnectCachePipe)
    {
        // Connect to the parent for the cache pipe.
        hr = StrAllocFormatted(&sczPipeName, CACHE_PIPE_NAME_FORMAT_STRING, pConnection->sczName);
        ExitOnFailure(hr, "Failed to allocate name of parent cache pipe.");

        pConnection->hCachePipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
        if (INVALID_HANDLE_VALUE == pConnection->hCachePipe)
        {
            ExitWithLastError(hr, "Failed to open parent pipe: %ls", sczPipeName)
        }

        // Verify the parent and notify it that the child connected.
        hr = ChildPipeConnected(pConnection->hCachePipe, pConnection->sczSecret, &pConnection->dwProcessId);
        ExitOnFailure(hr, "Failed to verify parent pipe: %ls", sczPipeName);
    }

    pConnection->hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, pConnection->dwProcessId);
    ExitOnNullWithLastError(pConnection->hProcess, hr, "Failed to open companion process with PID: %u", pConnection->dwProcessId);

LExit:
    ReleaseStr(sczPipeName);

    return hr;
}
Beispiel #26
0
/********************************************************************
 Print - Function that sends the data from richedit control to the printer

 NOTE: Any errors encountered are saved to the vhr variable
********************************************************************/
void Print(
    __in_opt HWND hRtfWnd
    )
{
    HRESULT hr = S_OK;
    FORMATRANGE fRange;
    RECT rcPage;
    RECT rcPrintablePage;
    GETTEXTLENGTHEX gTxex;
    HDC hPrinterDC = vpPrintDlg->hDC;
    int nHorizRes = ::GetDeviceCaps(hPrinterDC, HORZRES);
    int nVertRes = ::GetDeviceCaps(hPrinterDC, VERTRES);
    int nLogPixelsX = ::GetDeviceCaps(hPrinterDC, LOGPIXELSX);
    //int nLogPixelsY = ::GetDeviceCaps(hPrinterDC, LOGPIXELSY);
    LONG_PTR lTextLength = 0; // Length of document.
    LONG_PTR lTextPrinted = 0; // Amount of document printed.
    DOCINFOW dInfo;
    LPDEVNAMES pDevnames;
    LPWSTR sczProductName = NULL;
    BOOL fStartedDoc = FALSE;
    BOOL fPrintedSomething = FALSE;

    // Ensure the printer DC is in MM_TEXT mode.
    if (0 == ::SetMapMode(hPrinterDC, MM_TEXT))
    {
        ExitWithLastError(hr, "failed to set map mode");
    }

    // Rendering to the same DC we are measuring.
    ::ZeroMemory(&fRange, sizeof(fRange));
    fRange.hdc = fRange.hdcTarget = hPrinterDC;

    // Set up the page.
    rcPage.left = rcPage.top = 0;
    rcPage.right = MulDiv(nHorizRes, ONE_INCH, nLogPixelsX);
    rcPage.bottom = MulDiv(nVertRes, ONE_INCH, nLogPixelsX);

    // Set up 1" margins all around.
    rcPrintablePage.left = rcPage.left + ONE_INCH;  
    rcPrintablePage.top = rcPage.top + ONE_INCH;
    rcPrintablePage.right = rcPage.right - ONE_INCH;
    rcPrintablePage.bottom = rcPage.bottom - ONE_INCH;

    // Set up the print job (standard printing stuff here).
    ::ZeroMemory(&dInfo, sizeof(dInfo));
    dInfo.cbSize = sizeof(DOCINFO);
    hr = WcaGetProperty(L"ProductName", &sczProductName);
    if (FAILED(hr))
    {
        // If we fail to get the product name, don't fail, just leave it blank;
        dInfo.lpszDocName = L"";
        hr = S_OK;
    }
    else
    {
        dInfo.lpszDocName = sczProductName;
    }

    pDevnames = (LPDEVNAMES)::GlobalLock(vpPrintDlg->hDevNames);
    ExitOnNullWithLastError(pDevnames, hr, "failed to get global lock");

    dInfo.lpszOutput  = (LPWSTR)pDevnames + pDevnames->wOutputOffset;

    if (0 == ::GlobalUnlock(pDevnames))
    {
        ExitWithLastError(hr, "failed to release global lock");
    }

    // Start the document.
    if (0 >= ::StartDocW(hPrinterDC, &dInfo))
    {
        ExitWithLastError(hr, "failed to start print document");
    }

    fStartedDoc = TRUE;

    ::ZeroMemory(&gTxex, sizeof(gTxex));
    gTxex.flags = GTL_NUMCHARS | GTL_PRECISE;
    lTextLength = ::SendMessageW(hRtfWnd, EM_GETTEXTLENGTHEX, (LONG_PTR)&gTxex, 0);

    while (lTextPrinted < lTextLength)
    {
        // Start the page.
        if (0 >= ::StartPage(hPrinterDC))
        {
            ExitWithLastError(hr, "failed to start print page");
        }

        // Always reset to the full printable page and start where the
        // last text left off (or zero at the beginning).
        fRange.rc = rcPrintablePage;
        fRange.rcPage = rcPage;
        fRange.chrg.cpMin = (LONG)lTextPrinted;
        fRange.chrg.cpMax = -1;

        // Print as much text as can fit on a page. The return value is
        // the index of the first character on the next page. Using TRUE
        // for the wParam parameter causes the text to be printed.
        lTextPrinted = ::SendMessageW(hRtfWnd, EM_FORMATRANGE, TRUE, (LPARAM)&fRange);
        fPrintedSomething = TRUE;

        // If text wasn't printed (i.e. we didn't move past the point we started) then
        // something must have gone wrong.
        if (lTextPrinted <= fRange.chrg.cpMin)
        {
            hr = E_FAIL;
            ExitOnFailure(hr, "failed to print some text");
        }

        // Print last page.
        if (0 >= ::EndPage(hPrinterDC))
        {
            ExitWithLastError(hr, "failed to end print page");
        }
    }

LExit:
    // Tell the control to release cached information, if we actually tried to
    // print something.
    if (fPrintedSomething)
    {
        ::SendMessageW(hRtfWnd, EM_FORMATRANGE, 0, (LPARAM)NULL);
    }

    if (fStartedDoc)
    {
        ::EndDoc(hPrinterDC);
    }

    ReleaseStr(sczProductName);

    vhr = hr;
}
Beispiel #27
0
static DWORD WINAPI DisplayThreadProc(
    __in LPVOID pvContext
    )
{
    HRESULT hr = S_OK;

    DISPLAY_THREAD_CONTEXT* pContext = static_cast<DISPLAY_THREAD_CONTEXT*>(pvContext);
    HINSTANCE hInstance = pContext->hInstance;
    HWND hwndParent = pContext->hWnd;

    // We can signal the initialization event as soon as we have copied the context
    // values into local variables.
    ::SetEvent(pContext->hInit);

    BOOL fComInitialized = FALSE;

    HANDLE_THEME* pCurrentHandle = NULL;
    ATOM atomWc = 0;
    WNDCLASSW wc = { }; // the following are constant for the display window class.
    wc.lpfnWndProc = DisplayWndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = THMVWR_WINDOW_CLASS_DISPLAY;

    HWND hWnd = NULL;
    RECT rc = { };
    int x = CW_USEDEFAULT;
    int y = CW_USEDEFAULT;

    BOOL fRedoMsg = FALSE;
    BOOL fRet = FALSE;
    MSG msg = { };

    BOOL fCreateIfNecessary = FALSE;

    hr = ::CoInitialize(NULL);
    ExitOnFailure(hr, "Failed to initialize COM on display thread.");
    fComInitialized = TRUE;

    // As long as the parent window is alive and kicking, keep this thread going (with or without a theme to display ).
    while (::IsWindow(hwndParent))
    {
        if (pCurrentHandle && fCreateIfNecessary)
        {
            THEME* pTheme = pCurrentHandle->pTheme;

            if (CW_USEDEFAULT == x && CW_USEDEFAULT == y && ::GetWindowRect(hwndParent, &rc))
            {
                x = rc.left;
                y = rc.bottom + 20;
            }

            hWnd = ::CreateWindowExW(0, wc.lpszClassName, pTheme->sczCaption, pTheme->dwStyle, x, y, pTheme->nWidth, pTheme->nHeight, hwndParent, NULL, hInstance, pCurrentHandle);
            ExitOnNullWithLastError(hWnd, hr, "Failed to create display window.");

            fCreateIfNecessary = FALSE;
        }

        // message pump
        while (fRedoMsg || 0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
        {
            if (fRedoMsg)
            {
                fRedoMsg = FALSE;
            }

            if (-1 == fRet)
            {
                hr = E_UNEXPECTED;
                ExitOnFailure(hr, "Unexpected return value from display message pump.");
            }
            else if (NULL == msg.hwnd) // Thread message.
            {
                if (WM_THMVWR_NEW_THEME == msg.message)
                {
                    // If there is already a handle, release it.
                    if (pCurrentHandle)
                    {
                        DecrementHandleTheme(pCurrentHandle);
                        pCurrentHandle = NULL;
                    }

                    // If the window was created, remember its window location before we destroy
                    // it so so we can open the new window in the same place.
                    if (::IsWindow(hWnd))
                    {
                        ::GetWindowRect(hWnd, &rc);
                        x = rc.left;
                        y = rc.top;

                        ::DestroyWindow(hWnd); 
                    }

                    // If the display window class was registered, unregister it so we can
                    // reuse the same window class name for the new theme.
                    if (atomWc)
                    {
                        if (!::UnregisterClassW(reinterpret_cast<LPCWSTR>(atomWc), hInstance))
                        {
                            DWORD er = ::GetLastError();
                            er = er;
                        }

                        atomWc = 0;
                    }

                    // If we were provided a new theme handle, create a new window class to
                    // support it.
                    pCurrentHandle = reinterpret_cast<HANDLE_THEME*>(msg.lParam);
                    if (pCurrentHandle)
                    {
                        wc.hIcon = reinterpret_cast<HICON>(pCurrentHandle->pTheme->hIcon);
                        wc.hCursor = ::LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
                        if (0 < pCurrentHandle->pTheme->cFonts)
                        {
                            wc.hbrBackground = pCurrentHandle->pTheme->rgFonts[pCurrentHandle->pTheme->dwFontId].hBackground;
                        }
                        atomWc = ::RegisterClassW(&wc);
                        if (!atomWc)
                        {
                            ExitWithLastError(hr, "Failed to register display window class.");
                        }
                    }
                }
                else if (WM_THMVWR_SHOWPAGE == msg.message)
                {
                    if (pCurrentHandle && ::IsWindow(hWnd) && pCurrentHandle->pTheme->hwndParent == hWnd)
                    {
                        DWORD dwPageId = static_cast<DWORD>(msg.lParam);
                        int nCmdShow = static_cast<int>(msg.wParam);

                        // First show/hide the controls not associated with a page.
                        for (DWORD i = 0; i < pCurrentHandle->pTheme->cControls; ++i)
                        {
                            THEME_CONTROL* pControl = pCurrentHandle->pTheme->rgControls + i;
                            if (!pControl->wPageId)
                            {
                                ThemeShowControl(pCurrentHandle->pTheme, pControl->wId, nCmdShow);
                            }
                        }

                        // If a page id was provided also, show/hide those controls
                        if (dwPageId)
                        {
                            ThemeShowPage(pCurrentHandle->pTheme, dwPageId, nCmdShow);
                        }
                    }
                    else // display window isn't visible or it doesn't match the current handle.
                    {
                        // Keep the current message around to try again after we break out of this loop
                        // and create the window.
                        fRedoMsg = TRUE;
                        fCreateIfNecessary = TRUE;
                        break;
                    }
                }
            }
            else if (!ThemeHandleKeyboardMessage(pCurrentHandle->pTheme, hwndParent, &msg)) // Window message.
            {
                ::TranslateMessage(&msg);
                ::DispatchMessageW(&msg);
            }
        }
    }

LExit:
    if (::IsWindow(hWnd))
    {
        ::DestroyWindow(hWnd);
    }

    if (atomWc)
    {
        if (!::UnregisterClassW(THMVWR_WINDOW_CLASS_DISPLAY, hInstance))
        {
            DWORD er = ::GetLastError();
            er = er;
        }
    }

    DecrementHandleTheme(pCurrentHandle);

    if (fComInitialized)
    {
        ::CoUninitialize();
    }

    return hr;
}
Beispiel #28
0
/******************************************************************
WixWaitForEvent - entry point for WixWaitForEvent custom action
    which waits for either the WixWaitForEventFail or
    WixWaitForEventSucceed named auto reset events. Signaling the
    WixWaitForEventFail event will return ERROR_INSTALL_FAILURE or
    signaling the WixWaitForEventSucceed event will return
    ERROR_SUCCESS. Both events are declared in the Global\ namespace.
********************************************************************/
extern "C" UINT __stdcall WixWaitForEvent(
    __in MSIHANDLE hInstall
    )
{
    HRESULT hr = S_OK;
    UINT er = ERROR_SUCCESS;
    HWND hMessageWindow = NULL;
    LPCWSTR wzSDDL = L"D:(A;;GA;;;WD)";
    OS_VERSION version = OS_VERSION_UNKNOWN;
    DWORD dwServicePack = 0;
    PSECURITY_DESCRIPTOR pSD = NULL;
    SECURITY_ATTRIBUTES sa = { };
    HANDLE rghEvents[2];

    hr = WcaInitialize(hInstall, "WixWaitForEvent");
    ExitOnFailure(hr, "Failed to initialize.");

    // Create a window to prevent shutdown requests.
    hr = CreateMessageWindow(&hMessageWindow);
    ExitOnFailure(hr, "Failed to create message window.");

    // If running on Vista/2008 or newer use integrity enhancements.
    OsGetVersion(&version, &dwServicePack);
    if (OS_VERSION_VISTA <= version)
    {
        // Add SACL to allow Everyone to signal from a medium integrity level.
        wzSDDL = L"D:(A;;GA;;;WD)S:(ML;;NW;;;ME)";
    }

    // Create the security descriptor and attributes for the events.
    if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSDDL, SDDL_REVISION_1, &pSD, NULL))
    {
        ExitWithLastError(hr, "Failed to create the security descriptor for the events.");
    }

    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle = FALSE;

    rghEvents[0] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventFail");
    ExitOnNullWithLastError(rghEvents[0], hr, "Failed to create the Global\\WixWaitForEventFail event.");

    rghEvents[1] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventSucceed");
    ExitOnNullWithLastError(rghEvents[1], hr, "Failed to create the Global\\WixWaitForEventSucceed event.");

    // Wait for either of the events to be signaled and handle accordingly.
    er = ::WaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE);
    switch (er)
    {
    case WAIT_OBJECT_0 + 0:
        er = ERROR_INSTALL_FAILURE;
        break;
    case WAIT_OBJECT_0 + 1:
        er = ERROR_SUCCESS;
        break;
    default:
        ExitOnWin32Error(er, hr, "Unexpected failure.");
    }

LExit:
    ReleaseHandle(rghEvents[1]);
    ReleaseHandle(rghEvents[0]);

    if (pSD)
    {
        ::LocalFree(pSD);
    }

    if (hMessageWindow)
    {
        CloseMessageWindow(hMessageWindow);
    }

    if (FAILED(hr))
    {
        er = ERROR_INSTALL_FAILURE;
    }

    return WcaFinalize(er);
}
Beispiel #29
0
/********************************************************************
 PrintEula - Custom Action entry point

********************************************************************/
extern "C" UINT __stdcall PrintEula(MSIHANDLE hInstall)
{
    //AssertSz(FALSE, "Debug PrintEula");

    HRESULT hr = S_OK;
    HWND hWndMain = NULL;
    HMODULE hRichEdit = NULL;
    BOOL fRegisteredClass = FALSE;

    hr = WcaInitialize(hInstall, "PrintEula");
    ExitOnFailure(hr, "failed to initialize");

    // Initialize then display print dialog.
    vpPrintDlg = (PRINTDLGEXW*)GlobalAlloc(GPTR, sizeof(PRINTDLGEXW)); // MSDN says to allocate on heap.
    ExitOnNullWithLastError(vpPrintDlg, hr, "Failed to allocate memory for print dialog struct.");

    vpPrintDlg->lStructSize = sizeof(PRINTDLGEX);
    vpPrintDlg->hwndOwner = ::FindWindowW(L"MsiDialogCloseClass", NULL);
    vpPrintDlg->Flags = PD_RETURNDC | PD_COLLATE | PD_NOCURRENTPAGE | PD_ALLPAGES | PD_NOPAGENUMS | PD_NOSELECTION;
    vpPrintDlg->nCopies = NO_OF_COPIES;
    vpPrintDlg->nStartPage = START_PAGE_GENERAL;

    hr = ::PrintDlgExW(vpPrintDlg);
    ExitOnFailure(hr, "Failed to show print dialog");

    // If user said they want to print.
    if (PD_RESULT_PRINT == vpPrintDlg->dwResultAction)
    {
        // Get the stream for Eula
        hr = ReadEulaText(hInstall, &vpszEulaText);
        ExitOnFailure(hr, "failed to read Eula text from MSI database");

        // Have to load Rich Edit since we'll be creating a Rich Edit control in the window
        hr = LoadSystemLibrary(L"Riched20.dll", &hRichEdit);
        ExitOnFailure(hr, "failed to load rich edit 2.0 library");

        hr = CreateRichTextWindow(&hWndMain, &fRegisteredClass);
        ExitOnFailure(hr, "failed to create rich text window for printing");

        hr = PrintRichText(hWndMain);
        if (FAILED(hr)) // Since we've already shown the print dialog, we better show them a dialog explaining why it didn't print
        {
            ShowErrorMessage(hr);
        }
    }

LExit:
    ReleaseNullStr(vpszEulaText);
    if (vpPrintDlg)
    {
        if (vpPrintDlg->hDevMode)
        {
            ::GlobalFree(vpPrintDlg->hDevMode);
        }

        if (vpPrintDlg->hDevNames)
        {
            ::GlobalFree(vpPrintDlg->hDevNames);
        }

        if (vpPrintDlg->hDC)
        {
            ::DeleteDC(vpPrintDlg->hDC);
        }

        ::GlobalFree(vpPrintDlg);
        vpPrintDlg = NULL;
    }

    if (fRegisteredClass)
    {
        ::UnregisterClassW(WINDOW_CLASS, NULL);
    }

    if (NULL != hRichEdit)
    {
        ::FreeLibrary(hRichEdit);
    }

    // Always return success since we dont want to stop the
    // installation even if the Eula printing fails.
    return WcaFinalize(ERROR_SUCCESS);
}
Beispiel #30
0
/********************************************************************
 XmlCreateDocument -

*********************************************************************/
extern "C" HRESULT DAPI XmlCreateDocument(
    __in_opt LPCWSTR pwzElementName,
    __out IXMLDOMDocument** ppixdDocument,
    __out_opt IXMLDOMElement** ppixeRootElement
    )
{
    HRESULT hr = S_OK;
    BOOL (WINAPI *pfnDisableWow64)(__out PVOID* ) = NULL;
    BOOL (WINAPI *pfnEnableWow64)(__in BOOLEAN ) = NULL;
    BOOL (WINAPI *pfnRevertWow64)(__in PVOID ) = NULL;
    BOOL fWow64Available = FALSE;
    void *pvWow64State = NULL;

    // RELEASEME
    IXMLDOMElement* pixeRootElement = NULL;
    IXMLDOMDocument *pixdDocument = NULL;

    // Test if we have access to the Wow64 API, and store the result in fWow64Available
    HMODULE hKernel32 = ::GetModuleHandleA("kernel32.dll");
    ExitOnNullWithLastError(hKernel32, hr, "failed to get handle to kernel32.dll");

    // This will test if we have access to the Wow64 API
    if (NULL != GetProcAddress(hKernel32, "IsWow64Process"))
    {
        pfnDisableWow64 = (BOOL (WINAPI *)(PVOID *))::GetProcAddress(hKernel32, "Wow64DisableWow64FsRedirection");
        pfnEnableWow64 = (BOOL (WINAPI *)(BOOLEAN))::GetProcAddress(hKernel32, "Wow64EnableWow64FsRedirection");
        pfnRevertWow64 = (BOOL (WINAPI *)(PVOID))::GetProcAddress(hKernel32, "Wow64RevertWow64FsRedirection");

        fWow64Available = pfnDisableWow64 && pfnEnableWow64 && pfnRevertWow64;
    }

    // create the top level XML document
    AssertSz(vcXmlInitialized, "XmlInitialize() was not called");

    // Enable Wow64 Redirection, if possible
    if (fWow64Available)
    {
        // We want to enable Wow64 redirection, but the Wow64 API requires us to disable it first to get its current state (so we can revert it later)
        pfnDisableWow64(&pvWow64State);
        // If we fail to enable it, don't bother trying to disable it later on
        fWow64Available = pfnEnableWow64(TRUE);
    }

    hr = ::CoCreateInstance(vclsidXMLDOM, NULL, CLSCTX_INPROC_SERVER, XmlUtil_IID_IXMLDOMDocument, (void**)&pixdDocument);
    ExitOnFailure(hr, "failed to create XML DOM Document");
    Assert(pixdDocument);

    if (IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument30) || IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument20))
    {
        vfMsxml30 = TRUE;
    }

    if (pwzElementName)
    {
        hr = XmlCreateElement(pixdDocument, pwzElementName, &pixeRootElement);
        ExitOnFailure(hr, "failed XmlCreateElement");
        hr = pixdDocument->appendChild(pixeRootElement, NULL);
        ExitOnFailure(hr, "failed appendChild");
    }

    *ppixdDocument = pixdDocument;
    pixdDocument = NULL;

    if (ppixeRootElement)
    {
        *ppixeRootElement = pixeRootElement;
        pixeRootElement = NULL;
    }

LExit:
    // Re-disable Wow64 Redirection, if appropriate
    if (fWow64Available && !pfnRevertWow64(pvWow64State))
    {
        // If we expected to be able to revert, and couldn't, fail in the only graceful way we can
        ::ExitProcess(1);
    }

    ReleaseObject(pixeRootElement);
    ReleaseObject(pixdDocument);
    return hr;
}