cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Kevin_Hodgson
Level 5

Basic MSI - Need to detect Word and Excel and ask user to shut them down.

I have a Basic MSI installer that installs an Office COM Add-In, but under certain situations the Add-In isn't correctly registered with Word or Excel if they are running during the installation.

I need some way for the Basic MSI to detect that Word and Excel are running, and then bring up the standard filesinuse dialog asking the user to shut them down before continuing.

On Uninstallation, the MSI correctly notices that Word and/or Excel have the Add-In open, and ask for Word/Excel to be closed before continuing. The problem I'm encountering is initial installation.

Hopefully someone can point me in the right direction.
Labels (1)
0 Kudos
(4) Replies
Kevin_Hodgson
Level 5

I've found a few hints here and there, but I'm now getting an error from the Installation.

This is the error I get as the Install Execution begins.

MSI (s) (00:0C) [21:12:40:287]: Doing action: CheckForOffice
Action 21:12:40: CheckForOffice.
Action start 21:12:40: CheckForOffice.
MSI (s) (00:0C) [21:12:40:290]: Note: 1: 2762
Error 2762.Cannot write script record. Transaction not started.
MSI (s) (00:0C) [21:12:48:849]: Product: Office Add-In -- Error 2762.Cannot write script record. Transaction not started.

Action ended 21:12:48: CheckForOffice. Return value 3.
Action ended 21:12:48: INSTALL. Return value 3.

I've created a Deferred in System Context Custom Action that executes the following script. It's sequenced to run in the Install Exec sequence right before the InstallValidate action. It's intended to find if WinWord, Excel or Outlook are running, and add them to the FilesInUse list if they are. This is necessary because the Office Add-In we are installing does not install correctly if Word, Excel or Outlook (using Word as it's mail editor) are running during the installation.

'Look for Excel
sProcessName = "excel.exe"
strComputer = "localhost"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer _
& "\root\cimv2")

Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where " _
& "Name = '"& sProcessName & "'")

if colProcessList.count > 0 then
For Each objProcess in colProcessList
Set myrec = Installer.CreateRecord(2)
myRec.StringData(1) = objProcess.Name
myRec.IntegerData(2) = objProcess.ProcessID
Session.Message &H050000000, myrec
Next
end if

'Look for Outlook
sProcessName = "outlook.exe"
strComputer = "localhost"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer _
& "\root\cimv2")

Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where " _
& "Name = '"& sProcessName & "'")

if colProcessList.count > 0 then
For Each objProcess in colProcessList
Set myrec = Installer.CreateRecord(2)
myRec.StringData(1) = objProcess.Name
myRec.IntegerData(2) = objProcess.ProcessID
Session.Message &H050000000, myrec
Next
end if

'Look for Word
sProcessName = "winword.exe"
strComputer = "localhost"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer _
& "\root\cimv2")

Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where " _
& "Name = '"& sProcessName & "'")

if colProcessList.count > 0 then
For Each objProcess in colProcessList
Set myrec = Installer.CreateRecord(2)
myRec.StringData(1) = objProcess.Name
myRec.IntegerData(2) = objProcess.ProcessID
Session.Message &H050000000, myrec
Next
end if
0 Kudos
RobertDickau
Flexera Alumni

At least regarding "Error 2762. Cannot write script record", a deferred action needs to be between InstallInitialize and -Finalize...

Calling Session.Message or MsiProcessMessage with INSTALLMESSAGE_FILESINUSE or INSTALLMESSAGE_RMFILESINUSE (during immediate mode, however) might help, too.
0 Kudos
Kevin_Hodgson
Level 5

RobertDickau wrote:
At least regarding "Error 2762. Cannot write script record", a deferred action needs to be between InstallInitialize and -Finalize...

Calling Session.Message or MsiProcessMessage with INSTALLMESSAGE_FILESINUSE or INSTALLMESSAGE_RMFILESINUSE (during immediate mode, however) might help, too.


Hi Robert.
It was my understanding that you need to add Processes to the FILESINUSE list before InstallValidate, which is sequenced before InstallInitialize.
I moved the CA to after InstallInitialize, and I don't get the error anymore, but I also don't get the FilesInUse Dialog.

I'm not sure how to create the Session.Message Custom Action. This seems like a fairly common need, I just wish there were more (any) concrete examples of how to do this.
0 Kudos
Kevin_Hodgson
Level 5

I've split this up into a couple of different parts, but I'm still not getting quite what I want.

I've split off a new Search Custom Action that looks for Word, Excel or Outlook currently running. I've got it setting properties if it finds them. (Eg. WORDRUNNING, WORDNAME, WORDPID).

WORDRUNNING contains a value if winword.exe is detected in the process list, otherwise it's NULL
WORDNAME contains the Name of the detected Winword process.
WORDPID contains the ProcessID of the detected Winword process.
The nine Public Properties (three for each of Word, Excel and Outlook) are added to the SecureCustomProperties list so that they'll still be available during deferred execution.
This is a VBScript custom action that runs after APPSEARCH as an Immediate Execution (Terminal Server Aware). When debugging I can see that all the properties are set.

However, I'm not quite sure what to do with them to get the FilesInUse Dialog to appear. I'm unclear on how to use the Session.Message or MsiProcessMessage to populate the FilesInUse Dialog with the 1,2 or 3 processes that have been detected, and how to sequence it. I'm fairly certain it should be in the Execute Sequence as a Deferred Action.

Any guidance, or a script example of how to use Session.Message to update the FilesInUse/RMFilesInUse dialog would be appreciated.
0 Kudos