.NET Framework - Control.FromHandle for Compact Framework

Asked By jhow
26-Oct-09 12:08 PM
I am trying to find a way to create a .NET form or control from a
window outside my own application (I know the handle of the window).
The desktop way would be to simply call Control.FromHandle, but this
method does not exist in the Compact Framework.

Are there any workarounds for this?
System.Runtime.InteropServices
(1)
Compact Framework
(1)
System.Windows.Forms
(1)
GetLastWin32Error
(1)
OpenNETCF
(1)
Control.FromHandle
(1)
CharSet.Unicode
(1)
UnmanagedType
(1)
  Paul G. Tobey [eMVP] replied...
12-Aug-09 11:26 AM
What do you want to *do* with it?  That should control what you do next...

Paul T.
  jhow replied...
26-Oct-09 12:08 PM
I have a small popup window in my application that I would like to
make a child of the startbar. I believe if I do this, it will stop the
window being hidden by the startbar.

As a result, I would like to get the handle of the startbar, create a
control from it and set it as the Owner of my popup.
  Chris Tacke, MVP replied...
14-Aug-09 05:48 PM
Sounds like a kludge to me, but you do not need Control.FromHandle for that
anyway.  You're P/Invoking to find the Start bar's handle, just P/Invoke
SetParent to reparent your dialog.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
  jhow replied...
26-Oct-09 12:08 PM
Thanks Chris, yes it is a kludge, but I have racked my brains over this
one and it is the only way I can think of. Using the Topmost property
only works until some other window such as the Startbar bumps it off
the top of the z-order. Do you have any better ideas?

I tried your SetParent solution but this fails for some reason. Any
ideas why?

[DllImport("Coredll.dll", EntryPoint="FindWindow",
CharSet=CharSet.Unicode)]
public static extern IntPtr FindWindow(string _WindowClassName, string
_WindowName);

[DllImport("Coredll.dll", EntryPoint="SetParent", CharSet =
CharSet.Unicode)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr
hWndParent);

_pickerForm = new PickerForm();

//not necessary, but just in case
_pickerForm.Owner = null;

//returns a valid handle
IntPtr handle = FindWindow("HHTaskBar", null);

//shows "0" indicating failure
MessageBox.Show(SetParent(_pickerForm.Handle, handle).ToString());

//even this.Handle does not work
MessageBox.Show(SetParent(_pickerForm.Handle, this.Handle).ToString
());
  jhow replied to jhow
26-Oct-09 12:08 PM
Is there anybody out there?
  Paul G. Tobey [eMVP] replied to jhow
19-Aug-09 10:57 AM
I do not believe that this is going to be possible.  You've got a process
boundary there that should not be broken and that I am certain is not
designed to be broken by the .NET CF.  Here is what I'd do:

Forget about managed code and try this in native code.  If you cannot make
that work (and that would not surprise me one bit), trying to do it from
managed code is a waste of time.

If it does not work, think about other ways that you might achieve what you
need.  You need a pop up window of some sort associated with the taskbar,
right?  What about a notification balloon associated with an icon in the
system tray?  This breaks through the process barrier and has the shell
present what you give it and then sends you messages associated with user
actions.  it is also supported...

Paul T.
  jhow replied to Paul G. Tobey [eMVP]
26-Oct-09 12:08 PM
A notification window is not quite what I am looking for and I know
what I am trying to do is possible, because I have seen it done in at
least 3 other applications before. It is quite a common feature in
dictionary applications.

What I am looking for is something like this:
http://www.pda4x.com/attachmentes/Day_080509/65_73680_db2b3_pxdxa.Screenshot_2.jpg

or the same popup dragged to a different position on the startbar
here:
http://wronek.wdfiles.com/local--files/mdict/mdict.JPG

If you look at the start bar on the first image, you will see a small
popup window (cum button) (aka picker window) to the right of the
title "MDict". This popup can be freely dragged about anywhere in the
startbar region, and, despite what happens to the start bar, it always
stays "on top".

Other dictionary applications allow their picker windows to be dragged
about anywhere within the entire screen area and also manage to always
stay topmost.

I am just puzzled as to how they do it. Do these images and this
explanation shed any light to you on a possible solution?
  Paul G. Tobey [eMVP] replied to jhow
20-Aug-09 11:05 AM
It looks to me like there is either a system tray item being added or just a
front-most window that gets pushed to the top of the stack all the time.  If
you just say, "I need a floating window to always be on top of everything,
even the start menu.", the first thing that comes to mind is "topmost".  Of
course, other topmost windows will try to come to the front when you select
them, but I do not see any reason why you could not push yourself back on top
as soon as you detect that.

Paul T.
  Christopher Fairbairn [MVP] replied to jhow
20-Aug-09 09:20 PM
Hi,


They probably are doing this by reparenting their window to the window which
represents the navbar.

Within C# / .NET CF it is all a bit of a hack (and I would not really even
recommend doing it at the native level...) but if you follow these
instructions hopefully it is something close to what you want...

Start off by adding a new form to your project (I called it "IconForm"), and
set the following properties.

FormBorderStyle = none
MaximizeBox = false
ControlBox = false
Size = 24,24

Also make sure you delete the MainMenu instance.

Then add the following class to your project

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public static class FormExtensions
{
public static void ReparentToNavBar(this Form form, Point location)
{
IntPtr hWndParent = FindWindow("HHTaskBar", null);
Reparent(form, hWndParent, location);
}

// Reparents "form" to be a child of "hWndParent" positioned
// using the x,y co-ordinates specified by "location".
public static void Reparent(this Form form, IntPtr hWndParent, Point
location)
{
IntPtr hWndChild = form.Handle;

// Remove the WS_POPUP window style and
// add the WS_CHILD window style
uint style = GetWindowLong(hWndChild, GWL_STYLE);
style &= ~WS_POPUP;
style |= WS_CHILD;
SetWindowLong(hWndChild, GWL_STYLE, style);

// Reparent the window
SetParent(hWndChild, hWndParent);

// Adjust the positioning of the form
form.Location = location;
}

private const uint WS_POPUP = 0x80000000;
private const uint WS_CHILD = 0x40000000;

private const uint WS_EX_TOPMOST = 0x00000008;

private const int GWL_STYLE = -16;
private const int GWL_EXSTYLE = -20;

[DllImport("coredll.dll")]
private static extern uint GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("coredll.dll")]
private static extern uint SetWindowLong(IntPtr hWnd, int nIndex, uint
dwNewLong);

[DllImport("coredll.dll")]
private static extern IntPtr FindWindow(string lpClassName, string
lpWindowName);

[DllImport("coredll.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr
hWndNewParent);
}

Once this has been done, you should be able to add a button click event
handler or something similiar to invoke the code to add your custom window
to the nav bar. A code snippet similiar to the following should be
sufficient:

Form f = new IconForm(); // or what ever you named your custom form
f.Show();
f.ReparentToNavBar(new Point(45, 0));

And to remove it, you would simply execute

f.Close();
f.Dispose();

You should see that this window appears on the top of your screen, and
  jhow replied to Paul G. Tobey [eMVP]
26-Oct-09 12:08 PM
The problem is how would I detect it?
  jhow replied to Christopher Fairbairn [MVP]
26-Oct-09 12:08 PM
You are right Christopher. I did a Remote Spy on my mobile device and
found that the MDict dictionary picker is being attached as a child to
the navbar. (I have noticed another app (Magic Button) has also attached
itself there, so it seems it is not such an uncommon practice).

Another problem has arisen though. I would like my application, to sit
on top of all the other children on the navbar. The MDict dictionary
picker, as soon as it is turned on, always manages to get to the top
of the z-order. I can see this visually on my mobile screen as well as
in the order it is listed in Remote Spy.

I copied and tweaked this code from pinvoke.net but cannot seem to get
it to work:

static public class FormHelper2
{
[DllImport("coredll.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr
hWndInsertAfter,
int x, int y, int cx, int cy, uint uFlags);

public const int SWP_NOMOVE = 0x0002;
public const int SWP_NOSIZE = 0x0001;

public const int HWND_TOPMOST = -1;

public static void MakeTopMost(Form form)
{
//THIS RETURNS TRUE
bool b = SetWindowPos(form.Handle, (IntPtr)HWND_TOPMOST, 0, 0,
0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
  jhow replied to Paul G. Tobey [eMVP]
26-Oct-09 12:08 PM
Paul, the problem is how would I detect that?
  jhow replied to Christopher Fairbairn [MVP]
26-Oct-09 12:08 PM
You are right Christopher. I did a Remote Spy on my mobile device and
found that the MDict dictionary picker is being attached as a child to
the navbar. (I have noticed another app (Magic Button) has also attached
itself there, so it seems it is not such an uncommon practice).

As a result I used the code you kindly provided and it does work.
Thanks for that.

But another problem has arisen. I would like my application, to sit on
top of all the other children on the navbar. The MDict dictionary
picker, as soon as it is turned on, always manages to get to the top
of the z-order. I can see this visually on my mobile screen as well as
in the order it is listed in Remote Spy and would like to do this for
my app as well.

I copied and tweaked this code from pinvoke.net, but cannot seem to get
it to work. The SetWindowPos() method below returns true, but the
window behaviour on my mobile screen and Remote Spy both indicate that
my window is still at the bottom of the Z order. Any ideas?

(By the way, the extended style for my window is WS_EX_TOPMOST).

static public class FormHelper2
{
[DllImport("coredll.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr
hWndInsertAfter,
int x, int y, int cx, int cy, uint uFlags);

public const int SWP_NOMOVE = 0x0002;
public const int SWP_NOSIZE = 0x0001;

public const int HWND_TOPMOST = -1;

public static void MakeTopMost(Form form)
{
bool b = SetWindowPos(form.Handle, (IntPtr)HWND_TOPMOST, 0, 0,
0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
  Chris Tacke, MVP replied to jhow
23-Aug-09 09:50 PM
When SetParent fails, what does GetLastWin32Error return (and you have to
enable that in C#).


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
  Chris Tacke, MVP replied to jhow
23-Aug-09 09:53 PM
I'd be inclined to use Spy++ and actually look to see what the handle
relationships actually are instead of guessing based on behavior.  it is a
lot more reliable.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
  Paul G. Tobey [eMVP] replied to jhow
24-Aug-09 12:44 PM
Changes in frontmost order should appear.  Again, Spy++...

Paul T.
  jhow replied to Paul G. Tobey [eMVP]
26-Oct-09 12:08 PM
I mean how would I detect it programmatically?

Anyone have any suggestions as to why my SetWindowPos(form.Handle,
(IntPtr)HWND_TOPMOST, 0, 0,
0, 0, SWP_NOMOVE | SWP_NOSIZE); mentioned above is not working?
Unfortunately this is returning a true value indicating success, so
that would mean GetLastError is irrelevant.

However the behaviour, and Spy++ shows that the method is not working.
In Spy++ my window still sits at the bottom of the z-order of the
Navbar's children, and visually, it is getting hidden by the other
children.
  Paul G. Tobey [eMVP] replied to jhow
26-Aug-09 11:24 AM
Look for the messages sent to you when you are no longer frontmost.  You'll
get an NCACTIVATE message, indicating that you are not in front any more,
and an ACTIVATE message indicating the same. When you get one of those, you
can adjust yourself to be in front again (although you should probably take
care, in that case, that there are not a bunch of these windows floating
around or you might get in a war, each trying to force itself to the front
endlessly).

It works fine for me.  Perhaps your parameter values are wrong (flags or
HWND_TOPMOST), or you are calling things in the wrong order or something.  I
did a FindWindow to find my Windows CE taskbar, a SetParent to set it to the
parent of my window, and a SetWindowPos to make it topmost and it works
exactly as I'd hope.  I am not using Pocket PC, so I cannot promise that it
will work the same there, but I would expect it to.

Paul T.


I mean how would I detect it programmatically?

Anyone have any suggestions as to why my SetWindowPos(form.Handle,
(IntPtr)HWND_TOPMOST, 0, 0,
0, 0, SWP_NOMOVE | SWP_NOSIZE); mentioned above is not working?
Unfortunately this is returning a true value indicating success, so
that would mean GetLastError is irrelevant.

However the behaviour, and Spy++ shows that the method is not working.
In Spy++ my window still sits at the bottom of the z-order of the
Navbar's children, and visually, it is getting hidden by the other
children.
  jhow replied to Paul G. Tobey [eMVP]
26-Oct-09 12:08 PM
Will I really receive NCACTIVATE or ACTIVATE messages when I lose
topmost status?

I thought these messages were only for when a window lose active
status. Often when my window is topmost, it will not be the active
application, and therefore will not be deactivated when it loses its
topmost position.
  Paul G. Tobey [eMVP] replied to jhow
27-Aug-09 12:08 PM
You are not losing topmost status, but yes, on Windows CE 5, a topmost
window will get a WM_NCACTIVATE and a WM_ACTIVATE message when another
topmost window comes in front of it.  You are just not the top of the
topmost windows.  It seems that you may need to read-up on what topmost is
all about and play around with ordinary windows being topmost or not.
Topmost windows are a class of windows, not a single window on the device.
You can half half-a-dozen topmost windows at a time.  It should be obvious
that only one is going to be the top window of that group, just as on
Windows on the desktop, you have a stack of windows with the active window
on top, but potentially still have the Start menu above those windows (the
Start menu is part of the taskbar which is topmost by default in Windows).

Paul T.
Create New Account
help
Conversion form previous VS .NET Framework In the past converted an application written in an old (<2005) VS to VS 2005 void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InvoiceForm)); this.textBox17 = new System.Windows.Forms.TextBox(); this.textBox15 = new System.Windows.Forms.TextBox(); this.textBox7 = new System.Windows.Forms.TextBox(); this.textBox6 = new System.Windows.Forms.TextBox(); this.textBox5 = new System.Windows
WIA - Problem with Com .NET Framework Hi all, I am having problems with the WIA Com object and I am not Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using WIA; using System.Runtime.InteropServices; using System.Configuration; namespace Scan { public partial class Test : Form { private const int WIA_DPS_DOCUMENT_HANDLING_SELECT_FEEDER = 1 Now.ToFileTime().ToString(); string FileName = "c: \ tempimage_" + scanTime + ".jpg"; img[ScanCount].SaveFile(FileName); C# Discussions System.Windows.Forms.ButtonBase.WndProc (1) System.Windows.Forms.Control.WmMouseUp (1) System.Windows.Forms.Button
Null Reference exception in user app- debug help needed! (.NET 1.1 ) .NET Framework Hi, I have been investigating a 'System.NullReferenceException' for about a week but have not in VS 2003 as follows. . . A first chance exception of type 'System.NullReferenceException' occurred in system.windows.forms.dll Additional information: Object reference not set to an instance of an object. the call stack at this time looks like- (Word-wrap may make this look nasty) system.windows.forms.dll! System.Windows.Forms.ListView.ListViewItemCollection.get_Item(int displayIndex = 0x97) + 0x147 bytes system.windows.forms.dll! System
Problems with Specialized ComboBox in DataGridViewColumn .NET Framework The attached specialized combo boxes allows the use of the keyboard to find a selected of How to Host Controls in Windows Forms DataGridView Cells. I get: System.NullReferenceException at System.Windows.Forms.DataGridViewComboBoxCell.ComboBox_DropDown(Object sender, EventArgs e) at System.Windows.Forms.ComboBox.OnDropDown(EventArgs e) at System.Windows.Forms.ComboBox.WmReflectCommand(Message& m) at System.Windows.Forms.ComboBox.WndProc(Message& m) at
C#_2008]_ __.COMException_non_è_stata_gestita .NET Framework Finalmente ho trovato il newsgroup di C#!! Vengo al mio problema. Con C# 2008 ho dettaglio dell'errore, ho riportato anche il codice presente sul bottone dell form. Dettaglio errore: System.Runtime.InteropServices.COMException non ? stata gestita Message = "Non ? attivo alcun riferimento del modello" Source = "MicroStationDGN.Application.1 e) in C: \ Users \ Administrator \ AppData \ Local \ Temporary Projects \ WindowsFormsApplication1 \ Form1.cs:riga 39 in System.Windows.Forms.Control.OnClick(EventArgs e) in System.Windows.Forms.Button.OnClick(EventArgs e) in System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) in