Jump to content


This is a ready-only archive of the InstallSite Forum. You cannot post any new content here. / Dies ist ein Archiv des InstallSite Forums. Hier können keine neuen Beiträge veröffentlicht werden.
Photo

Backup/restore files on install/uninstall


5 replies to this topic

gregg1ep00

gregg1ep00
  • Full Members
  • 3 posts

Posted 12 October 2010 - 22:59

Greetings everyone,

I am attempting to author an InstallShield Basic MSI installer that will overwrite some program files on the filesystem. Here's what I need to do:

On installation:
  1. Backup a list of files
  2. Overwrite the target files with those in my installer

Then, on uninstallation:
  1. Uninstall the files installed in step 2 above
  2. Restore the files backed up in step 1 above


I'm very inexperienced with Custom Actions and placing them correctly in the Exec sequence. I currently have the following custom action defined to backup the components:

CODE

function BackupComponents(hMSI)

STRING sInstallDir;
NUMBER nSize, nResult;
STRING sBackupDir, sSourceDir, sTargetDir;
STRING saDir(), saFile();
NUMBER i, nCount;

begin

MsiGetProperty(hMSI, "INSTALLDIR", sInstallDir, nSize);  

// Define our files to backup
nCount = 2;
Resize( saDir, nCount );
Resize( saFile, nCount );

sBackupDir = "BACKUP";
saDir(0) = "Subdir1\\Lib";
saFile(0) = "File1.dll";
saDir(1) = "Subdir1\\Lib";
saFile(1) = "File2.dll";

// Loop through the files and make backups
for i = 0 to (nCount - 1)
 sSourceDir = sInstallDir ^ saDir(i);
 sTargetDir = sInstallDir ^ sBackupDir ^ saDir(i);
 nResult = CopyFile( sSourceDir ^ saFile(i), sTargetDir ^ saFile(i) );
 if ( nResult != 0 ) then
  SprintfMsiLog( "Error copying %s to %s: %d", sSourceDir ^ saFile(i), sTargetDir, nResult );
 else
  nResult = SetFileInfo( sSourceDir ^ saFile(i), FILE_ATTRIBUTE, FILE_ATTR_NORMAL, "" );
 endif;
endfor;
end;  


The backup CA is currently working properly. I cannot get the restore CA to work at all. Here's what I have:

CODE

function RestoreComponents(hMSI)

STRING sInstallDir;
NUMBER nSize, nResult;
STRING sBackupDir, sSourceDir, sTargetDir;
STRING saDir(), saFile();
NUMBER i, nCount;
STRING sDllToReg;
STRING sCustomActionData;

begin

MsiSetProperty(hMSI, "ALLUSERS", "1");
MsiGetProperty(hMSI, "CustomActionData", sCustomActionData, nSize);
MsiGetProperty(hMSI, "INSTALLDIR", sInstallDir, nSize);

MessageBox("CA Data = " + sCustomActionData, INFORMATION);
MessageBox("INSTALLDIR = " + sInstallDir, INFORMATION);

// Define our files to backup
nCount = 2;
Resize( saDir, nCount );
Resize( saFile, nCount );

sBackupDir = "BACKUP";
saDir(0) = "Subdir1\\Lib";
saFile(0) = "File1.dll";
saDir(1) = "Subdir1\\Lib";
saFile(1) = "File2.dll";

// Stop services
StopMyServices(hMSI);

// Loop through the files and make backups
for i = 0 to (nCount - 1)
 sTargetDir = sInstallDir ^ saDir(i);
 sSourceDir = sInstallDir ^ sBackupDir ^ saDir(i);
 nResult = CopyFile( sSourceDir ^ saFile(i), sTargetDir ^ saFile(i) );
 if ( nResult != 0 ) then
  SprintfMsiLog( "Error copying %s to %s: %d", sSourceDir ^ saFile(i), sTargetDir, nResult );
 endif;
endfor;

DeleteDir( sInstallDir ^ sBackupDir, ALLCONTENTS );

// Now re-register the old dll's
sDllToReg = sInstallDir ^ saDir(0) ^ saFile(0);
LaunchAppAndWait( WINSYSDIR ^ "regsvr32.exe", "/s /c \"" + sDllToReg + "\"", LAAW_OPTION_WAIT | LAAW_OPTION_HIDDEN );

sDllToReg = sInstallDir ^ saDir(5) ^ saFile(5);
LaunchAppAndWait( WINSYSDIR ^ "regsvr32.exe", "/s /c \"" + sDllToReg + "\"", LAAW_OPTION_WAIT | LAAW_OPTION_HIDDEN );
end;  


At first, I tried setting the restore CA for immediate execution after SelfRegModules, which didn't work. Then I tried setting it for rollback execution in system context after UnregisterProgIdInfo and that didn't work either. I tried to set a property called RESTORECOMPONENTS earlier in the installation process, thinking I could access CustomActionData, but that doesn't seem to be working either.

Can anyone help me?

Thanks in advance,
Greg

MSIYER

MSIYER
  • Full Members
  • 90 posts

Posted 13 October 2010 - 08:57

You have to configure the CA to run on uninstall. For that you need to check if the user has triggered an uninstall(in any of the many ways possible), and run your CA.

REMOVE , for example, is a property that is set when uninstallation happens. You can check for this property.

If REMOVE="ALL" run your CA. Please look at the attachment to have a better grasp.
Also follow this url for further details:
http://msdn.microsoft.com/en-us/library/aa371194(VS.85).aspx

Attached Images

  • ConditioningCAs.GIF

Edited by MSIYER, 13 October 2010 - 08:58.


gregg1ep00

gregg1ep00
  • Full Members
  • 3 posts

Posted 14 October 2010 - 05:17

Thanks so much for your response.

I have REMOVE="ALL" in the Install Exec Condition as you list in your example. Also, I placed the CA to execute after InstallFinalize. In-Script Execution is now set back to Immediate Execution.

After running the install/uninstall, it does seem to be running the CA, but it is only replacing some of the files. Not sure if something is running in the background that's preventing the XCopyFile call from happening. I'm not seeing any information in the MSI log. Is the SprintfMsiLog the correct way to write to the log?

jcarlos10

jcarlos10
  • Full Members
  • 13 posts

Posted 19 October 2010 - 23:14

Greg,

Remember that you should always avoid a custom action if you can perform the same functionality using one of the MSI tables. In your case, at least for the Backup part, I think you can substitute the custom action with the MoveFile table, which will allow you to copy or move files that were not installed by your product. Take a look at the documentation here, where you will find the details for populating the table. Remember you will have to use the direct editor view in InstallShield.

For the second custom action, I cannot think of a way to achieve the functionality using tables so you may have to stick to the custom action, especially because you are trying to register DLL files during uninstall (By the way, Were the files you are replacing created by your company? otherwise it may not be a good solution what you are trying to do).

In order to be able to write to the log from an InstallScript custom action, take a look at the following paper, which explains very clearly how to do it:
Writing to the log file from a custom action

And finally I recommend that you set your Restore custom action to run in Deferred mode, which will force you to place it before InstallFinalize, this is because it will be performing actual changes to the system and not just collecting data or something similar. In this case you will have to use CustomActionData to pass the properties to your custom action (INSTALLDIR property will not be available). More details on this here.

I hope you find this information helpful and good luck.

Regards,
Juan C. Becerra

Edited by jcarlos10, 19 October 2010 - 23:17.


gregg1ep00

gregg1ep00
  • Full Members
  • 3 posts

Posted 21 October 2010 - 19:41

Juan, thank you for the response and the detailed instructions. To answer your question, yes these files are created by my company and this installer is being used to patch these files.

One of the issues ended up being that the dll's I was trying to replace had the read-only attribute set, and XCopyFiles was not replacing them. I inserted a call to SetFileInfo to clear the read-only flag and I achieved the desired result.

Currently I have the RestoreComponent CA set for immediate execution right after InstallFinalize and it seems to be working. I'm a little gun-shy about making any changes, although I'm sure what you suggest is the proper way to do things.

Thanks again for your help and the additional documentation.

Greg

jcarlos10

jcarlos10
  • Full Members
  • 13 posts

Posted 22 October 2010 - 19:10

Greg,

I understand how you feel, I've been there before.

However I still recommend you do it. It will surely not give any trouble and your installer will be following better practices.

I also recommend, in case you haven't seen it before, you take a look at the rules here.

Have a great day,
Juan C. Becerra