How to determine if an MSI patch (.msp file) has been applied using C++?
Ok, so I need to determine if a patch has been applied to an MSI. Lets start with Enumerating the installed products and enumerating all the patches applied for each installed product.
I guess the title should be “How to enumerate installed MSI products and their applied MSP patches.”
I have to do it in C++, which is a drag because it looked like three lines of code in C#, but hey, maybe it isn’t so hard with C++ using .NET as well.
I researched on MSDN, of course. It looks like I need to use this function: MsiGetPatchInfoEx. However, I need to know the MSI GUID in order to use that function, so I might as well learn to use the MsiEnumProducts, MsiGetProductInfo, MsiEnumPatches to match the Product to an MSI Guid and that to a patch.
Creating the Project
- I created a new Project in Visual Studio to test this out. The project type I used was under C++ and is called Win32 Console application.
- I didn’t make any changes to the default code provided: targetver.h, stafx.h, stafx.cpp.
- Make sure you have the Platform SDK installed for the next step.
- I went to the project properties and went to Linker | Inpuut and added to Additional Dependencies the following line:
1
"$(WindowsSdkDir)Lib\msi.lib"
- I wrote my code.
Learning the Code
So here is what the code I wrote in this little learning project will do:
- Create a list or
vector
to store eachMSIProduct
. - Loop through each installed MSIs using the
MsiEnumProducts
function and for each installed MSI: - Get MSI information using
MSIProductInfo
. - Create an
MSIProduct
object using the information fromMSIProductInfo
and add theMSIProduct
to the list orvector
. - Write to standard output the MSI count (as Id), the MSI name, and the MSI Guid.
- Create a list or
vector
to store eachMSIPatch
. - Check if any patches or MSPs are applied to the MSI and for each patch:
- Get MSP information using
MSIPatchInfoEx
. - Create an
MSIPatch
object using the information fromMSIPatchInfoEx
and add theMSIPatch
to this list orvector
. - Write to standard output the MSP Guid.
Here is my code:
Run.cpp
This file does all the work and has the tmain function. It creates a list or vector
of MSIProduct
objects and then uses MsiEnumProducts and MsiGetProductInfo to create and add each MSIProduct
to the vector
. It also loops through each of the MSIProduct
‘s and find any installed patches. It adds each patch found to the MSIProduct
‘s _Patches
vector
.
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | // Run.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "windows.h" #include "Msi.h" #include "MSIProduct.h" // Includes MSIBase.h and MSIPatch.h as well #include <iostream> #include <vector> using namespace std; #define MYSIZE 512 int _tmain( int argc, _TCHAR* argv[]) { // Step 1. Create a list or vector to store each MSIProduct. vector<MSIProduct> *products = new vector<MSIProduct>(); // Step 2. Loop through each installed MSIs using the MsiEnumProducts // function and for each installed MSI: int i = 0; bool foundMoreApps = true ; while (foundMoreApps) { DWORD size = MYSIZE; LPTSTR tmpGuid = new TCHAR [MYSIZE]; LPTSTR tmpName = new TCHAR [MYSIZE]; UINT ret1 = MsiEnumProducts(i, tmpGuid); if (ret1 > 0) { foundMoreApps = false ; continue ; } // Step 3. Get MSI information using MSIProductInfo. UINT ret2 = MsiGetProductInfo(tmpGuid, INSTALLPROPERTY_PRODUCTNAME, tmpName, &size); if (ret2 > 0) { // Todo: Handle failure } // Step 4. Create an MSIProduct object using the information from MSIProductInfo // and add the MSIProduct to the list or vector. products->push_back(MSIProduct()); products->at(i).SetName(tmpName); products->at(i).SetGuid(tmpGuid); // Step 5. Write to standard output the MSI count (as Id), the MSI name, and the MSI Guid. cout << endl; cout << "Id: " << i << endl; wcout << "Product: " << tmpName << endl; wcout << "Guid: " << tmpGuid << endl; cout << "Patches: " ; // Step 6. Create a list or vector to store each MSIPatch. vector<MSIPatch> *patches = new vector<MSIPatch>(); products->at(i).SetPatches(patches); // Step 7. Check if any patches or MSPs are applied to the MSI and for each patch: int j = 0; bool foundMorePatches = true ; while (foundMorePatches) { DWORD size = MYSIZE; LPTSTR tmpPatchGuid = new TCHAR [MYSIZE]; LPTSTR tmpPatchState = new TCHAR [MYSIZE]; LPTSTR tmpPatchTransforms = new TCHAR [MYSIZE]; UINT retPatch1 = MsiEnumPatches(tmpGuid, j, tmpPatchGuid, tmpPatchTransforms, &size); if (retPatch1 > 0) { cout << "(" << retPatch1 << ") :" << endl; foundMorePatches = false ; continue ; } // These values correspond to the constants the dwFilter parameter // of MsiEnumPatchesEx uses. // Step 8. Get MSP information using MSIPatchInfoEx. UINT retPatch2 = MsiGetPatchInfoEx(tmpPatchGuid, tmpGuid, NULL, MSIINSTALLCONTEXT_MACHINE, INSTALLPROPERTY_PATCHSTATE, tmpPatchState, &size); // Returns "1" if this patch is currently applied to the product. // Returns "2" if this patch is superseded by another patch. // Returns "4" if this patch is obsolete. if (retPatch2 > 0) { // Todo: Handle failure } // Step 9. Create an MSIPatch object using the information from MSIPatchInfoEx // and add the MSIPatch to this list or vector. patches->push_back(MSIPatch()); patches->at(j).SetPatchState(tmpPatchState); patches->at(j).SetGuid(tmpPatchGuid); patches->at(j).SetTransforms(tmpPatchTransforms); // Step 9. Write to standard output the MSP Guid. wcout << "\t" << "Patch Guid: " << tmpPatchGuid << endl; j++; } i++; } } [/sourcecode] I did create some simple supporting classes for this : <strong>MSIBase.h</strong> [sourcecode language= "cpp" ] #pragma once #include "windows.h" class MSIBase { public : // Constructor MSIBase( void ); // Destructor virtual ~MSIBase( void ); // Accessor functions LPTSTR GetName(); void SetName( LPTSTR inName); LPTSTR GetGuid(); void SetGuid( LPTSTR inGuid); protected : LPTSTR _Guid; LPTSTR _Name; }; |
MSIBase.cpp
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include "StdAfx.h" #include "MSIBase.h" MSIBase::MSIBase( void ) { } MSIBase::~MSIBase( void ) { } // Accessor functions LPTSTR MSIBase::GetName() { return _Name; } void MSIBase::SetName( LPTSTR inName) { _Name = inName; } LPTSTR MSIBase::GetGuid() { return _Guid; } void MSIBase::SetGuid( LPTSTR inGuid) { _Guid = inGuid; } |
MSIProduct.h
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | #include "MSIBase.h" #include "MSIPatch.h" #include <vector> #pragma once class MSIProduct : public MSIBase { public : MSIProduct( void ); ~MSIProduct( void ); std::vector<MSIPatch> GetPatches(); void SetPatches(std::vector<MSIPatch> * inPatches); void AddPatch(MSIPatch inPatch); protected : std::vector<MSIPatch> * _Patches; }; |
MSIProduct.cpp
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include "StdAfx.h" #include "MSIProduct.h" MSIProduct::MSIProduct( void ) { } MSIProduct::~MSIProduct( void ) { delete _Patches; } std::vector<MSIPatch> MSIProduct::GetPatches() { return * _Patches; } void MSIProduct::SetPatches(std::vector<MSIPatch> * inPatches) { _Patches = inPatches; } void MSIProduct::AddPatch(MSIPatch inPatch) { _Patches->push_back(inPatch); } |
MSIPatch.h
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | #pragma once #include "MSIBase.h" class MSIPatch : public MSIBase { public : MSIPatch( void ); ~MSIPatch( void ); LPTSTR GetTransforms(); void SetTransforms( LPTSTR inTransforms); int GetPatchState(); void SetPatchState( int inPatchState); void SetPatchState( LPTSTR inPatchState); protected : LPTSTR _Transforms; int _PatchState; }; |
MSIPatch.cpp
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include "StdAfx.h" #include "MSIPatch.h" MSIPatch::MSIPatch( void ) { } MSIPatch::~MSIPatch( void ) { } LPTSTR MSIPatch::GetTransforms() { return _Transforms; } void MSIPatch::SetTransforms( LPTSTR inTransforms) { _Transforms = inTransforms; } int MSIPatch::GetPatchState() { return _PatchState; } void MSIPatch::SetPatchState( int inPatchState) { _PatchState = inPatchState; } void MSIPatch::SetPatchState( LPTSTR inPatchState) { _PatchState = _wtoi(inPatchState); } |
Sorry, I am not explaining in more detail, my time is limited.
Note: I found one problem where an application has a ™ in the name. (Skype™ 4.2) and the output doesn’t work well after that.
Copyright ® Rhyous.com – Linking to this article is allowed without permission and as many as ten lines of this article can be used along with this link. Any other use of this article is allowed only by permission of Rhyous.com.
koreanamericandaily.com
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
yacht.rit.edu
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
carnegiecouncil.org
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
Australian Kids Clothing Size Chart
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
mybedshop.com
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
just click Storenvy.com
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
diy.com projects
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
sofas
How to determine if an MSI patch (.msp file) has been applied using C++? | Rhyous
[...] already have a C++ example of doing this, but that isn’t much help when you have to do it in C#. So it is good to know how to do this [...]