InstallScript is the language to create installations for InstallShield. And …

InstallScript is similar to the C language.

as stated in InstallScript Language Reference. But they resembles only in their written form, not in their semantics or syntax. So be careful!!

Logic Operators (&&, ||) have no short circuit effects.

Doc: Logical Operators (&&, ||, !)

Unlike C, InstallShield performs complete Boolean evaluations of logical expressions.

So in order to achieve short-circuit effect, rewrite if statements with compound expressions to nested if statements.

For example,

if ( Foo() && Bar() ) then
	MessageBox( "Complete Boolean Evaluation", INFORMATION );
endif;
if ( Foo() ) then
	if ( Bar() ) then
		MessageBox( "Short-circuit evaluation", INFORMATION );
	endif;
endif;

And,

if ( Foo() || Bar() ) then
	MessageBox( "Complete Boolean Evaluation", INFORMATION );
endif;
if ( Foo() ) then
	MessageBox( "Short-circuit evaluation", INFORMATION );
elseif ( Bar() ) then
	MessageBox( "Short-circuit evaluation", INFORMATION );
endif;

Parentheses in if statement are optional

Equality comparison is written as a single equal sign (=)

Doc: Relational Operators (<, >, =, <=, >=, !=)

Equality comparison is written as =, though == also works (undocumented).

Unlike C, which uses == to test for equality, InstallScript's assignment operator and relational operator use the same symbol ( = ).

VerCompare function only applies to numeric version in w.x.y.z format

Doc: VerCompare

Only version number in format w.x.y.z is valid, comparing versions in other formats result in ISERR_GEN_FAILURE (-1).

Characters other than number characters are actually allowed, but they are ignored when doing comparison. e.g.

  • VerCompare( "1.2.3.4rc", "1.2.3.4", VERSION ) returns EQUALS (2)
  • VerCompare( "1.2.3.04", "1.2.3.4", VERSION ) returns EQUALS (2)
  • VerCompare( "v1.2.3.4", "v2.2.3.4", VERSION ) returns EQUALS (2)
  • VerCompare( "1.2.3.rc", "1.2.3.4", VERSION ) returns LESS_THAN (1)
  • VerCompare( "v1.2.3.4", "1.2.3.4", VERSION ) returns LESS_THAN (1)
  • VerCompare( "v2.1.3.4", "v1.2.3.4", VERSION ) returns LESS_THAN (1)
  • VerCompare( "v1.3.3.4", "v2.2.3.4", VERSION ) returns GREATER_THAN (0)

LaunchAppAndWait does not wait by default

Doc: LaunchAppAndWait

To actually launch an app and wait for it, you need to pass the LAAW_OPTION_WAIT option:

LaunchAppAndWait( szProgram, szCmdLine, LAAW_OPTION_WAIT );

If the launched program spawns a child process and exits itself, LAAW_OPTION_WAIT_INCL_CHILD option is also needed.

LAAW_OPTION_NOWAIT is the default

Actually, the value of the predefined constant LAAW_OPTION_NOWAIT is 0, thus specifying it is totally optional.

LaunchApp requires complete path of the application

LaunchApplication/LaunchAppAndWait/LaunchApp requires complete path of the application.

Otherwise, it failes with ISERR_GEN_FAILURE (-1) as the return value.

Commas

(Not documented)

Suprisingly, (fullwidth comma, \uff0c) can be used in place of , (comma, '\u002c').

SYSINFO on previous versions of InstallShield

SYSINFO.nOSMajor, SYSINFO.nOSMinor, SYSINFO.nWinMajor, SYSINFO.nWinMinor on InstallShield 2013 and InstallShield 2013 SP1 report version number up to 6.2 only, i.e., Windows Server 2012 R2 (6.3), Windows 10 (10.0), etc., will be reported as 6.2.

Data Type keywords are case-sensitive

Though most Data Type keywords can be entered in either lowercase or uppercase:

  • binary/BINARY
  • char/CHAR
  • int/INT
  • long/LONG
  • number/NUMBER
  • object/OBJECT
  • pointer/POINTER
  • short/SHORT
  • string/STRING
  • variant/VARIANT
  • void/VOID
  • wpointer/WPOINTER
  • wstring/WSTRING

while others are uppercase only:

  • BOOL
  • HWND
  • LIST
  • LPSTR
  • LPWSTR

So the best practise is to always use the uppercase form.

ISERR_SUCCESS and ISERR_GEN_FAILURE

ISERR_SUCCESS (0) and ISERR_GEN_FAILURE (-1) are predefined constants returned by built-in functions.

Values greater than zero are also returned by built-in functions, whose meaning are dependent on called functions, but always mean it's executed successfully.

Values less than zero will also returned by built-in functions when the error is specific and has a separate error code.

So to test whether a built-in function execute successfully, best practice is to compare it with ISERR_SUCCESS (0):

if ( nResult >= ISERR_SUCCESS ) then
	// Success
	// ...
endif;


if ( nResult < ISERR_SUCCESS ) then
	// Error
	// ...
endif;

Do NOT compare with ISERR_SUCCESS itself only:

// The following is prone to bug
if (nResult) then
	// Success (>0) or Error (<0)
	// ...
endif;

String Size and Autosize

Doc: String Size and Autosize, BYREF Operator

String without size specified is auto sized.

Note that an autosized string variable that is passed by reference to a function will not be autosized within the called function. If the function attempts to assign a value whose length is greater than the current size of that parameter, run-time error 401 occurs. To avoid this error, declare strings with a specific size when they are to be passed by reference to a function.

Indirection Operator (*)

Doc: Indirection Operator (*)

The indirection operator can be used with number pointers only.

Embed \0 in string

Embed \0 in string literal is possible, but most built-in functions simply ignores all values after first \0, including + operator for string concatenation.

svTest = "a\0b\0c";        // => "a\0b\0c\0"
svTest = "A\0B" + "C\0D";  // => "AC\0"

To concat strings with embeded \0, use CopyBytes(). And keep track of the length of string yourself, as functions like StrLength() or StrLengthChars() doesn't work either.

Strings with embeded null byte are useful in LAAW_PARAMETERS.lpEnvironment for example.