"Starting with
Windows Mobile 5.0,
only one instance
of the installer
(wceload.exe) can
be running at a
time on Pocket PC
devices. This
restriction has
always been in
place on
Smartphone. As a
result, CAB files
that start other
CAB files from a
custom setup DLL
may not work on
Windows Mobile 5.0.
The workaround for
this is to have a
small executable in
the CAB that a
custom setup.dll
starts in its
Install_Exit entry
point. This
executable can get
a handle to the
running wceload.exe
process, wait for
wceload.exe to
exit, and then
restart wceload.exe
on the additional
CABs."
Can anyone help get
me started? Are
there code samples?
I am looking at the
setup.dll code
sample that comes
with VS 2005
(C:\Program
Files\Windows CE
Tools\wce500
\Windows Mobile 5.0
Pocket PC
SDK\Samples\CPP\Win3
2\Setupdll), but I
am not sure what to
do...also, it
doesn't look like
they created a
seperate exe, it
looks like they are
using Winbase.h to
detect end of
process. Please HELP
Thanks
Sorry it has taken this long to follow up with you. Very busy as I’m sure
you are. I just wanted to let you know I resolved the setup issue and would
like to share the fundamentals of the solution so you can help others as you
have helped me.
Problem: Using a setup dll in my applications CAB to launch multiple
supporting CABs failed with Windows Mobile 5.0 because only one instance of
wceload.exe can run at any given time. One must check to see if the process
is running and can only start a new one once it has ended.
My solution (although not perfect) stems from Rowan Youngson’s suggestion in
this article http://row1.info/content/view/85/2/ .
First I created a separate application, call it ‘Startup.exe’. This is
actually a good idea because now when updates are available for the main
application ‘Main.exe’, they can be downloaded via web service; Startup will
manage the update instructions in an xml config file and create a process to
launch the Main application. Doing this without a ‘controller app (Startup)’
would be difficult otherwise because you can’t update the Main application,
its config files, or the DB if they are in use by the Main application.
Anyway, I digress, so…back to launching multiple CABS….
I created a class that manages the process threading….
public class ProcessInfo
{
/// <summary>
/// Part of the ProcessInfo class
/// </summary>
public Int32 hProcess;
/// <summary>
/// Part of the ProcessInfo class
/// </summary>
public Int32 hThread;
/// <summary>
/// Part of the ProcessInfo class
/// </summary>
public Int32 ProcessID;
/// <summary>
/// Part of the ProcessInfo class
/// </summary>
public Int32 ThreadID;
}
I imported the necessary libray info….
// CreateProcess PInvoke API
[DllImport("Coredll.dll", SetLastError = true)]
private extern static int CreateProcess(
string imageName,
string cmdLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
Int32 boolInheritHandles,
Int32 dwCreationFlags,
IntPtr lpEnvironment,
IntPtr lpszCurrentDir,
IntPtr si,
ProcessInfo pi
);
[DllImport("coredll.dll", SetLastError = true)]
private extern static Int32 WaitForSingleObject(
IntPtr Handle,
Int32 Wait);
[DllImport("CoreDll.dll")]
private extern static Int32 CloseHandle(
IntPtr hProcess);
[DllImport("CoreDll.dll")]
private extern static Int32 GetLastError();
[DllImport("CoreDll.dll")]
private extern static Int32 GetExitCodeProcess(
IntPtr hProcess,
out Int32 exitcode);
I then created a method in which to call when creating processes to
run…(NOTE: This first little ‘IF’ piece just allows me to run my 'Main' app
after 1 second and waits for no man! Else…wait for the user to respond.
Example: User needs to confirm when a process ended by tapping ‘OK’ after the
SQLCE CAB installs. Then the next process will run…
public static bool CreateProcess( string ExeName, string CmdLine)
{
Int32 wait;
if (ExeName == MainApp)
{
wait = 1000;
}
else
{
wait = -1;
}
Create the process info obj and make sure it exists
ProcessInfo pi = new ProcessInfo();
if (CreateProcess(ExeName, CmdLine, IntPtr.Zero, IntPtr.Zero,
0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, pi) == 0)
{
return false;
}
It will run and wait for user to respond or not, depending on the condition
set in the first ‘IF’ stament above…
WaitForSingleObject((IntPtr)pi.hProcess, wait);
Int32 exitCode;
Once the CAB installs then the user usually selects ‘OK’ to confirm a
successful install. This action triggers this Exit process…You could handle
any errors with ‘GetLastError’.
if (GetExitCodeProcess((IntPtr)pi.hProcess, out exitCode) == 0)
{
MessageBox.Show("Failure in GetExitCodeProcess");
CloseHandle((IntPtr)pi.hThread); // Free handles
CloseHandle((IntPtr)pi.hProcess);
return false;
}
A successful confirmation exit will jump you here and free up the handles.
CloseHandle((IntPtr)pi.hThread); // Free handles
CloseHandle((IntPtr)pi.hProcess);
if (exitCode != 0)
return false;
else
return true;
}
That’s it baby! Of course I left out a lot of code to simplify this, but
also to make sure a cut and paste would work with few modifications.
You may want to include various System references too like:
using System.Reflection;
using System.Runtime.InteropServices;
....etc...InteropServices is a must.
Be sure to include a call to the ‘CreateProcess’ method and include the
parameters as defind in the dllImport ‘CreateProcess’.
CreateProcess("wceload.exe", @"\windows\sqlce.ppc3.arm.CAB");
For more info see
http://msdn.microsoft.com/library/en-us/wcekernl/html/ceconProcessThreadFunctions.asp?frame=true
Thanks Again Chuck Mahenski
--
Charcoal
Going Mobile...Keep me moving.