Memantau Penginstalan Menggunakan MsiSetExternalUIRecord
Penulis paket dapat memantau pesan Pemasang Windows internal melalui pembuatan aplikasi yang dapat dieksekusi yang berisi penangan panggilan balik berbasis rekaman untuk menerima pesan dan fungsionalitas untuk memulai penginstalan.
Handler berbasis rekaman dalam contoh berikut sesuai dengan prototipe INSTALLUI_HANDLER_RECORD , dan penunjuk ke handler panggilan balik ini diteruskan ke fungsi MsiSetExternalUIRecord .
//
// ExternalUIRecord.cpp : Defines the entry point for the console application.
//
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <msi.h>
#include <msiquery.h>
#pragma comment(lib, "msi.lib")
#pragma comment(lib, "user32.lib")
#ifndef _WIN32_MSI
#define _WIN32_MSI 310
#endif
void Usage(LPCTSTR szProgram)
{
_tprintf(TEXT("Usage: %s <path to .MSI package>\n"), szProgram);
return;
}
// In the following snippet, the hRecord parameter is used only
// to format the displayed message. However, because hRecord is
// a handle to a MSI record, the MSI API could be called to
// obtain information. The external UI handler should not close
// hRecord because the handle belongs to the Windows Installer.
INT CALLBACK UIHandler(LPVOID pvContext, UINT uiMessageType, MSIHANDLE hRecord)
{
INSTALLMESSAGE iMessage = (INSTALLMESSAGE)(0xFF000000 & uiMessageType);
BOOL bMessage = (INSTALLMESSAGE_ERROR == iMessage);
BOOL bFatalExit = (INSTALLMESSAGE_FATALEXIT == iMessage);
BOOL bWarning = (INSTALLMESSAGE_WARNING == iMessage);
if ((bMessage || bFatalExit || bWarning) && hRecord && pvContext)
{
TCHAR rgchMessage[1024];
DWORD dwMessage = sizeof(rgchMessage)/sizeof(TCHAR);
LPTSTR pszMessage = rgchMessage;
UINT uiRet = MsiFormatRecord(*(MSIHANDLE*)pvContext,
hRecord, pszMessage, &dwMessage);
if (ERROR_MORE_DATA == uiRet)
{
// Allocate a buffer to hold the string and terminating null.
pszMessage = new TCHAR[++dwMessage];
if (!pszMessage)
{
// no memory, return an error
return -1;
}
uiRet = MsiFormatRecord(*(MSIHANDLE*)pvContext,
hRecord, pszMessage, &dwMessage);
if (ERROR_SUCCESS != uiRet)
{
// Return an error if an unexpected error occurs.
if (rgchMessage != pszMessage)
delete [] pszMessage;
return -1;
}
}
TCHAR rgchFatalError[] = TEXT("Fatal Error");
TCHAR rgchError[] = TEXT("Error");
TCHAR rgchWarning[] = TEXT("Warning");
TCHAR* pszCaption = NULL;
if (INSTALLMESSAGE_ERROR == iMessage)
pszCaption = rgchError;
else if (INSTALLMESSAGE_FATALEXIT == iMessage)
pszCaption = rgchFatalError;
else if (INSTALLMESSAGE_WARNING == iMessage)
pszCaption = rgchWarning;
int iResponse = MessageBox(NULL, pszMessage,
pszCaption, uiMessageType & 0x00FFFFFF);
if (rgchMessage != pszMessage)
delete [] pszMessage;
return iResponse;
}
// Signal that the handler handled this message.
return IDOK;
}
// A console application that takes the path to a package,
// installs the package silently, and uses a record based
// external UI handler to display any error.
int _tmain(int argc, _TCHAR* argv[])
{
UINT uiRet = ERROR_SUCCESS;
MSIHANDLE hProduct = NULL;
if (2 != argc)
{
// Incorrect command line used.
Usage(argv[0]);
uiRet = 1;
goto End;
}
// Because thid example won't restore the UI level,
// ignore return value.
MsiSetInternalUI(INSTALLUILEVEL_NONE, /* pWnd */ NULL);
uiRet = MsiOpenPackage(argv[1], &hProduct);
if (ERROR_SUCCESS != uiRet)
{
_tprintf(TEXT("ERROR: Failed to open %s database.\n"), argv[1]);
uiRet = 1;
goto End;
}
// set the external UI handler
DWORD dwMessageFilter = INSTALLLOGMODE_FATALEXIT
| INSTALLLOGMODE_ERROR | INSTALLLOGMODE_WARNING;
//Pass the pointer to hProduct as the pvContext argument,
// so that the record based external UI handler
// can use it to format the records we send to it.
uiRet = MsiSetExternalUIRecord(UIHandler,
dwMessageFilter, (LPVOID)&hProduct, /* ppuiPrevHandle */ NULL);
if (ERROR_SUCCESS != uiRet)
{
_tprintf(TEXT("ERROR: Failed to set the external UI handler.\n"));
uiRet = 1;
goto End;
}
// Do the default action and install the product.
uiRet = MsiDoAction(hProduct, TEXT(""));
End:
// Close opened resources.
if (hProduct)
MsiCloseHandle(hProduct);
return ERROR_SUCCESS == uiRet ? 0 : 1;
}
//