Showing posts with label InstallScript. Show all posts
Showing posts with label InstallScript. Show all posts

December 14, 2012

Forcefully removing the 'Installation Directory' during uninstallation..

Most frequent defect that is logged against an Application Package is around "the installation directory not deleted during uninstallation" and we all know that based on Windows Installer design, the files / folders that are not created by the installer will not be removed by the installer. But the user would always want a clean system after uninstallatoin :)

So here you go with the approach to remove the installation directory via Direct Editor.

In the following example, I have a Basic MSI Project created using InstallShied 2012 Spring edition and assume that your application would create some files in the installed directory after installation, which would invalidate the removal of installation directory during uninstallation. The same solution applies to InstallScript MSI Project as well.

Take a look at the RemoveFiles table. You can remove specific files and files using wildcards. Once you remove those files, the folder should get removed as well on uninstall.
Something like the following should do the trick:
_MyFilesToRemove, <SomeComponentKey>, *.*, INSTALLDIR, 2

where <SomeComponentKey> is a key to an entry in the Component table. Any component will do, but if there is an .exe that actually creates the binary files, then perhpas you would want to use that .exe's component as you would only want the files to get removed when the corresponding .exe is removed.
Also, you may want to change *.* to *.<SomeSpecificExtension>

[Note: The above solution is basically an excerpt from MartinMarkevics's post in a community website.]

October 20, 2012

Want to avoid 32bit installation on 64bit machine when you maintain a single project for both 32bit and 64bit?

If you are looking to maintain single project for 32bit and 64bit installers and want to avoid 32bit installation on the 64bit machine. You can do it using the following steps.

Step1: InstallScript function needs to be created. As follows

 // Function Delaration
export prototype MyFunction(HWND);

 // Function Definition
function MyFunction(hMSI)
// To Do: Declare local variables.
NUMBER nvSize;
begin
nvSize = 255;     
MsiGetProperty (hMSI, "VersionNT64", svVersionNT64, nvSize);
//MessageBox(svVersionNT64, WARNING);
if ( svVersionNT64 != "" ) then
                MessageBox(@IDSD_WARNING_64BIT, WARNING);
endif;
end
 
Step2: Define this in you String Table.
IDSD_WARNING_64BIT, WARNING = The 64-bit version of Windows has been detected. Installation of this [Product] on this platform cannot proceed, and will be cancelled. Please install this version of SecureDoc only on a 32-bit version of Windows platform.

Step 3: Create an InstallScript Custom action.
Call the above created function in this custom acation.
This custom action this should called after AppSearch in the Install Exec Sequence with the following condition ISReleaseFlags><"MyReleaseFlag" .

Note: This code sample applies to Basic MSI Projects and verified with InstallShield 2010, 2011. 2012 SP1 and 2012 Spring Edition.

September 17, 2012

Uninstallation: AskYesNo/MessageBox is hidden behind the progress bar dialog?

Based on the requirement, you may add a Message Box or Yes / No confirmation dialog to the uninstallation sequence using InstallScript Custom Action. When you try to uninstall the application on a Windows Vista environment, these prompts (modal dialog) will be hidden behind the Screen and you will be waiting indefinitely until you press ALT + TAB to view the same.
To overcome this problem, following InstallScript function can be used.
 // Function Delaration
export prototype MyFunction(HWND);
 // Function Definition
function MyFunction(hMSI)
// To Do: Declare local variables.
HWND hRecord,hInst;
begin

hRecord = MsiCreateRecord(1);
MsiRecordSetString( hRecord, 0, "UninstallMessage");
MsiProcessMessage(hInst, INSTALLMESSAGE_USER|MB_YESNO, hRecord);
MsiCloseHandle(hRecord);
end;
 Note: This code sample applies to Basic MSI Projects and verified with InstallShield 2010, 2011 & 2012 SP1.
 Also kindly refer the below MSDN article regarding MsiProcess message function.

August 17, 2012

How to check required Space on disc using InstallScript?

At times, we need Custom Functions (over & above the InstallShield's default behaviour) to check the availability of disc space before proceeding with the installation. Here is the code sample for the same.

///////////////////////////////////////////////////////////////////////////////
//  FUNCTION:   CheckRequiredSpace
//  Purpose:    Performs space requirements check for selected targetdir.
///////////////////////////////////////////////////////////////////////////////
function CheckRequiredSpace()
    STRING svRequired;
    BOOL   bCheck;
    NUMBER nResult, nvTotalRequiredSpace, nvTotalAvailableSpace;
begin
    //Get total required disk space
    nResult = FeatureGetTotalCost(MEDIA, TARGETDIR, nvTotalRequiredSpace);
    if (nResult < 0) then
          return -1;
    endif;
    //Add 10000 KB as safety buffer to required space
    nvTotalRequiredSpace = nvTotalRequiredSpace + 10000;
    //Get total available disk space
    nvTotalAvailableSpace = GetDiskSpaceEx(TARGETDIR, KBYTES);
    if (nResult < 0) then
          return -1;
    endif;
    //Convert nvTotalRequiredSpace to string
    NumToStr(svRequired, nvTotalRequiredSpace);
    //Check if there is enough space available
    if (nvTotalRequiredSpace > nvTotalAvailableSpace) then
            MessageBox(@CheckRequiredDiskSpace_Error + svRequired + " KB", WARNING);
            return 0;
    endif;
    return 1;
end;

This function applies to Pure InstallScript & InstallScript MSI Projects.

July 2, 2012

How to set Focus on your Installer dialog?

When we run an installer, sometimes the control switches between your installer and other application's screen, which might shift the focus from the installer dialog.

Here is how you can make sure to stay on top of your installer dialog unless you swtich explictly.

Call the function - SetInstallerDlgFocus(), before invoking each dialog, so that your installer will be always available in the foreground.

// Included header files
#include "WinApi.h"  // Required to Make Win32 API Calls

// Function declaration
prototype SetInstallerDlgFocus();

// Function definition
///////////////////////////////////////////////////////////////////////////////
//  FUNCTION:   SetInstallerDlgFocus
//  Purpose:    Bring window to the foreground. 
///////////////////////////////////////////////////////////////////////////////
function SetInstallerDlgFocus()
    HWND hDialog;
begin
      hDialog = GetWindowHandle(HWND_INSTALL);
      SetForegroundWindow(hDialog);
end; // end of SetInstallerDlgFocus


[Note: This applies to InstallScript MSI and Pure InstallScript type projects.]

April 26, 2012

Installer Logging for InstallScript Type Project

Installer Logging for InstallScript Type Project

A log file can be generated to record the progress of an InstallScript based installation via a registry key. The log file can be used to diagnose the cause of failure or unexpected behavior in an installation.
Follow these steps on the target machine where the failure or unexpected behavior is occurring:
1. Add the following registry key (case insensitive):
HKEY_CURRENT_USER\ISlogit
2. A log file is automatically be generated on the Desktop after running any InstallScript setup.
3. The InstallScript log is encrypted (.bin file), and customers should contact support.
InstallShield KB article, has more details.

November 21, 2010

How to create a Custom User friendly Log for InstallScript?

This article explains how to create your own logging for InstallScript / InstallScript MSI project or Custom Actions writted in InstallScript.

Use the following code-snippet to create Custom Logging for InstallScript

// Prototype Definition
prototype ISfn_CreateLogFile();
prototype BOOL ISfn_LogError(STRING, STRING, STRING);


// Global Declaration
STRING gLogFilePath,gLogFileName,sgLogfile, gsvProductName; // For Log file
BOOL IsLogCreated,IsLogWritten,IsTempLogPath; // For Log file


Add the following code in OnBegin event for InstallScript / InstallScript MSI project or just before invoking ISfn_LogError function.
// Read the ProductName to a variable
nvSize = 256;
MsiGetProperty(ISMSI_HANDLE,"ProductName",gsvProductName,nvSize);

//Create the Log File
ISfn_CreateLogFile();

 

How to invoke ISfn_LogError function for Custom Log?
For Example:
ISfn_LogError("Local system name", "From Wscript : '" + svLocalSystemName + "'" ,"Success")
- first parameter states that the particular step is perfomed while getting Local System Name,
- the second parameter logs the retrieved local system name, the third parameter
- the third parameter determines that the actions output is a Success
Function Definition:
Copy the following function definition to your .rul file:
//---------------------------------------------------------------------------
// ISfn_CreateLogFile()
// Description: This function creates the installation log file in the format of
// PRODUCTNAME_Install_<InstallDate>__<InstallTime>.txt under
// Temp folder of the currently logged in user.
//---------------------------------------------------------------------------

function ISfn_CreateLogFile()


STRING sInstallerLogFilePath,sProdName;
STRING sSysDate,sSysTime,sHhr,sMin,sSec,svString,sLogFileName;
NUMBER nvResult,nPos,nHhrLen,nMinLen;
STRING szErrMsg;
NUMBER nvFileHandle;
begin


sInstallerLogFilePath="";
sInstallerLogFilePath = TempFolder;
if (ExistsDir(sInstallerLogFilePath)=0) then
         gLogFilePath = sInstallerLogFilePath;
else
         sInstallerLogFilePath = "";
         GetDisk(TempFolder,sInstallerLogFilePath);
         gLogFilePath = sInstallerLogFilePath + "\\";
         IsTempLogPath = TRUE;
endif;

// Creating the Log File Name
sProdName = gsvProductName;
//Frame the Log File Name
// Get the current date.
GetSystemInfo (DATE, nvResult, sSysDate);
// Get the current time.
GetSystemInfo (TIME, nvResult, sSysTime);
nPos = StrFind(sSysTime,":");
//Get the Hour part from the Date
StrSub ( sHhr, sSysTime, 0, nPos );
nHhrLen = StrLength(sHhr);
nHhrLen = nHhrLen + 1;
//Get the Minutes part from the Date
StrSub ( sMin, sSysTime, nHhrLen, 2 );
nMinLen = StrLength(sMin);
nMinLen = nHhrLen + nMinLen + 1;
//Get the Seconds part from the Date
StrSub ( sSec, sSysTime, nMinLen, 2 );
sSysTime = sHhr + "_" + sMin + "_" + sSec;
//Frame the final Log File name
if (!MAINTENANCE) then
          sLogFileName = sProdName + "_Install_" + sSysDate + "__" + sSysTime +".txt";
else
          sLogFileName = sProdName + "_UnInstall_" + sSysDate + "__" + sSysTime +".txt";
endif;
gLogFileName = sLogFileName;
// Set the file mode to append.
OpenFileMode (FILE_MODE_APPEND);
// Create a new file and leave it open.
if (CreateFile (nvFileHandle, gLogFilePath, sLogFileName) != 0) then
        // Report the error.
       MessageBox ("Error log file creation failed. Installation continues...", INFORMATION);
       IsLogCreated = FALSE;
else
       IsLogCreated = TRUE;endif;
// Set the message to write to the file.
// Append the message to the file.
// Write the Header Informations into the file
szErrMsg = "*******************************************************************************************************************";

if (WriteLine(nvFileHandle, szErrMsg) != 0) then
       // Report the error.
       MessageBox ("Errors couldnot be logged into the log file.     Installation continues...", INFORMATION);
       IsLogWritten = FALSE;
else
        IsLogWritten = TRUE;
        sgLogfile = gLogFilePath ^ sLogFileName;
endif;

if (IsLogWritten = TRUE)then
endif;
szErrMsg = "";
if (!MAINTENANCE) then
        szErrMsg = " "+ gsvProductName +" Installation Log ";
else
        szErrMsg = " "+ gsvProductName +" UnInstallation Log ";
endif;
WriteLine(nvFileHandle, szErrMsg);
szErrMsg = "";
szErrMsg = " Created on " + sSysDate + "__" + sSysTime + " ";
WriteLine(nvFileHandle, szErrMsg);
szErrMsg = "";
szErrMsg = "*******************************************************************************************************************";
WriteLine(nvFileHandle, szErrMsg);
szErrMsg = "";

// Close the file.
CloseFile (nvFileHandle);
end; // end of ISfn_CreateLogFile


 //---------------------------------------------------------------------------
// ISfn_LogError()
// Description: This function logs the installation actions in the Installation
// log file which was created using ISfn_CreateLogFile() function
// Input Parameters:
// ActionRequested: Action name/detail that is related to that particular action
// Parameters: Data that are passed to that particular function / action
// Status: Determines the output of that particular action(Information/Success/Error)
//---------------------------------------------------------------------------
function BOOL ISfn_LogError(ActionRequested, Parameters, Status)


NUMBER nvFileHandle,nvResult;
STRING szErrMsg,sSysDate,sSysTime;
begin
end; // end of ISfn_LogError
if (IsLogCreated=TRUE && IsLogWritten = TRUE) then
GetSystemInfo (DATE, nvResult, sSysDate);
GetSystemInfo (TIME, nvResult, sSysTime);
szErrMsg = "";
if Status = "Error" then
szErrMsg = "[" + sSysDate + "," + sSysTime + "] ERROR " + ActionRequested + " :: " + Parameters + " :: " + Status;
else
szErrMsg = "[" + sSysDate + "," + sSysTime + "] " + ActionRequested + " :: " + Parameters + " :: " + Status;
endif;

OpenFileMode (FILE_MODE_APPEND);
if (OpenFile (nvFileHandle, gLogFilePath, gLogFileName) = 0) then
WriteLine(nvFileHandle, szErrMsg);
endif;
CloseFile (nvFileHandle);
szErrMsg = "";
endif;

April 28, 2010

InstallScript - Reversing Input String

Here is the InstallScript function to reverse the input string and return the reversed string.

///////////////////////////////////////////////////////////////////////////////

// StrReverse()
// Description: This function reverses the input string
//////////////////////////////////////////////////////////////////////////////
function STRING StrReverse(svStr)
         string szReversedString;
         number nLen, nCnt;
begin
         nLen = StrLength(svStr) - 1;
         for nCnt = 0 to nLen
                szReversedString[nCnt] = svStr[nLen - nCnt];
         endfor;
         return szReversedString;
end; // End of StrReverse

November 18, 2009

Reading ComputerName - VBScript & InstallScript Samples

Often we have a requirement to read the target computer name to update INI / config file etc., and this article discuss the different ways to read the Computer Name in Script, which can be used within any installer.
VBScript
 Function GetCompName
          Set objNetwork = CreateObject("WScript.Network")
          ComputerName = objNetwork.ComputerName
          GetCompName = ComputerName
 End Function

InstallScript
function STRING  GetCompName()
       STRING szKey, szName, svValue;
       NUMBER nvSize, nvType;
begin
      szKey = "System\\CurrentControlSet\\Control\\ComputerName\\ComputerName";
      szName = "ComputerName";
      // Set the default root.
      RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
      // Retrieve the registry key value.
      RegDBGetKeyValueEx(szKey, szName, nvType, svValue, nvSize);
   return svValue;
end;

November 17, 2009

How to configure user & local group on target computer using InstallShield

Net.exe is a process, which belongs Windows OS can be used to create / delete users, local groups and add domain users to local group

  • Checking the user in existing domain
           net user <user>/<domain>
  • Add / delete Users to existing local group
           net localgroup <localgroup> <domain>\<user> /add
  • Create / delete a local user
           net user<user> <pass> /add
           net user <user> / delete
  • Create / delete a local group
           net localgroup <localgroup Name> /add /comment:”….”
           net localgroup <localgroup Name> /delete
The following functions are InstallScript implementation to create / delete the specified Local group which can be directly used in InstallScript / InstallScript MSI Projects. The same can be written as Custom Action for Basic MSI Projects
These functions are compatible IS 12.0 & above, further it might work on previous versions of InstallShield too.

Function Declaration:
          Prototype CreateLocalGroups(STRING);
          Prototype DeleteLocalGroups(STRING);

Function Definition:
//---------------------------------------------------------------------------
//CreateLocalGroups()
// Description: This function creates the specified local group
//INPUT:
//               szLocalGroupName – Local group to be created
// OUTPUT:
//               N/A - No return value
//---------------------------------------------------------------------------
function CreateLocalGroups(szLocalGroupName)
       STRING szProgram, szCmdLine, svDummy, svBatchFilePath, svBatchFileName;
       NUMBER nResult, nvResult, nvFileHandle;
begin
        svBatchFilePath = SUPPORTDIR;
        svBatchFileName = "createlocalgroups.bat";
       // Set the file mode to append.
       OpenFileMode (FILE_MODE_APPEND);
       // Create a new file and leave it open.
       if (CreateFile (nvFileHandle, svBatchFilePath, svBatchFileName) != 0) then
                   // Report the error.
       else
                  // Batch file create successfully
                 szProgram = "net.exe";
                 szCmdLine = "localgroup “ + szLocalGroupName + “ /add /comment:\"Members in this group are granted the administration rights\">createlocalgroups.log";
                 WriteLine(nvFileHandle, szProgram + " " + szCmdLine);
      endif;
      CloseFile ( nvFileHandle );
      ChangeDirectory(SUPPORTDIR);
      nResult = LaunchAppAndWait(svBatchFilePath ^ svBatchFileName,"",LAAW_OPTION_WAIT
LAAW_OPTION_HIDDEN);

      if (nResult = 0) then
                GetFileInfo ( SUPPORTDIR ^ "createlocalgroups.log" , FILE_SIZE , nvResult , svDummy );
                if (nvResult = 0) then
                          //Local Groups create successfully
               else
                          MessageBox ("Failed to create Local Groups. Installation Continues..", INFORMATION);
               endif;
      else
               MessageBox ("Failed to create Local Groups. Installation Continues..", INFORMATION);
      endif;
end; // End of Createlocalgroups


//---------------------------------------------------------------------------
//DeleteLocalGroups()
// Description: This function deletes the specified local group
//INPUT:
//           szLocalGroupName – Local group to be deleted
// OUTPUT:
//           N/A - No return value
//---------------------------------------------------------------------------
function DeleteLocalGroups(szLocalGroupName)
              STRING szProgram, szCmdLine, svDummy, svBatchFilePath, svBatchFileName;
              NUMBER nResult, nvResult, nvFileHandle;
begin
             svBatchFilePath = SUPPORTDIR;
             svBatchFileName = "deletelocalgroups.bat";
             // Set the file mode to append.
             OpenFileMode (FILE_MODE_APPEND);
             // Create a new file and leave it open.
             if (CreateFile (nvFileHandle, svBatchFilePath, svBatchFileName) != 0) then
                        // Report the error.
             else
                       // Batch file create successfully
                       szProgram = "net.exe";
                       szCmdLine = "localgroup “ + szLocalGroupName + “ /delete\">deletelocalgroups.log";
                       WriteLine(nvFileHandle, szProgram + " " + szCmdLine);
             endif;
             CloseFile ( nvFileHandle );
             ChangeDirectory(SUPPORTDIR);
             nResult = LaunchAppAndWait(svBatchFilePath ^ svBatchFileName,"",LAAW_OPTION_WAIT
LAAW_OPTION_HIDDEN);
             if (nResult = 0) then
                         GetFileInfo ( SUPPORTDIR ^ "deletelocalgroups.log" , FILE_SIZE , nvResult , svDummy );
                         if (nvResult = 0) then

                                       //Local Groups deleted successfully
                         else
                                        MessageBox ("Failed to delete Local Groups. Installation Continues..", INFORMATION);
                         endif;
             else
                          MessageBox ("Failed to delete Local Groups. Installation Continues..", INFORMATION);
             endif;
end; // End of Deletelocalgroups