gciochina
3rd February 2009, 02:46 PM
Hello!
Couldn't find a similar question, sorry if it's been posted before.
I'm working on a mobile application written in C# .Net CF 2.0 for WM 5/6/6.1
Currently the client has asked us to customize the Close(X)/Ok button on the right upper corner of the screen (the button that closes the form/application).
I'm talking about this button.
http://img5.imageshack.us/img5/4016/standardlayoutwq5.th.jpg (http://img5.imageshack.us/my.php?image=standardlayoutwq5.jpg)
He wants us to change it's look&feel (meaning that the button would be represented using a picture, and upon clicking a form should open.)
Like this:
http://img5.imageshack.us/img5/9472/genericlayoutyo7.th.jpg (http://img5.imageshack.us/my.php?image=genericlayoutyo7.jpg)
Is this possible? I know this means redrawing the NonClient area, but how exactly do i do this?:)
And could this be done using API calls? what api calls should me made in this case?
Thanks.
gciochina
6th February 2009, 08:59 AM
cmooon guys, the deadline is getting closer :(
gciochina
12th February 2009, 08:53 AM
Okay. With the delivery set for tonite, I've managed to pull it through. In order to do this, we have to get the handle of the task Bar, using p/Invoke FindWindow("HHTaskBar",...). Then using a Graphics object created from the device context of the window "found" above, we paint a picture over the "OK" button (the form must have it's properties set to MinimizeBox = false and ControlBox = true, in order for the custom WndProc to handle messages when clicking the region of the task bar where we are painting. Below is the code sample. Cheers mates :)
public class MyForm : System.Windows.Forms.Form
{
#region members and delegates
delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("CoreDll.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string className, string WindowsName);
[DllImport("coredll.dll", EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("coredll.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr newWndProc);
[DllImport("coredll.dll")]
static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("coredll.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("coredll.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
private const int GWL_WNDPROC = -4;
private static WndProcDelegate newWndProc;
private static IntPtr oldWndProc = IntPtr.Zero;
bool userPressed = false;
ResourceManager resManager;
#endregion
#region ctor
public MyForm ()
{
InitializeComponent();
}
#endregion
#region meths
private void InitializeComponent()
{
this.ControlBox = false;
this.Closing += new System.ComponentModel.CancelEventHandler(this.OnCl osing);
this.Load += new System.EventHandler(this.OnLoad);
resManager = new ResourceManager("PATH_TO_PICTURE", Assembly.GetCallingAssembly());
}
private void OnLoad(object sender, EventArgs e)
{
newWndProc = new WndProcDelegate(WndProc);
oldWndProc = GetWindowLong(this.Handle, GWL_WNDPROC);
int success = SetWindowLong(this.Handle, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(newWndProc)) ;
}
public IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
//we are targeting a specific sequence (31 , 273) that will tell us when the user clicks on the picture
IntPtr retVal = IntPtr.Zero;
switch (msg)
{
case 273:
if (userPressed)
{
userPressed = false;
Execute();
}
break;
case 31:
userPressed = true;
break;
default:
if (msg != 307)
userPressed = false;
DrawCustomBtn();
//retVal = CallWindowProc(oldWndProc, this.Handle, msg, wParam, lParam);
break;
}
return IntPtr.Zero;
}
private void Execute()
{
//do something
}
public void DrawCustomBtn()
{
try
{
IntPtr hwnd = FindWindow("HHTaskBar", null);
if (!hwnd.Equals(IntPtr.Zero))
{
IntPtr hDC = GetWindowDC(hwnd);
Graphics g = Graphics.FromHdc(hDC);
g.DrawImage((Bitmap)resManager.GetObject("icon_upper_right"), this.Width - ((Bitmap)resManager.GetObject("icon_upper_right")).Width - 4, 4);
g.Dispose();
ReleaseDC(hwnd, hDC);
}
}
catch (DllNotFoundException dllex)
{
throw dllex;
}
catch (Exception ex)
{
throw ex;
}
}
public void OnClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
try
{
if (Microsoft.WindowsCE.Forms.SystemSettings.ScreenOr ientation != Microsoft.WindowsCE.Forms.ScreenOrientation.Angle0 )
Microsoft.WindowsCE.Forms.SystemSettings.ScreenOri entation = Microsoft.WindowsCE.Forms.ScreenOrientation.Angle0 ;
}
catch (Exception ex)
{
Log.WriteInfoLog("RESIZING : rotation failed in : " + this.Name + " Message: " + ex.Message );
}
}
#endregion
}
Ather
12th February 2009, 03:25 PM
an another work around could be to make the app full screen, later create a picturebox ;)
gciochina
18th February 2009, 09:19 AM
Thanks for the suggestion! :)
Yes, indeed you are right, when it can be applied, i too recommend that the application be made full screen and the buttons be added after.
But the solution above is for the case when there is still need for the "start" button and status bar to be shown. anyways, i've solved the issue, the management is happy, the client is happy so everything went okay ;)
vBulletin® v3.8.7, Copyright ©2000-2012, vBulletin Solutions, Inc.