2

How to know the property list contained an MSI file?

If we know the property name, we can get property value for a specific property. we can use the following codes:

WCHAR wzBuf[MAX_PATH+1]=L"";
DWORD dw=_countof(wzBuf);
    fGoodPath = ( ERROR_SUCCESS == ::MsiGetPropertyW(hInstall, L"INSTALLLOCATION", wzBuf, &dw) );

Just wondering how can we know all the property names defined in MSI/MSP files?

Gufran Hasan
  • 8,910
  • 7
  • 38
  • 51
seeker
  • 23
  • 3
  • 1
    You can't, not really. There are properties that come from the system (like Stein links to), properties listed in the Property table of your MSI, and ones passed in or set at run time by various built-in or custom actions. Take a verbose log to see the list at the end, but know that any run-time code could behave differently on a different system. What are you trying to do? – Michael Urman Jul 17 '19 at 01:44
  • Thank you for the answer. Please check my correction below. – seeker Jul 17 '19 at 04:04
  • Found some C++ code, have a look and see if it does the job? Also added a VBScript answer. – Stein Åsmul Jul 17 '19 at 12:31

2 Answers2

1

SDK Documentation: I would try these documented ones from the MSI SDK first.

SDK Sources: There is also the msi.h header file from the SDK. Seeing as you have Visual Studio installed, just right-click the include entry and go "Open Document <msi.h>". You can also find it on github.com (here and there). Try searching for "INSTALLPROPERTY_PACKAGECODE" or some other documented property in msi.h:

Sample:

#define INSTALLPROPERTY_PACKAGECODE           __TEXT("PackageCode")
#define INSTALLPROPERTY_VERSION               __TEXT("Version")
#if (_WIN32_MSI >=  110)
#define INSTALLPROPERTY_PRODUCTICON           __TEXT("ProductIcon")

...

Etc... Not sure if this is what you asked for exactly?


Links:

VBScript, built-in MSI properties: from this old answer, a list of VBScript accessible properties:

ProductCode, Language, ProductName, PackageCode, Transforms, AssignmentType, PackageName, InstalledProductName, VersionString, RegCompany, RegOwner, ProductID, ProductIcon, InstallLocation, InstallSource, InstallDate, Publisher, LocalPackage, HelpLink, HelpTelephone, URLInfoAbout, URLUpdateInfo

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
1

Github.com: VBScript sample from github.com: PullMSPOfficeUpdates.vbs which is recommended to check. Iterates patches. A "canned" github search.

Basic Sample: Here is a trimmed down sample which gets the Patch Code from an MSP. Sorry for no C++, but I am too rusty and not enough time (maybe add your own answer and set that accepted as C++ - hint: just edit your current one, it is more of a comment as it stands - prefer to edit your original answer or comment it - just the approach generally used here):

Const MSIOPENDATABASEMODE_PATCHFILE = 32
Const MSIPID_REVNUMBER = 7

Set installer = CreateObject("WindowsInstaller.Installer")
Set msp = installer.OpenDatabase("C:\MyPath.msp", MSIOPENDATABASEMODE_PATCHFILE)
Set summaryinfo = msp.SummaryInformation

MsgBox summaryinfo.Property(MSIPID_REVNUMBER)

UPDATE: I am not a C++ developer, but with some help from Installshield's Michael Urman, I think this C++ sample should work with Visual Studio 2017 at least. Please don't be too picky about the actual C++ constructs, use github.com to find more samples (canned search sample - just for others and myself in the future, I know you don't need it):

#include "pch.h"

#define WIN32_LEAN_AND_MEAN

#include <atlstr.h> // CString support from ATL
#include <Msiquery.h>

#pragma comment(lib, "msi.lib") // to allow linking

int main()
{
    CString lpszFilename = L"C:\\YourPatchFile.msp";

    PMSIHANDLE hSum;
    DWORD dwErr = MsiGetSummaryInformation(0, lpszFilename, 0, &hSum);
    if (ERROR_SUCCESS == dwErr)
    {
        UINT uiProperty = 7;
        UINT uiDataType = 0;
        INT iValue = 0;
        FILETIME ftValue = { 0 };
        CString sValue;
        DWORD cchValue = MAX_PATH;

        dwErr = MsiSummaryInfoGetProperty(hSum, uiProperty, &uiDataType, &iValue, &ftValue, (LPWSTR)sValue.GetString(), &cchValue);

        MessageBox(NULL, sValue, L"Patch Code:", MB_OK);
    }

   MsiCloseHandle(hSum);
   return 0;
}

Testing: 1) Create new C++ console project in Visual Studio, 2) Paste the above code to the new project's main "ConsoleApplicationX.cpp" file (where X is a number) - replacing whatever is there, 3) Adjust the path to your MSP file (CString lpszFilename = L"C:\\YourPatchFile.msp";), 4) Say out loud: "fire in the hole" and hope for the best :-).

MSI API Documentation: Here are some links:

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • Epic! Really appreciated your help with detailed guidance!! – seeker Jul 18 '19 at 11:20
  • No problem - glad you liked it. On another note: C++ really is clunky isn't it? Compared to modern scripting? At least it is fast and reliable and "down to the metal" (no layers to depend upon). – Stein Åsmul Jul 18 '19 at 12:03