Can someone help me with some patch detection code...
Hi there,
This isn't really directly related to InstallShield, but I hope someone can help me out.
Years ago I posted to see how I can detect if a patch has been applied on a particular machine. We have an update utility that will fire a Myapp.msp if it is detected in a particular folder. What is happening is that everytime the file is detected it reapplies the patch. I would like to check if the patch has been applied and only do so if absent.
I received a reply with this information...
"Have your app query the Revision Number of the summary information stream of
your MSP file to get the patch's GUID. Then use MsiEnumPatchesEx (or
minimum MsiEnumPatches) to check if patch is on the machine.
If it is not on the machine you could also check that the MSP is applicable
by using MsiDeterminePatchSequence or MsiDetermineApplicablePatches. The
idea is that with patch sequencing an MSP could be superseded by a different
MSP already on the machine. Thus applying the so called "new" patch even
though it is not installed locally (MsiEnumPatchesEx returns not found)
would result in a redundant installation."
The utility is written in some form of C and I'm a VB.Net guy, however I would still need help with MsiEnumPatches or MsiEnumPatchesEx. Here's the current code for firing the patch...
if (GetFileAttributes(m_ServerUpdateFolder + "MyPatch.msp") != -1)
{
LogMsg.Format("Running %sMyPatch.msp", m_ServerUpdateFolder);
m_LogTrace.WriteLine(LogMsg);
CmdLine.Format("msiexec /qn /p \"%sMyPatch.msp\"", m_ServerUpdateFolder);
RunProcessAndWait(CmdLine, &dwThreadRtnValue);
if (dwThreadRtnValue == 0)
{
m_LogTrace.WriteLine("\tClient Patch successfully or previously applied!");
m_LogTrace.WriteLine("******************************************");
m_LogTrace.WriteLine("Log Trace ended %s\n", COleDateTime::GetCurrentTime().Format());
}
else
{
m_LogTrace.WriteLine("\tAn error occurred while applying the Client patch: %d!", dwThreadRtnValue);
m_LogTrace.WriteLine("\tPossible causes: Patch target not installed or patch no longer applicable.");
m_LogTrace.WriteLine("******************************************");
m_LogTrace.WriteLine("Log Trace ended %s\n", COleDateTime::GetCurrentTime().Format());
}
}
else
{
m_LogTrace.WriteLine("No Client patch found in update location!");
m_LogTrace.WriteLine("******************************************");
m_LogTrace.WriteLine("Log Trace ended %s\n", COleDateTime::GetCurrentTime().Format());
}
What I would like to do is, if a patch is detected, grab any needed code and determine if it is applied. If not, run it as above.
I guess I would need to grab the ProductCode from the base .msi, which will also be in the update folder, m_ServerUpdateFolder.
Any help with coding this would be greatly appreciated!
Thanks much and sorry if this is way out of bounds for this forum!!
Answers (2)
Here's the original post I had with replies...
http://www.packagedeploy.com/forum/platformsdk-msi/detect-if-patch-has-been-apply-prevent-apply-31/
I guess I need code to enumerate through installed products, get information from the .msp sitting in the update folder, see if the patch was applied to any products. If so, just skip, else fire the patch.
Here's what we ended up with. Seems to work and I hope it helps someone...
Type t = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer iInstaller = (Installer)Activator.CreateInstance(t);
string strPatchPath = null;
string strPatchCode = null;
string strProdCode = null;
string strPatchXML = null;
XmlDocument xmlMsiPatch = new XmlDocument();
if (MinMsiVersion > Convert.ToDouble(iInstaller.Version.Substring(0, iInstaller.Version.IndexOf('.'))))
{
MessageBox.Show("Minimum Windows Installer version " + MinMsiVersion + " required. Current version is " + iInstaller.Version, "Windows Installer version problem...");
}
strPatchPath = "C:\\Program Files (x86)\\Synergis\\Adept80\\Client\\Install\\AdeptPatch.msp";
strPatchXML = iInstaller.ExtractPatchXMLData(strPatchPath);
xmlMsiPatch.LoadXml(strPatchXML);
strPatchCode = xmlMsiPatch.DocumentElement.Attributes["PatchGUID"].Value;
strProdCode = xmlMsiPatch.GetElementsByTagName("TargetProductCode").Item(0).InnerText;
//Now check if patch is applied...
int rtn = 0;
dynamic ePatch = iInstaller.get_Patches(strProdCode);
if (ePatch.count > 0)
{
for (var i = 0; i < ePatch.count; i++)
{
if (ePatch[i] == strPatchCode)
{
MessageBox.Show("here");
rtn = 1;
}
}
}