Steforgame 910
Steforgame 910

Reputation: 1

Why can't I get MSI installation progress in my MFC

I am trying to display the progress of an MSI installation in my MFC application, but I am not able to get the progress updates to show in my UI. Here is a snippet of my code:

#include "resource.h"
#include "afxdialogex.h"
#include "CMainDlg.h"
#include "msi.h"
#include "MsiQuery.h"

#define ON_WM_MSI_INSTALLATION_PROGRESS_SET_RANGE (WM_USER + 101)
#define ON_WM_MSI_INSTALLATION_PROGRESS_CHANGED (WM_USER + 102)

IMPLEMENT_DYNAMIC(CMainDlg, CDialogEx)

CMainDlg::CMainDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_Main, pParent)
{
}

void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_ActionTextS, m_ActionTextS);
    DDX_Control(pDX, IDC_PROGRESS1, m_InstallationProgress);
}

BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
    ON_MESSAGE(ON_WM_MSI_INSTALLATION_PROGRESS_SET_RANGE, &CMainDlg::OnMSIInstallationProgressSetRange)
    ON_MESSAGE(ON_WM_MSI_INSTALLATION_PROGRESS_CHANGED, &CMainDlg::OnMSIInstallationProgressChanged)
    ON_BN_CLICKED(IDC_BUTTON1, &CMainDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

struct UIHandlerContext
{
    CWnd* pThis;
};

UIHandlerContext g_context;

int __stdcall InstallUIHandler(LPVOID pvContext, UINT iMessageType, LPCSTR szMessage)
{
    MSIHANDLE hRecord = reinterpret_cast<MSIHANDLE>(szMessage);
    UINT baseMessageType = iMessageType & 0xFF000000; // Fixed bitmask

    TRACE("Received message type: 0x%08X (base: 0x%08X)\n", iMessageType, baseMessageType);

    if (!hRecord)
    {
        TRACE("Invalid record handle\n");
        return ERROR_SUCCESS;
    }

    switch (baseMessageType)
    {
    case INSTALLMESSAGE_PROGRESS:
    {
        int field1 = MsiRecordGetInteger(hRecord, 1);
        int field2 = MsiRecordGetInteger(hRecord, 2);

        TRACE("Progress message - Field1: %d, Field2: %d\n", field1, field2);

        static int totalSteps = 0;
        static int currentProgress = 0;

        if (field1 == 0 && field2 > 0)  // Reset counter
        {
            totalSteps = field2;
            currentProgress = 0;
            TRACE("Setting total steps to: %d\n", totalSteps);
            g_context.pThis->PostMessage(ON_WM_MSI_INSTALLATION_PROGRESS_SET_RANGE, 0, totalSteps);
        }
        else if (field1 == 1)  // Increment
        {
            currentProgress += field2;
            TRACE("Incrementing progress to: %d\n", currentProgress);
            g_context.pThis->PostMessage(ON_WM_MSI_INSTALLATION_PROGRESS_CHANGED, 0, currentProgress);
        }
    }
    break;
    }

    return ERROR_SUCCESS;
}

UINT InstallMSIWithUIHandler(LPCTSTR szMSIPath, CMainDlg* pThis)
{
    g_context.pThis = pThis;

    MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

    INSTALLUI_HANDLER previousUI = MsiSetExternalUI(
        InstallUIHandler,
        INSTALLLOGMODE_PROGRESS |
        INSTALLLOGMODE_ACTIONSTART |
        INSTALLLOGMODE_ACTIONDATA |
        INSTALLLOGMODE_FATALEXIT |
        INSTALLLOGMODE_ERROR |
        INSTALLLOGMODE_WARNING |
        INSTALLLOGMODE_USER |
        INSTALLLOGMODE_INFO |
        INSTALLLOGMODE_COMMONDATA,
        NULL);

    CString commandLine = L"ALLUSERS=1 REBOOT=ReallySuppress";
    return MsiInstallProduct(szMSIPath, commandLine);
}

CString GetStartupPath()
{
    wchar_t path[MAX_PATH];
    GetModuleFileNameW(NULL, path, MAX_PATH);
    CString fullPath(path);
    int pos = fullPath.ReverseFind(L'\\');
    CString directory = fullPath.Left(pos);
    directory.Replace("\\", "\\\\");
    return directory;
}

LRESULT CMainDlg::OnMSIInstallationProgressSetRange(WPARAM wParam, LPARAM lParam)
{
    int totalRange = (int)lParam;
    CString msg;
    msg.Format("Setting Progress Range: 0 to %d", totalRange);
    MessageBox(msg, "Debug", MB_OK);
    m_InstallationProgress.SetRange32(0, totalRange);
    return 0;
}

LRESULT CMainDlg::OnMSIInstallationProgressChanged(WPARAM wParam, LPARAM lParam)
{
    int progress = (int)lParam;
    CString msg;
    msg.Format("Setting Progress Position: %d", progress);
    MessageBox(msg, "Debug", MB_OK);
    m_InstallationProgress.SetPos(progress);
    return 0;
}

BOOL CMainDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_InstallationProgress.SetRange32(0, 100);
    m_InstallationProgress.SetStep(1);
    m_InstallationProgress.SetPos(0);

    return TRUE;
}

void CMainDlg::OnBnClickedButton1()
{
    InstallMSIWithUIHandler(GetStartupPath() + "\\test.msi", this);
}

Despite following the instructions to set up the message handler for the MSI installation progress, I am unable to get the progress updates to reflect in my UI. Any help or suggestions on what might be wrong would be greatly appreciated.

Thank you!

I tried various ways using the INSTALLMESSAGE_PROGRESS message but it doesn't seem to work, what I expect is to get the same progress as the MSI that is displayed just below the ActionText

MSI Installation ProgressBar

My UI ProgressBar

could someone help me?

Upvotes: 0

Views: 33

Answers (0)

Related Questions