Shell launcher

  • Thread starter =?iso-8859-1?q?Carlos_M._P=E9rez?=
  • Start date
?

=?iso-8859-1?q?Carlos_M._P=E9rez?=

This email is regarding a March 15 article in CodeProject
(http://www.codeproject.com/netcf/UseSystemimagelist.asp).

I'm developing a kiosk application for Windows CE, using OpenNETCF.
Basically, the application has to launch other programs and be able to
switch to them and close them. Using OpenNETCF classes for processes I
can launch applications, but I can't manage them because I get the
handle for the process, NOT the window handle. And that's the one I
need for switching to and from applications.

In that article I've noticed an interesting way of launching
applications:

private void button1_Click(object sender, System.EventArgs e)
{
string FullPath=@"\windows\explorer.exe";
ShellExecuteInfo sei=new ShellExecuteInfo();
GCHandle hfile = GCHandle.Alloc((FullPath + '\0').ToCharArray(),
GCHandleType.Pinned);
sei.lpFile = (IntPtr)((int)hfile.AddrOfPinnedObject() + 4);
//windowstyle
sei.nShow = 1;
GCHandle hverb = new GCHandle();
hverb = GCHandle.Alloc(("Open"+'\0').ToCharArray(),
GCHandleType.Pinned);
sei.lpVerb = (IntPtr)((int)hverb.AddrOfPinnedObject() + 4);
bool ret=ShellExecuteEx(sei);
}

sealed class ShellExecuteInfo
{
public UInt32 cbSize = 60;
public UInt32 fMask = 0x00000040;
public IntPtr hwnd = IntPtr.Zero;
public IntPtr lpVerb = IntPtr.Zero;
public IntPtr lpFile = IntPtr.Zero;
public IntPtr lpParameters = IntPtr.Zero;
public IntPtr lpDirectory = IntPtr.Zero;
public int nShow = 0;
public IntPtr hInstApp = IntPtr.Zero;
public IntPtr lpIDList = IntPtr.Zero;
public IntPtr lpClass = IntPtr.Zero;
public IntPtr hkeyClass = IntPtr.Zero;
public UInt32 dwHotKey = 0;
public IntPtr hIcon = IntPtr.Zero;
public IntPtr hProcess = IntPtr.Zero;
}


The ShellExecuteInfo class contains an IntPtr variable called hWnd,
but of course it's initialized to IntPtr.Zero and not used by the
routine that launches the applications.

How could I retrieve the value of hWnd, just as the original author
retrieves the Verb and File? If this method of launching applications
could provide me
with the handle to the window just launched, it would be fine: I could
then use that handle to switch to the application, or kill it.

Thanks in advance.

Regards,
Carlos M Perez
 
P

Peter Foot [MVP]

If you know the window title you can use FindWindow to get the window
handle. Alternatively you could enumerate the top level windows and get
their process ids using GetWindowThreadProcessId, then match these to your
process ids from when you created the process.

Peter
 
?

=?iso-8859-1?q?Carlos_M._P=E9rez?=

And how could I enumerate the top level windows? All the routines I've
tried fail: even though I have the handle to the main application
window (with Win32Windows.GetActiveWindow() ) I don't know how to tell
the program to continue finding windows. I know I can't enumerate top
level windows using EnumWindows (I'm developing with the 1.1 CF)
because of the delegate functions, but how could I implement a similar
funcionality on CF 1.1?
 
?

=?iso-8859-1?q?Carlos_M._P=E9rez?=

Thanks, Alex. I've implemented your code using a Ventana (Window)
struct, like this:

private struct Ventana
{
public string Caption;
public IntPtr Handle;
public IntPtr WinHandle;
public Ventana(string cap, IntPtr hnd, IntPtr whnd)
{
Caption = cap;
Handle = hnd;
WinHandle = whnd;
}
}

and then using this code for the actual enumeration of windows:

public static ArrayList EnumerateTopWindows()
{
ArrayList winList = new ArrayList();
IntPtr hwnd = IntPtr.Zero;
System.Text.StringBuilder sb = null;
// Get the first window
hwnd = Win32Window.GetActiveWindow();
hwnd = Win32Window.GetWindow(hwnd,
Win32Window.GetWindowParam.GW_HWNDFIRST);
while(hwnd != IntPtr.Zero)
{
IntPtr parentWin = GetParent(hwnd);
// Make sure that the window doesn't have a parent
if ((parentWin == IntPtr.Zero))
{
int length = (int) GetWindowTextLength(hwnd);
// Check if it has caption text
if (length > 0)
{
Ventana ventana = new Ventana();
sb = new System.Text.StringBuilder(length + 1);
GetWindowText(hwnd, sb, sb.Capacity);
ventana.Caption = sb.ToString();
ventana.WinHandle = hwnd;
//Sacamos el handle del proceso
GetWindowThreadProcessId(ventana.WinHandle, out ventana.Handle);
winList.Add(ventana);
}
}
hwnd = Win32Window.GetWindow(hwnd,
Win32Window.GetWindowParam.GW_HWNDNEXT);
}
return winList;
}

The only differences (that I've been able to spot) between your code
and this are that I use my own struct Ventana instead of the Window[]
mentioned in your code; that I get the Process handle for each
enumerated window and pass it to the Ventana struct, and that I use the
OpenNETCF wrappers for some of the API functions. Apart from that, both
pieces of code are exactly equal. But mine generates an infinite loop:
I don't know why, but hwnd neves equals IntPtr.Zero.

Can you help me?

Regards,

Carlos Manuel Pérez
Truly in the shoulder of giants
 
?

=?iso-8859-1?q?Carlos_M._P=E9rez?=

If it further helps any of you, the infinite loop occurs only when
testing the application on the WinCE emulator. I've just tried this
application on the destination device, and there it (semi) works. It
does not freeze because of an infinite loop, but it fails to display
some top level windows.

I've made some buttons that launch test applications like Word, the
Control panel, FreeCell, Windows Explorer, etc. All of them are
correctly displayed on the ListBox I've made, except Explorer. Is that
window an exception I should treat specially?

Thanks and regards,

Carlos M Perez
Truly in the shoulder of giants
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top