Saturday, May 22, 2010

Working with MSI

How to create an MSI installation package from scratch

(1) Install the Microsoft Windows Installer SDK. This will by default install to C:\Program Files\Windows Installer 4.5 SDK\.

(2) Browse to the C:\Program Files\Windows Installer 4.5 SDK\Tools folder and run the Orca.msi installation. Perform a complete installation of Orca. This program is used to modify .MSI files.

(3) Create a basic MSI package by merging the two sample .msi files together. From a DOS prompt, do the following:
Step 1: Copy the schema.msi file to YourNewMSI.msi file
Step 2: msimerg YourNewMSI.msi sequence.msi
Step 3: msimerg YourNewMSI.msi uisample.msi

You now have a single MSI file with basic logic and sequencing. To customize for your specific application, do the following steps:

(1) Open the YourNewMSI.msi file with Orca (right-click and select Edit with Orca).

(2) Click on the View / Summary Information menu in Orca. Change it into something relevant for your company or product, and select the platforms and languages.

(3) Run GUIDGEN to get the GUID for the ProductID for your MSI package, and make sure it's all in UPPERCASE!

(4) Go to the "Property" table, and change the ARPHELPLINK to your company website.

(5) Drop the ComponentDownload row.

(6) Add a new row for each of the following properties (case sensitive):

ALLUSERS = 1 for machine-only installations.

ProductName = Your product name

Manufacturer = Your company name

ProductCode = Use GUIDGEN to get a GUID for this product

ProductVersion = Your product version

ARPNOMODIFY = 1 (to disable the "Modify" button in Add/Remove Programs.)

ARPNOREMOVE = 1 (to disable the "Remove" button.)

You need to create at least 1 feature and 1 component. Do the following:

(7) Go to the "Feature" table



You need to create at least 1 feature and 1 component before you can run/use the MSI:

Go to the "Feature" table and create a new record:
Feature = Complete
Parent =
Title = Complete
Description = Complete installation
Display = 1 (=displayed expanded in the featurelist)
Level = 1
Directory = TARGETDIR
Attributes = 0

Now we need to add the registry key we'd like to install. Go to the Registry table,
and create a new record:

Registry = REG00001
Root = -1 (= Depend on the value of the ALLUSERS property.
You can also use 0=HKCR, 1=HKCU, 2=HKLM, 3=HKEY_USERS)
Key = SOFTWARE\[Manufacturer]\[ProductName]
Name = ProductName
Value = [ProductName] [ProductVersion]
Component = COMP0001

Note: Using [propertyname] means it should use the named property's value.

Now we need to create the COMP0001 component we just referenced:

Go to the Components table and create a new record:
Component = COMP0001
ComponentID = (Run GUIDGEN to get a GUID - make sure it's in UPPERCASE)
Directory = TARGETDIR
Attribute = 4 (4= registry, 0 = files to be installed locally)
Condition =
Keypath = REG00001

Now we can connect this component to the "Complete" feature:

Go to the FeatureComponents table and create a new record:
Feature = Complete
Component = COMP0001

Now, we need to have a single record in the Directory table before the installation can be done.
This is because of the special handling of the TARGETDIR property, which has to be resolved.

Create a new record in the Directory table:
Directory = TARGETDIR
Directory_parent = (leave blank (null) or use TARGETDIR)
Value = SourceDir

Tip: Change the LicenseAgreementDlg record (text field) in the Controls table to include your license text.

Tip: Use the Tools | Validate menu option in Orca to make sure you have entered all the data properly.

You should now be able to install your MSI package (only a registry key, but a good start :). Make sure the installation and removal can be completed, and that the ARP (Add / Remove Programs) info is as expected. Use RegEdit to see that the registry key was installed properly, and is removed when uninstalling.

Installing MSI packages silently using command lines

You can create a small command file to install the MSI package silently (not going through all the dialogs) ; this makes it easier and faster to perform tests of the actual installations once the user interface has been tested.

Create the following two small text files in your project folder:

To install silently, no prompts, no logging:

Install.cmd:
MsiExec /i "MyMSI.msi" /Qb-!

Uninstall.cmd:
MsiExec /X "MyMSI.msi" /Qb-!

To install silently with a success/failed dialog in the end, and logging enabled:

Install.cmd:
MsiExec /i "MyMSI.msi" /L*v "c:\temp\MyMSI_i.log" /Qb+

Uninstall.cmd:
MsiExec /X "MyMSI.msi" /L*v "c:\temp\MyMSI_x.log" /Qb+

Please make sure you have a C:\temp directory, and have write access to it.
You can now doubleclick on the install.cmd or uninstall.cmd to quickly install or remove your software package.

Tip: Make sure you include the redistributable setup files for MSI for Win9x / NT on your website, some people might now have the Windows Installer technology installed. They can be found in C:\Program Files\MsiIntel.SDK\Redist\.

Expanding the installation package

Naturally, installing a registry is not as important as installing files - but it's vital to have the basics in order. If your MSI is now fully working, you can continue with adding files to be installed.

For each of your following MSI projects, remember to copy your basic MSI and then open it with Orca and change the ProductID in the summary information and the ProductCode property to some unique UPPERCASE GUID numbers for this package.

Adding file(s) to the installer

Create a directory structure under your project source directory that matches the target folder structure. For each directory you have listed, a subdirectory with the same name must exist in the source tree. In most cases this means you would have a Program Files\Your Company Name\Your Product Name\ subfolder in the root of the source tree.

The files you want to install must be found in the directory they should be installed to (by default relative to the source root, and the installation target base path). So if you install YourApplication.exe to C:\Program Files\MyCompany\MyProduct\, you should have a Program Files\MyCompany\MyProduct\YourApplication.exe under the root of your source tree.

Create the following properties in the directory table:

(Use Directory_Parent=TARGETDIR, DefaultDir=.)
SystemFolder
ProgramMenuFolder
PersonalFolder
ProgramFilesFolder
DesktopFolder
StartMenuFolder
These are automatically resolved during install. See "System Folder Properties" in the help file (link from under Directory table help).

Create the target installation directory records:

DIR00001, parent=ProgramFilesFolder, DefaultDir=.:PROGRA~1|Program Files
DIR00002, parent=DIR00001, Defaultdir=Spinne~1|Spinner Software

Tip: The Defaultdir uses the format targetdir:sourcedir, optionally short | long filenames. The "." means the value used in the directory_parent field is the resolved target path (so no subdirectory is created with the defaultvalue name). So while DIR00001 resolves to the ProgramFilesFolder value (and expects a Program Files subdirectory in the source tree), DIR00001 creates a Spinner Software subdirectory under the resolved DIR00001 parent (and expects one in the source tree as well). This essentially allows you to have multiple source directories that all resolve to the same target during installation.

Go to the Files table, and create a new entry record. In this example we'll install Notepad.exe:

File=FILE0001, Component=COMP0002, Filename=Notepad.exe, Filesize=0, Attributes=0, Sequence=1.
If a file is Vital to the proper functioning of the application, use Attributes = 512.

Create a new component to hold your file. Go to the Components table and add a new record:

COMP0002, attributes = 0, directory = DIR00002, Keypath=FILE0001.
Use GUIDGEN to get the component ID.

When you set the directory field for Component COMP0002 to use DIR00002, Notepad.exe (FILE0001 pointed to by the keypath) file will be installed into C:\Program Files\Spinner Software\.

Create a new record in the FeatureComponents table:

Feature=Complete, Component=COMP0002.

Create a record in the Media table with DiskID=1, LastSequence=1 (highest Sequence number in File table).

Save the MSI, then open a command prompt and run the following command in the project folder:

CScript //nologo wifilver.vbs mymsi.msi
This will show you the information found in the File table.

Now update it with the latest file information (found from the source tree):

CScript //nologo wifilver.vbs mymsi.msi /U

Your MSI file is now ready to install both registry keys and files :).

Adding a shortcut

Create new records in the Directory table for the shortcuts:

DIR00003, parent=StartMenuFolder or ProgramMenuFolder, defaultdir=.
DIR00004, parent=DIR00003,
defaultdir=Spinne~1|Spinner Software
(or whatever name you want in your start menu, in short | long file name format)
DIR00005, parent=DesktopFolder, defaultdir=.

Create a new record in the Icon table:

Name=ICON0001.exe, Data = full path to the exe file in the source tree
(this will be read in automatically and the icon stored).

Create new records in the Shortcuts table:

Shortcut=SCUT0001, Directory=DIR00004, Name=Notepad,
Component=COMP0002, Target=Complete, Description=Notepad,
Icon=ICON0001.exe, IconIndex=0 or 1, ShowCmd=1.

For the Desktop shortcut, copy/paste the row, then change the keyname
and the directory from DIR00004 to DIR00005:

Shortcut=SCUT0002, Directory=DIR00005, Name=Notepad,
Component=COMP0002, Target=Complete, Description=Notepad,
Icon=ICON0001.exe, IconIndex=0 or 1, ShowCmd=1.

Note that there's a bug, so the extension (file type) of the Icon field must match the target file extension. Hence, name it ICON0001.exe. Please note the value of this field is Case Sensitive.

Validate your project, then run a test. You should now have a shortcut on the users desktop, and under the Spinner Software folder in the Start Menu | Programs menu.

Compressing the MSI into a single file

For this you need the WiMakCab.vbs script from C:\Program Files\MsiIntel.SDK\Samples\Scripts. Copy it to your project folder.

Run the following command to create a cabinet file with all the files listed in MyMSI.MSI :

cscript //nologo wimakcab.vbs mymsi.msi MyCabinet /C

The most useful option for this script is the ability to create a single MSI file that contains everything. This is the kind of file you want to distribute.

Run the following command to create a cabinet file containing all your files, sequence the File table, update the MyMSI.MSI file to include the new cabinet file, and enable the "Compressed" option:

cscript //nologo wimakcab.vbs mymsi.msi MyCabinet /C /U /E /S

Note that 4 MyCabinet.* files are created: The actual cabinet file (.CAB), the .DDF is a definition of the content of the CAB file, and the .INF file lists the files in the cabinet. The .RPT file is just a text report on the success of the cabinet creation. All 4 files can be deleted after you've used the /C /U /E /S options, since your files are now streamed inside the single MSI file.

Tip: If you have problems creating the cab file, check the File Table records. The WiMakCab.vbs script only handles File Table records where the NonCompressed bit is cleared in the Attributes field. There is also a problem with MakeCab.exe under Windows 2000 : if a file has the NonCompressed bit set and you update the MSI to use a single compressed file (with a built in cabinet), this flag is not removed, and the package will not install properly. You'll get an error that the file to install could not be found. You can fix this in the WiMakCab script by adding the following lines :

 ' In the top of WiMakCab, add the msidbFileAttributesCompressed flag
Const msidbFileAttributescompressed = &h00004000

' Right before the statement (search wimakcab for it):
' If (attributes And msidbFileAttributesNoncompressed) = 0 Then
' you can insert the following block of code:

' MakeCab does not change the NonCompressed / Compressed flag!!
If (attributes And msidbFileAttributesNoncompressed) <> 0 Then
WScript.Echo "File " & filename & " is marked non-compressed. Changing attribute."
attributes = (attributes - msidbFileAttributesNonCompressed)

' To be really nice, you could set it to the proper value:
attributes = (attributes + msidbFileAttributesCompressed)

' Update the field (the record will be updated later)
record.IntegerData(5) = attributes
End If

I found it useful to create a little command script to create the compressed MSI. I update the files in the source tree, then run this command file to create a new, single (compressed) MSI for distribution. It expects a file named Input.msi, and creates the file Output.msi.

CreateMSI.cmd:
@ECHO OFF
@ECHO.
@ECHO Updating MSI file with new files
@ECHO.

@ECHO Remove target output file
DEL /Q "Output.msi"

@ECHO Update MSI information from source tree
CScript //nologo WiFilVer.vbs Input.msi
CScript //nologo WiFilVer.vbs Input.msi /U

@ECHO Copy original file to new output file
COPY /Y "Input.msi" "Output.msi"

REM @ECHO Create a single cabinet file with all your files
REM CScript //nologo WiMakCab.vbs "Output.msi" Files /C

@ECHO Create and embed the file cabinet
CScript //nologo WiMakCab.vbs "Output.msi" Files /C /U /E /S

DEL /Q "Files.CAB"
DEL /Q "Files.INF"
DEL /Q "Files.RPT"
DEL /Q "Files.DDF"

@ECHO Done
PAUSE

Part 2 - Custom Actions:

Continue to -> How to create MSI Custom Actions

(c) 2004 Nicolai Kjaer, Spinner Software B.V.

Sunday, May 9, 2010

CDMA vs GSM

- CDMA: Verizon, Sprint PCS, and Virgin Mobile. 270 million subscribers worldwide.
- GSM: AT&T Wireless, T-Mobile USA. 1 billion subscribers worldwide.

International Roaming: GSM yes. CDMA no.

SIM cards: GSM yes. SIM's are not tied to the network but the actual phone. SIM allows phones to be instantly activated without carrier intervention. CDMA has R-UIM card in parts of Asia but not in USA.

Speed: CDMA is faster. CDMA2000 (or EVDO) allows downstream rate of 2 Mbps. GSM EDGE boasts 384 Kbps.