1

I'm completely out of my depth with this, so need some asistance please. I'm trying to use MsiGetSummaryInformation and MsiSummaryInfoGetProperty

I'm not from a C++ background, so you'll have to bear with me. Here is my attempt:

    UINT sisStatus = MsiGetSummaryInformation(0,originalTransform,0,&sumh);
    //UINT sisStatus = MsiGetSummaryInformation(hDbObject,0,0,&sumh);
    if (ERROR_SUCCESS == sisStatus)
    {
        //success - start getting/setting SIS
        //UINT property_type = VT_LPSTR;

        UINT pcount;
        MsiSummaryInfoGetPropertyCount(sumh,&pcount);
        wcout << "PCount " << pcount << endl;

        UINT getpropertyid = 2; 
        UINT returnpropertyid;      
        int returnedIntPropData;
        FILETIME fileValPtr;     
        LPDWORD stringDataLength = 0;           
        LPWSTR propdata = L"";

        MsiSummaryInfoGetProperty(sumh,getpropertyid,&returnpropertyid,&returnedIntPropData,&fileValPtr,propdata, stringDataLength);

        wcout << "Propdata " << propdata << endl;
        wcout << "Stringlength " << stringDataLength << endl;


    }

It doesn't appear to work though. The values returned don't seem to be correct. Can anybody shed any light please?

UPDATE

Here's my new (updated) example:

UINT getpropertyid = 2; 
        UINT returnpropertyid;      
        int returnedIntPropData;
        FILETIME fileValPtr;     
        LPDWORD stringDataLength = new DWORD();     
        LPWSTR propdata = new TCHAR[];

        UINT gps = MsiSummaryInfoGetProperty(sumh,getpropertyid,&returnpropertyid,&returnedIntPropData,&fileValPtr,propdata, stringDataLength);
        if (ERROR_SUCCESS == gps)
        {
            wcout << "RETURN CODE: " << gps << endl;

        wcout << "Propdata " << propdata << endl;
        wcout << "Stringlength " << stringDataLength << endl;
         }
        else
        {
            wcout << "RETURN CODE EXPAND: " << gps << endl;             

            int num = (int)stringDataLength;
            wcout << "Buffer size: " << num << endl;

            propdata = new TCHAR[num];
            stringDataLength = new DWORD(num);  

            MsiSummaryInfoGetProperty(sumh,getpropertyid,&returnpropertyid,&returnedIntPropData,&fileValPtr,propdata, stringDataLength);

            wcout << "Propdata " << propdata << endl;
            wcout << "Stringlength " << stringDataLength << endl;   


        }

This line: wcout << "Buffer size: " << num << endl;

returns 3873856, which seems a bit large? I think my coding's got a bit messy. Your example would be a great help!

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111

1 Answers1

0

Avoid calling new; that gets you into a world of pain if you don't really know what you're doing. Instead pass the address of storage you've already allocated (for example by declaring a local integer value, or in the buffer for a std::wstring). I've modified your first example to be more how I would write it, albeit I'd rarely end up in a place to use wcout. (Note there's still a dangling variable for originalTransform and a hardcoded uiProperty.)

PMSIHANDLE hSum;
DWORD dwErr = MsiGetSummaryInformation(0, originalTransform, 0, &hSum);
if (ERROR_SUCCESS == dwErr)
{
    UINT uiProperty = 2;
    UINT uiDataType = 0;
    INT iValue = 0;
    FILETIME ftValue = {0};
    std::wstring sValue;
    DWORD cchValue = MAX_PATH;
    sValue.resize(cchValue);
    dwErr = MsiSummaryInfoGetProperty(hSum, uiProperty, &uiDataType, &iValue, &ftValue, const_cast<LPWSTR>(sValue.data()), &cchValue);
    if (ERROR_MORE_DATA == dwErr)
    {
        sValue.resize(++cchValue);
        dwErr = MsiSummaryInfoGetProperty(hSum, uiProperty, &uiDataType, &iValue, &ftValue, const_cast<LPWSTR>(sValue.data()), &cchValue);
    }
    if (ERROR_SUCCESS == dwErr)
    {
        sValue.resize(cchBuf);
        if (VT_LPSTR == uiDataType)
            wcout << "String Data (" << cchBuf << "): " << sValue << "\n";
        else if (VT_I4 == uiDataType)
            wcout << "Numeric Data: " << iValue << "\n";
    }
    else
    {
        wcout << "Error retrieving property: " << dwErr << "\n";
    }
}
else
{
    wcout << "Error retrieving summary info: " << dwErr << "\n";
}
Michael Urman
  • 15,737
  • 2
  • 28
  • 44
  • That's great. I've took the aspects from your example, and created a function which I can call for multiple SIS values. And it appears to work well. I must admit, this C++ adventure has been a baptism by fire. When you say thinkgs like 'avoid calling new' it makes me smile as this is a standard thing in the languages I generally write in. It feels like C++ is for coding purists.....which is not me! Anyway, a quick question. What is the ampersand for in function calls? I thought it denoted the 'out' parameters? However your example confirms I'm incorrect? Thanks. – Captain Planet Oct 25 '13 at 20:09
  • Ah, languages with GC. :) The followup question sounds better suited for a new question or a different stack exchange site, but here's the short version. Ampersand can be two different things that both implement pass-by-reference semantics. On the calling end, it means pass the address of the variable, and *is* typically used for 'out' parameters. On the receiving end, it means reference, and is typically as a syntactic sugar variant of passing the address where neither caller or remaining code need `&` or `*`. – Michael Urman Oct 25 '13 at 21:20