What are the steps to making an MSI?

  • Thread starter Thread starter Richard Lewis Haggard
  • Start date Start date
R

Richard Lewis Haggard

I know that this has been asked before, but I don't seem to be able to make
heads or tails of the response, so I'd be grateful if someone could be so
good as to go through the steps necessary in order to make a deployable
project.

I'm in C# and have a solution that makes an application. I want to make this
application available to vic- err ah I mean beta users. Now what?
==========
Richard Lewis Haggard
 
I know that this has been asked before, but I don't seem to be able to make
heads or tails of the response, so I'd be grateful if someone could be so
good as to go through the steps necessary in order to make a deployable
project.

I'm in C# and have a solution that makes an application. I want to make this
application available to vic- err ah I mean beta users. Now what?

I've recently had to go through this, and there were a fair number of
gotchas. Here's a brief summary of the steps to follow if you want to
do what I did.

1) Write the CF app.
2) Create an InstallActions project which is a desktop class library
type.
3) Within that, create Build and Etc directories.
4) Within the Build directory, have a buildcab.bat batch file.
I parameterised the version provided automatically by VS.NET so that
it would be more maintainable.
5) Within the Etc directory, add a .ini file and a .inf file for your
project. The .inf file lists which files you need from your main
app. The .ini file really just gives a description and lists which
cab files buildcab.bat will have created for you after running it.
I need SQL Server CE in my project, so I also have a .ini file for
that.
6) Set a Pre-Build Event for the project. Mine is set to:
"$(ProjectDir)\Build\buildcab.bat" (including the quotes)
7) In the same project, add a custom install action to launch the
device installer (more on that in a minute). I also have a
custom uninstall action to remove some registry entries which the
device installer creates.
8) Create a Setup project which includes the cab file generated at
build time, the device installer (coming soon!) and any cab/ini
files you need. (In my case, this is the SQL Server CE cab and
ini file.) In the UI, have a checkbox which, when ticked,
fires the custom action from 7) to launch the device installer
when installation has finished.
9) Write the device installer. In my case, this uses
OpenNETCF.Desktop.Communications.dll to talk to the device - it
does this to check for SQL Server CE's presence, write registry
settings, verify the installation etc. The most important thing
this program does, however, is launch the CeAppMgr to install
your app. In my case, I have a nasty bit of code at the start
so that if I get a certain parameter, I try to find an msiexec
process with the appropriate main window title (the name of the
app as far as the installer is concerned) and wait for that process
to finish before showing the main installation/configuration dialog.

It's all very involved, despite our project having relatively simple
needs (it appears that configuration is a much-neglected part of device
application installation)... Let me know if any of the above sounds
interesting and you need more information. At some stage I may create a
sample application which has all the elements of the above in, but in a
very simple way, as a sort of "Hello world" program for any CF app
which requires configuration.
 
Been there, thank you, and was unable to gain anything significantly useful
from it. In fact if you look at how the article was rated, you will see
something very interesting. Half of the people thought it was great. The
other half thought it was exceptionally unuseful. I fall into the group that
could extract nothing useful from it.
========
Richard Lewis Haggard
 
God, I'm getting thicker by the second. I did not make much headway with
this at all.

In an attempt to see if I could figure this out, I created a simple little
'hello world' form application and then tried to implement your steps.

Add "InstallActions project which is a desktop class library type". Ah, ok,
I see a C# project type Class Library template. I'll try that.

'Create Build and Etc. directories" OK, I've highlighted 'InstallActions',
right clicked and selected 'Add new folder' and specified the folder names
as "Build" and "Etc"

"Buildcab.bat batch file in the Build directory". I selected 'PocketHello'
and then selected the 'Build Cabfile' menu item in order to get VS to build
me a batch file. I copied the resulting BuildCab.bat file to Build.
Parameterized? What parameterized? The existing batch file already does
exactly what I want it to; ie, makes all of the device processor dependent
CAB files.

"In Etc directory, add INI and INF" - Where does the INI come from? I see an
INF for PPC.

Nope. I've completely lost the thread at this point. This seems like an
awful lot of work for what needs to be done. Are you sure this is how to
make an MSI that can be used to distribute an application?
==========
Richard Lewis Haggard
 
Richard Lewis Haggard said:
God, I'm getting thicker by the second. I did not make much headway with
this at all.

Apparently, I'm just as thick because it took me quite awhile to figure out
how to do this. MSDN article
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/
html/netcfdeployment.asp) wasn't good enough, though I think it's accurate
once you understand what everything in it means.

What helped me successfully do this was
http://simon.kittle.info/articles/packaging_and_deploying_pocketpc_apps.htm.

--Terry
 
God, I'm getting thicker by the second. I did not make much headway with
this at all.

In an attempt to see if I could figure this out, I created a simple little
'hello world' form application and then tried to implement your steps.

Add "InstallActions project which is a desktop class library type". Ah, ok,
I see a C# project type Class Library template. I'll try that.
Right.

'Create Build and Etc. directories" OK, I've highlighted 'InstallActions',
right clicked and selected 'Add new folder' and specified the folder names
as "Build" and "Etc"
Goodo.

"Buildcab.bat batch file in the Build directory". I selected 'PocketHello'
and then selected the 'Build Cabfile' menu item in order to get VS to build
me a batch file. I copied the resulting BuildCab.bat file to Build.
Parameterized? What parameterized? The existing batch file already does
exactly what I want it to; ie, makes all of the device processor dependent
CAB files.

I parameterized it in terms of output directory, input location etc. If
nothing else, it made the command line somewhat easier to follow. You
certainly don't have to.
"In Etc directory, add INI and INF" - Where does the INI come from? I see an
INF for PPC.

You have to write your own ini file - but there's an example in the
article you didn't like.
Nope. I've completely lost the thread at this point. This seems like an
awful lot of work for what needs to be done. Are you sure this is how to
make an MSI that can be used to distribute an application?

Just making an MSI to install things on the desktop is very
straightforward - but you need to then get it to install stuff on the
device, and that's the harder bit.

I'll try to work up a full solution with examples of all of this -
maybe over the weekend. Will that be early enough for you to meet
deadlines etc?
 
Terry Westley said:

It's interesting that that contains the same advice that another
article does - to run CeAppMgr with no parameters when uninstalling the
desktop application. That seems really confusing to me - there's
nothing to tell the user *why* it's popped up.

(It also doesn't allow for any configuration. I seem to be the only
person in the world who wants to configure a PPC app from a desktop
installer though, given the lack of articles on the subject...)
 
That would be a great help and I thank you.

Have you ever tried the setup wizard?
=========
Richard Lewis Haggard
 
That would be a great help and I thank you.

Have you ever tried the setup wizard?

Yes, I think so - but to be honest, it doesn't help with the tough bits
of making a CF installer.
 
This is so *darned* frustrating.

I took a look at your other setup project reference and tried to follow it.
Again, there are problems.

While compiling the CustomInstaller part of the project, I get a failure to
recognize "using System.XML;" The error indicates that an assembly is
missing. I've manually included 'System.XML.DLL' yet the problem persists.
Why?

Additionally, there is a problem with "[RunInstaller(true)]" I've tried
including every darned assembly I can find and none seem to make a
difference. What am I missing?
c:\ce\pockethello\custominstaller\custominstaller.cs(2,14): error CS0234:
The type or namespace name 'XML' does not exist in the class or namespace
'System' (are you missing an assembly reference?)

c:\ce\pockethello\custominstaller\custominstaller.cs(20,3): error CS0246:
The type or namespace name 'RunInstaller' could not be found (are you
missing a using directive or an assembly reference?)

======
Richard Lewis Haggard
 
Oh! I see. Part of the problem is that it was unclear as to what kind of
project was added to have the CAB file, DLL and INI file dependencies. That
was a SETUP project, not a blank project as was somewhat implied by the
sample project. That took care of the 'EXE file doesn't have an entry point'
error.
========
Richard Lewis Haggard

Richard Lewis Haggard said:
This is so *darned* frustrating.

I took a look at your other setup project reference and tried to follow it.
Again, there are problems.

While compiling the CustomInstaller part of the project, I get a failure to
recognize "using System.XML;" The error indicates that an assembly is
missing. I've manually included 'System.XML.DLL' yet the problem persists.
Why?

Additionally, there is a problem with "[RunInstaller(true)]" I've tried
including every darned assembly I can find and none seem to make a
difference. What am I missing?
c:\ce\pockethello\custominstaller\custominstaller.cs(2,14): error CS0234:
The type or namespace name 'XML' does not exist in the class or namespace
'System' (are you missing an assembly reference?)

c:\ce\pockethello\custominstaller\custominstaller.cs(20,3): error CS0246:
The type or namespace name 'RunInstaller' could not be found (are you
missing a using directive or an assembly reference?)

======
Richard Lewis Haggard


Terry Westley said:
Apparently, I'm just as thick because it took me quite awhile to figure out
how to do this. MSDN article
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/
html/netcfdeployment.asp) wasn't good enough, though I think it's accurate
once you understand what everything in it means.

What helped me successfully do this was
http://simon.kittle.info/articles/packaging_and_deploying_pocketpc_apps.htm.
 
That would be a great help and I thank you.

Unfortunately I should have asked my team leader before agreeing to do
this - he feels (understandably) that we shouldn't make our setup
methods too public.

If you have any more specific questions, I may well be able to answer
them, but I won't be able to come up with a sample, I'm afraid.
 
Well, progress of a sort. Setup runs on the PC side but it aborts with a
message to the effect that the ini file is invalid. I'm not sure whether
that means that the ini file is not being found or if the contents of the
found ini file are in someway malformed. So much for copy and paste. <sigh>

Once I've been through this, I will definitely write it up and make it
publicly available on my web site.
===
Richard Lewis Haggard
 
Well, progress of a sort. Setup runs on the PC side but it aborts with a
message to the effect that the ini file is invalid. I'm not sure whether
that means that the ini file is not being found or if the contents of the
found ini file are in someway malformed. So much for copy and paste. <sigh>

Once I've been through this, I will definitely write it up and make it
publicly available on my web site.

One thing to watch here: You need to give AppManager the *full* path to
the ini file, not just a relative path.

If that isn't the problem, could you post the ini file contents?
 
OK, to cut a long story short - I have put together a complete, step by step example of how to make a deployment project. Go to my web site (www.Haggard-And-Associates.com) and have a look. If you run into a problem with what's documented, let me know and I'll fix the documentation.

Deployment example
===
Richard Lewis Haggard
 
It turned out to be something really silly. When I'd copied the example INI
file and modified, I'd misspelled my own project CAB files so the installer
was failing to find a CAB that matched the application and processor type.
Once that was fixed, it worked.

By the way, I'd appreciate it if, when you get the time and inclination,
you'd proof my deployment documentation so that I don't send someone else
down the garden path.
http://www.haggard-and-associates.com/DOT_NET/C_Sharp_for_CF/Deployment/deployment.htm
=====
Richard Lewis Haggard
 
It turned out to be something really silly. When I'd copied the example INI
file and modified, I'd misspelled my own project CAB files so the installer
was failing to find a CAB that matched the application and processor type.
Once that was fixed, it worked.
Excellent.

By the way, I'd appreciate it if, when you get the time and inclination,
you'd proof my deployment documentation so that I don't send someone else
down the garden path.
http://www.haggard-and-associates.com/DOT_NET/C_Sharp_for_CF/Deployment/deployment.htm

No problem.

For the custom installer, I really can't see why you'd need to include
System.Data (either the DLL or the namespace reference). Unless you're
popping up a message box, you don't really need System.Windows.Forms
either. (On looking further, it seems that RunAppManager uses
MessageBox - that's why you need System.Windows.Forms in your version.)

I'd personally recommend ditching the template for install actions -
it's got a load of "designer support" (which doesn't seem to be
terribly helpful) which complicates the code significantly. A very
simple template would be:

// These are all the "using" statements I need - they're more than
// what's needed to compile the code below though.
using System;
using System.Reflection;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using Microsoft.Win32;

namespace <whatever>
{
/// <summary>
/// Custom install action
/// </summary>
[RunInstaller(true)]
public class <whatever>: Installer
{
public <whatever>()
{
// Add handler hooks in here
}

// Add the handler bodies here
}
}

No need for all the extra bits and bobs.


You don't explain why you've got an uninstall action that runs CeAppMgr
with no parameters. I know it's what the sample does, but I'm really
not convinced it's a good idea. The user has no idea why it's being put
up there, or what they're then meant to do.


The Pre-Build Event Command Line can be simpler - it can *always* be
"$(ProjectDir)\BuildCabs\buildcab.bat" (including the quotes). That way
it doesn't have to be changed if you change the project name.


I would recommend putting the .ini file in the same place as the .inf
file - it's just easier to keep all the cab-related stuff in one place.
 
OK, the deployment part is working OK but I don't have the 'reinstall' or the 'uninstall' cases working at all. The second time the MSI runs, the installer says that it will be necessary to manually uninstall the application through the control panel. What needs to be done to get the MSI to handle reinstall and uninstall conditions?
========
Richard Lewis Haggard
"Richard Lewis Haggard" <HaggardAtWorldDotStdDotCom> wrote in message OK, to cut a long story short - I have put together a complete, step by step example of how to make a deployment project. Go to my web site (www.Haggard-And-Associates.com) and have a look. If you run into a problem with what's documented, let me know and I'll fix the documentation.

Deployment example
===
Richard Lewis Haggard
 
Back
Top