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?