cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Sairen
Level 7

Unwanted patch cache

As you might guess, I've got this installer. 😄 It's a Basic MSI installer, and we're on about the 6th major version of it. So it's been around awhile, pretty stable. We wrap the MSI in Setup.exe and distribute it like that.

We do major upgrades when changing the 1st or 2nd version number, and for everything else, including daily builds, it's updating according to the rules of a minor upgrade. We have never put out patches for this product.

Today, I had a few people tell me that a particular exe we distribute wasn't updating properly. I found this in their log file:

Source for file 'filemonitor.exe.0BC73C49_D315_4459_BD9C_12CAEDE59903' is uncompressed, at 'C:\Windows\Installer\$PatchCache$\Managed\3382210BEFD77CD419638F493C5C259C\6.5.0\'.

Versus this in a log file from a machine I tested, working Source for file 'filemonitor.exe.0BC73C49_D315_4459_BD9C_12CAEDE59903' is compressed

In both cases, the values for the "minor upgrade variables" -- my phrasing -- are the same:

Command Line: REINSTALL=ALL REINSTALLMODE=vomus IS_MINOR_UPGRADE=1
I also searched the rest of the log, and REINSTALLMODE does not change values later on.

I have several questions, in descending importance, though some might be intertwined...
1) How do I fix these machines so that the next time they update, it fetches the file from the installer package and not this cached machine. Is it safe to delete the folder structure under $PatchCache$?
2) How do I stop it (the machine? the installer?) from creating this patch cache again?
3) Why did it create a patch cache for this product when we've never put out a patch?

Thank you for any insight into this behavior you might have!
Labels (1)
0 Kudos

(3) Replies
Sairen
Level 7

We discovered that there are a handful of files being cached, most of which belong to Microsoft-created merge modules. For the two of ours being cached, one was a versioned executable, and the other was a font. If we renamed those two files, they did get updated the next time we did a minor upgrade. Hurray! The executable was NOT recached, but the font was.
More answers to that would be lovely, but I just wanted to provide some additional information.
Can anyone think why this is being created or why this files are being cached? Again, we have never released a patch for this product.
0 Kudos
Sairen
Level 7

Me again!

Imagine my surprise when, looking for answers to this mysterious new problem, I find a question from... myself! Seeing this again. Same basic idea.

A small handful of files, almost always from a merge module, end up in this Patch Cache. When my users do a minor upgrade, the source is that Patch Cache folder. They get old files, and product errors ensue.

And once again, we've never released patches. Anyone know why these files might be ending up here? Wild guesses welcome at this point!

Thanks -
0 Kudos
TimoZimmermann
Level 5

I have some systems where I have the same problem, but I'm unable te reproduce this behaviour.:confused:
So I don't know what the reason is that the installer copies some files into the patchcache although it wasn't a patch but a minor upgrade.

My actual solution is, that I wrote a custom action which deletes the corresponding files in the patchcache.
It is sequenced in the execute sequence after PrewentDowngrade with the condition IS_MINOR_UPGRADE=1

Does anybody have more Information about this or another solution for this?



///////////////////////////////////////////////////////////////////////////////
//
// Function: CleanPatchCache
//
// Purpose: delete files in corresponding patchcache folder
// (T.Zimmermann 14.11.2013)
///////////////////////////////////////////////////////////////////////////////
function CleanPatchCache(hMSI)
STRING svCacheFolder, svMatchingFileName, svFileSpec;
NUMBER nResult;
LIST listFiles;
HWND hRecord;
begin

try

//get PatchCache folder for actual product
svCacheFolder = WINDIR ^ "Installer\\$PatchCache$\\Managed" ^ CompressedGUID(PRODUCT_GUID);
SprintfMsiLog("PatchCache Folder: %s", svCacheFolder);

//find all exe and dll files in it
listFiles = ListCreate (STRINGLIST);
if listFiles = LIST_NULL then
SprintfMsiLog("Unable to create list.");
else

//first find exe files
svFileSpec = "*.exe";

//iterate through all subfolders
nResult = FindAllFiles (svCacheFolder, svFileSpec, svMatchingFileName, RESET);
while(nResult = 0)
// Add the file to the list.
if ListAddString (listFiles, svMatchingFileName, AFTER) < 0 then
SprintfMsiLog("Unable to build complete file list");
endif;

// Find the next matching file name.
nResult = FindAllFiles(svCacheFolder, svFileSpec, svMatchingFileName, CONTINUE);
endwhile;


// Free all files and folders accessed by FindAllFiles. If your
// setup does not target the Windows NT platform, this step is
// not necessary.
FindAllFiles(svCacheFolder, svFileSpec, svMatchingFileName, CANCEL);

//then find dll files
svFileSpec = "*.dll";

//iterate through all subfolders
nResult = FindAllFiles (svCacheFolder, svFileSpec, svMatchingFileName, RESET);
while(nResult = 0)
// Add the file to the list.
if ListAddString (listFiles, svMatchingFileName, AFTER) < 0 then
SprintfMsiLog("Unable to build complete file list");
endif;

// Find the next matching file name.
nResult = FindAllFiles(svCacheFolder, svFileSpec, svMatchingFileName, CONTINUE);
endwhile;


// Free all files and folders accessed by FindAllFiles. If your
// setup does not target the Windows NT platform, this step is
// not necessary.
FindAllFiles(svCacheFolder, svFileSpec, svMatchingFileName, CANCEL);



// Get the first file from the list.
nResult = ListGetFirstString (listFiles, svMatchingFileName);

// Loop while not at end of list.
while (nResult != END_OF_LIST)

SetFileInfo(svMatchingFileName, FILE_ATTRIBUTE, FILE_ATTR_NORMAL,"");
DeleteFile(svMatchingFileName);
SprintfMsiLog("CachedFile deleted: %s", svMatchingFileName);

// Get the next file from the list.
nResult = ListGetNextString (listFiles, svMatchingFileName);

endwhile;


// Remove the list from memory.
ListDestroy(listFiles);

endif;

catch
//Log it in the event
hRecord = MsiCreateRecord(1);
MsiRecordSetString(hRecord,0,"CleanPatchCache failed: " + svCacheFolder);
MsiProcessMessage(hMSI, INSTALLMESSAGE_INFO, hRecord);

MsiCloseHandle(hRecord);

endcatch;

end;


//reference: http://kb.flexerasoftware.com/selfservice/viewContent.do?externalID=Q105971
///////////////////////////////////////////////////////////////////////////////
//
// Function: CompressedGUID
//
// Purpose: Converts original GUID to Compressed GUID. (as stored in registry)
// (T.Zimmermann 14.11.2013)
//
// param name=szOriginal GUID to be compressed.
// returns compressed guid.
// Example: szReturnValue = CompressedGUID("{EAFD321F-7441-49F7-845F-162AFE9A9E89}");
//
///////////////////////////////////////////////////////////////////////////////
function string CompressedGUID(szOriginal)
STRING szCompressed;
STRING szSub;
STRING szReturn;

begin
szCompressed = szOriginal;
StrReplace(szCompressed,"{","",0);
StrReplace(szCompressed,"-","",0);
StrReplace(szCompressed,"}","",0);
StrSub(szSub, szCompressed,0,8);
szReturn = ReverseString(szSub);

StrSub(szSub, szCompressed,8,4);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,12,4);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,16,2);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,18,2);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,20,2);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,22,2);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,24,2);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,26,2);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,28,2);
szReturn = szReturn + ReverseString(szSub);

StrSub(szSub, szCompressed,30,2);
szReturn = szReturn + ReverseString(szSub);
return szReturn;
end;
0 Kudos