The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
// This code is free software; you can redistribute it and/or modify it
// under the same terms as Perl itself.

// This code is free software; you can redistribute it and/or modify it
// under the same terms as Perl itself.

// ##### MSI logging related functions, no exported functions

#include "stdafx.h"

void Log(MSIHANDLE hModule, LPCTSTR sString) // Handle of MSI being installed. [in]
{
    // Set up variables.
    PMSIHANDLE hRecord = ::MsiCreateRecord(2);
    if (hRecord == NULL) return;

    UINT uiAnswer = ::MsiRecordSetString(hRecord, 0, sString);
    if (uiAnswer != ERROR_SUCCESS) return;
    
    // Send the message
    ::MsiProcessMessage(hModule, INSTALLMESSAGE(INSTALLMESSAGE_INFO), hRecord);
}

void SimpleLogString1(MSIHANDLE hModule, LPCTSTR s)
{
    static TCHAR str[513];
    _tcscpy_s(str, 512, s ? s : _T("<null>"));
    Log(hModule, str);
}

void SimpleLogString2(MSIHANDLE hModule, LPCTSTR s, LPCTSTR t)
{
    static TCHAR str[513];
    _tcscpy_s(str, 512, s ? s : _T("<null>"));
    _tcscat_s(str, 512, t ? t : _T("<null>"));
    Log(hModule, str);
}

void SimpleLogString3(MSIHANDLE hModule, LPCTSTR s, LPCTSTR t, LPCTSTR u)
{
    static TCHAR str[513];
    _tcscpy_s(str, 512, s ? s : _T("<null>"));
    _tcscat_s(str, 512, t ? t : _T("<null>"));
    _tcscat_s(str, 512, u ? u : _T("<null>"));
    Log(hModule, str);
}

void SimpleLogString4(MSIHANDLE hModule, LPCTSTR s, LPCTSTR t, LPCTSTR u, LPCTSTR v)
{
    static TCHAR str[513];
    _tcscpy_s(str, 512, s ? s : _T("<null>"));
    _tcscat_s(str, 512, t ? t : _T("<null>"));
    _tcscat_s(str, 512, u ? u : _T("<null>"));
    _tcscat_s(str, 512, v ? v : _T("<null>"));
    Log(hModule, str);
}

UINT RETURN_ON_ERROR(UINT retval, MSIHANDLE hModule, LPCTSTR s)
{
    if (ERROR_SUCCESS != retval) {
        SimpleLogString1(hModule, s);
        return 1;
    }
    return 0;
}

void PrintUINT(MSIHANDLE hModule, UINT i) 
{
    static TCHAR sNumber[100];
    _stprintf_s(sNumber, 99, _T("%d"), i);
    SimpleLogString2(hModule, _T("DEBUG: UINT="), sNumber);
}

void PrintLastErrorDetails(MSIHANDLE hModule)
{
    PMSIHANDLE hLastErrorRec = MsiGetLastErrorRecord();
    TCHAR* szExtendedError = NULL;
    DWORD cchExtendedError = 0;
    if (hLastErrorRec) {
        // Since we are not currently calling MsiFormatRecord during an
        // install session, hInstall is NULL. If MsiFormatRecord was called
        // via a DLL custom action, the hInstall handle provided to the DLL
        // custom action entry point could be used to further resolve 
        // properties that might be contained within the error record.
            
        // To determine the size of the buffer required for the text,
        // szResultBuf must be provided as an empty string with
        // *pcchResultBuf set to 0.

        UINT uiStatus = MsiFormatRecord(NULL, hLastErrorRec, TEXT(""), &cchExtendedError);

        if (ERROR_MORE_DATA == uiStatus) {
            // returned size does not include null terminator.
            cchExtendedError++;

            szExtendedError = new TCHAR[cchExtendedError];
            if (szExtendedError) {
                uiStatus = MsiFormatRecord(NULL, hLastErrorRec, szExtendedError, &cchExtendedError);
                if (ERROR_SUCCESS == uiStatus) {
                    // We now have an extended error message to report.
                    SimpleLogString2(hModule, _T("DEBUG: ExtendedError="), szExtendedError);
                    SimpleLogString1(hModule, _T("DEBUG: check message code(1:) at http://msdn.microsoft.com/en-us/library/aa372835.aspx"));
                }
                delete [] szExtendedError;
                szExtendedError = NULL;
            }
        }
    }
}