
Best Answer deramor , 30 December 2016 - 01:45
I have good news.
The reason I was getting the 267 error was due to when the CA was scheduled.
From a scheduling perspective, the new rows to the directory table must be made before Costing starts.
Setting the values for those new entries must happen after Costing ends.
A summary of my implementation is:
CA1 is in the Execute Sequence, Synchronous, Immediate, Before Cost Init.
Given a list of folders, it creates directory table entries using MsiDatabaseOpenView and MsiViewModify
CA2 is also in the Execute Sequence, Synchronous, Immediate, After Cost Finalize.
Given the same list of folders, assigns a value to each of the new directory table entries.
Then creates DuplicateFile table entries with each of those DirectoryTable entries using MsiDatabaseOpenView and MsiViewModify.
Sample code for those interested is:
CA1
Given a list of folder values stored in lPaths list.
// Get a handle to the MSI hDatabase = MsiGetActiveDatabase(hMSI); nListResult = ListGetFirstString(lPaths, svString); i = 1; while (nListResult != END_OF_LIST) NumToStr(svTempNumber, i); svDirectoryKey = "DIRECTORYKEY" + svTempNumber; sQuery = "SELECT * FROM `Directory`"; nResult = MsiDatabaseOpenView(hDatabase, sQuery, hDirectoryView); ////////////////////////////////////////////////////////////////// // Add record svDirectoryKey to the directory table hRecord = MsiCreateRecord(3); // Column 1 Directory nResult = MsiRecordSetString( hRecord, 1, svDirectoryKey); // Column 2 Directory Parent nResult = MsiRecordSetString( hRecord, 2, "TARGETDIR"); // Column 3 Default Directory nResult = MsiRecordSetString( hRecord, 3, "DIRECT~" + svTempNumber + "|DIRECTORYKEY" + svTempNumber); // Add the new record to the table nResult = MsiViewModify(hDirectoryView, MSIMODIFY_INSERT_TEMPORARY, hRecord); MsiCloseHandle (hRecord); MsiViewClose (hDirectoryView); i++; nListResult = ListGetNextString(lPaths, svString); endwhile; MsiCloseHandle (hDatabase); ListDestroy (lPaths);
CA2
Given a list of folder values stored in lPaths list.
// Get a handle to the MSI hDatabase = MsiGetActiveDatabase(hMSI); nListResult = ListGetFirstString(lPaths, svString); i = 1; while (nListResult != END_OF_LIST) NumToStr(svTempNumber, i); svDirectoryKey = "DIRECTORYKEY" + svTempNumber; // Set the directory table entry to the path in the list. nResult = MsiSetTargetPath( hMSI, svDirectoryKey, svString ); ////////////////////////////////////////////////////////////////// // Now wright the duplicate file table entry. sQuery = "SELECT * FROM `DuplicateFile`"; nResult = MsiDatabaseOpenView(hDatabase, sQuery, hDuplicateView); hRecord = MsiCreateRecord(5); NumToStr(svFileKeyModifier, i); svFileKey = "DuplicateFile" + svFileKeyModifier; nResult = MsiRecordSetString( hRecord, 1, svFileKey ); nResult = MsiRecordSetString( hRecord, 2, "<THE COMPONENT TO USE AS A TRIGGER>" ); nResult = MsiRecordSetString( hRecord, 3, "<YOUR FILE KEY HERE>" ); nResult = MsiRecordSetString( hRecord, 4, "" ); nResult = MsiRecordSetString( hRecord, 5, svDirectoryKey ); // Write the updated row nResult = MsiViewModify(hDuplicateView, MSIMODIFY_INSERT_TEMPORARY, hRecord); MsiCloseHandle (hRecord); MsiViewClose (hDuplicateView); i++; nListResult = ListGetNextString(lPaths, svString); endwhile; MsiCloseHandle (hDatabase); ListDestroy (lPaths);
It is important to note that I also needed to implement Stephan's suggested change to my Settings.xml file.
I added <DuplicateFile MSI="Keep" MSM="Keep"/> to the section <EmptyTableDisposition MSI="Drop" MSM="Drop">
I suppose I could have alternatively just changed the defaults to Keep and Keep but I would rather not change things do dramatically.
Lastly, I had to make sure both the Directory table edits and the DuplicateFIle table edits were made on both install and uninstall. If not uninstall, the duplicate files would be orphaned.
The only limitation here is if the list of locations become shorter between install and removal, some files will not get removed.
I see no way around this at present but I don't think this is a show stopper and can be handled in documentation.
Go to the full post