How Can I Move The Window Like I Want With WinApi - c#

When I try to drag my window with this the window jumps and flickers around:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOVE)
{
int x = (m.LParam.ToInt32() & 0xffff);
int y = ((m.LParam.ToInt32() >> 16) & 0xffff);
if (x < 500)
Location = new Point(0, y);
else
base.WndProc(ref m);
}
else
base.WndProc(ref m);
}
must stop jumping
WM_MOVE, WM_MOVING, WM_WINDOWPOSCHANGING or other move event must continue firing while dragging the window because I want every new position to be checked.
another problem is Location = new Point(0, y); fires another move event (this one should be ignored)
Please help!

Here's an example of using WM_WINDOWPOSCHANGING and modifying the WINDOWPOS structure:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public uint flags;
}
public const int WM_WINDOWPOSCHANGING = 0x46;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_WINDOWPOSCHANGING:
WINDOWPOS wp = (WINDOWPOS)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
if (true) // ... if somecondition ...
{
// modify the location with x,y:
wp.x = 0;
wp.y = 0;
}
System.Runtime.InteropServices.Marshal.StructureToPtr(wp, m.LParam, true);
break;
}
base.WndProc(ref m);
}
}

This should do what you want:
protected override void WndProc(ref Message message)
{
const Int32 WM_SYSCOMMAND = 0x0112;
const Int32 SC_MOVE = 0xF010;
switch (message.Msg)
{
case WM_SYSCOMMAND:
Int32 command = message.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
{
Left = 0;
Top = 0;
return;
}
break;
}
base.WndProc(ref message);
}
Hans Passant suggested the LocationChanged event, and it can work quite nicely. In this example, the window is frozen at 0, 0 until the mouse pointer gets outside of a 500, 500 box:
private void Form1_LocationChanged(Object sender, EventArgs e)
{
if (MousePosition.X > 500 || MousePosition.Y > 500)
Location = MousePosition;
else
Location = new Point(0, 0);
}

Related

How do I set default to the minimum size my form on resize?

Sorry because my english is very bad !
I resize my form with WM_SIZE message, how can I set the minimum size for my form? I want the smallest size of the form to be 200x100
Here is my code:
protected override void WndProc(ref Message m)
{
const int RESIZE_HANDLE_SIZE = 10;
switch (m.Msg)
{
case 0x0084/*NCHITTEST*/ :
base.WndProc(ref m);
if ((int)m.Result == 0x01/*HTCLIENT*/)
{
Point screenPoint = new Point(m.LParam.ToInt32());
Point clientPoint = this.PointToClient(screenPoint);
if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)12/*HTTOP*/ ;
else
m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
}
else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)10/*HTLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)2/*HTCAPTION*/ ;
else
m.Result = (IntPtr)11/*HTRIGHT*/ ;
}
else
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)15/*HTBOTTOM*/ ;
else
m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
}
}
return;
}
base.WndProc(ref m);
}
If you want pInvoke solution (I see IntPtr, NCHITTEST etc. in your current code) you can try WM_GETMINMAXINFO message.
First, we want MINMAXINFO and POINT structs:
using System.Runtime.InteropServices;
...
[StructLayout(LayoutKind.Sequential)]
internal struct POINT {
public int X;
public int Y;
public POINT(int x, int y) {
X = x;
Y = y;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct MINMAXINFO {
public POINT ptReserved;
public POINT ptMaxSize;
public POINT ptMaxPosition;
public POINT ptMinTrackSize;
public POINT ptMaxTrackSize;
}
Then
protected override void WndProc(ref Message m) {
...
switch (m.Msg) {
...
case 0x0024: { // WM_GETMINMAXINFO
MINMAXINFO info = Marshal.PtrToStructure<MINMAXINFO>(m.LParam);
info.ptMinTrackSize = new POINT(
Math.Max(200, info.ptMinTrackSize.X), // smallest X (width)
Math.Max(100, info.ptMinTrackSize.Y)); // smallest Y (height)
Marshal.StructureToPtr(info, m.LParam, true);
break;
}
...
}

Using multiple keys when the form is not focused

I want to use multiple keys to do different things while the form is not focused.
What I have done already: I have done only one key to print out a certain text when the form is not focused.
// DLL libraries used to manage hotkeys
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
const int F1_HOTKEY_ID = 1;
const int F2_HOTKEY_ID = 1;
public Form1()
{
InitializeComponent();
// Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8
// Compute the addition of each combination of the keys you want to be pressed
// ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6...
RegisterHotKey(this.Handle, F1_HOTKEY_ID, 0, (int)Keys.F1);
RegisterHotKey(this.Handle, F2_HOTKEY_ID, 0, (int)Keys.F2);
}
private void Form1_Load(object sender, EventArgs e)
{
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == F1_HOTKEY_ID)
{
SendKeys.Send(txtBoxF1.Text + "{enter}");
}
base.WndProc(ref m);
}
Now I want to use multiple keys and this is what I tried:
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == F1_HOTKEY_ID)
{
SendKeys.Send(txtBoxF1.Text + "{enter}");
}
if (m.Msg == 0x0312 && m.WParam.ToInt32() == F2_HOTKEY_ID)
{
SendKeys.Send(txtBoxF2.Text + "{enter}");
}
base.WndProc(ref m);
}
But that prints out both F1 and F2 texts when I want it to print out f2 individually.
Thank you.

Is it possible to make a C# form non movable [duplicate]

How would i go about stopping a form from being moved. I have the form border style set as FixedSingle and would like to keep it this way because it looks good in vista :)
Take a look at this link. You might be interested in option #3. It will require you to wrap some native code, but should work. There's also a comment at the bottom of the link that shows an easier way to do it. Taken from the comment (can't take credit for it, but I'll save you some searching):
protected override void WndProc(ref Message message)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xF010;
switch(message.Msg)
{
case WM_SYSCOMMAND:
int command = message.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
return;
break;
}
base.WndProc(ref message);
}
You can set the FormBorderStyle property of the Form to None
this.FormBorderStyle=System.Windows.Forms.FormBorderStyle.None
I found this to stop the form from moving (its in c#)
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xF010;
switch (m.Msg)
{
case WM_SYSCOMMAND:
int command = m.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
return;
break;
}
base.WndProc(ref m);
}
Found here
Try to override WndProc:
protected override void WndProc(ref Message m)
{
const int WM_NCLBUTTONDOWN = 161;
const int WM_SYSCOMMAND = 274;
const int HTCAPTION = 2;
const int SC_MOVE = 61456;
if ((m.Msg == WM_SYSCOMMAND) && (m.WParam.ToInt32() == SC_MOVE))
{
return;
}
if ((m.Msg == WM_NCLBUTTONDOWN) && (m.WParam.ToInt32() == HTCAPTION))
{
return;
}
base.WndProc(ref m);
}
It's not all pretty (there is some flashing going on when you try to move the form), but you can use the LocationChanged property to keep the form where you want it:
private Point _desiredLocation;
// assign the _desiredLocation variable with the form location at some
// point in the code where you know that the form is in the "correct" position
private void Form_LocationChanged(object sender, EventArgs e)
{
if (this.Location != _desiredLocation)
{
this.Location = _desiredLocation;
}
}
Out of curiousity; why would you want to do this?
In Windows, the WS_CAPTION style is the non-client area that allows your window to be moved with a mouse. So the easiest way to do what you want is to remove this style from your window.
However, if you need to have a caption and still achieve what you want, then the next style would be to capture the WM_NCHITTEST message and check for HTCAPTION. If the code is HTCAPTION, return NTNOWHERE instead. This will prevent the default window procedure from executing the default move window thing.
It's not a good practice to make your form immovable. I'd think agfain about it if I were you.
Anyway, you can do this by overridding the WinProc to disable the [Move] menuitem from the system menu.
[DllImport("user32.dll")]
private static extern Int32 EnableMenuItem ( System.IntPtr hMenu , Int32uIDEnableItem, Int32 uEnable);
private const Int32 HTCAPTION = 0×00000002;
private const Int32 MF_BYCOMMAND =0×00000000;
private const Int32 MF_ENABLED =0×00000000;
private const Int32 MF_GRAYED =0×00000001;
private const Int32 MF_DISABLED =0×00000002;
private const Int32 SC_MOVE = 0xF010;
private const Int32 WM_NCLBUTTONDOWN = 0xA1;
private const Int32 WM_SYSCOMMAND = 0×112;
private const Int32 WM_INITMENUPOPUP = 0×117;
protected override void WndProc(ref System.Windows.Forms.Message m )
{
if (m.Msg == WM_INITMENUPOPUP)
{
//handles popup of system menu
if ((m.LParam.ToInt32() / 65536) != 0) // 'divide by 65536 to get hiword
{
Int32 AbleFlags = MF_ENABLED;
if (!Moveable)
{
AbleFlags = MF_DISABLED | MF_GRAYED; // disable the move
}
EnableMenuItem(m.WParam, SC_MOVE, MF_BYCOMMAND | AbleFlags);
}
}
if (!Moveable)
{
if (m.Msg == WM_NCLBUTTONDOWN) //cancels the drag this is IMP
{
if (m.WParam.ToInt32() == HTCAPTION) return;
}
if (m.Msg == WM_SYSCOMMAND) // Cancels any clicks on move menu
{
if ((m.WParam.ToInt32() & 0xFFF0) == SC_MOVE) return;
}
}
base.WndProc(ref m);
}
Also, you can handle OnMove event of your form. But I think this will cause some flickering:
private void Form1_Move(object sender, EventArgs e)
{
this.Location = defaultLocation;
}
Just change the FormBorderStyle property to None.
change the Form property StartPostion to Manual.
Then, handle the LocationChanged event:
private void frmMain_LocationChanged(object sender, EventArgs e)
{
Location = new Point(0, 0);
}
Go to form events-> Location changed
write the following code
Location = new Point(this.Width,this.Height);
I would question your need to make the form unmovable. This doesn't sound nice. You could of course save the location of the window when the window closes and reopen the window into that position. That gives the user some control over where the window should be located.
You can subscribe to the Form.Move event and reposition from it.
Just reset the location on formlocation_changed event to where it was i.e. set the Form.Location to a variable before it's moved and when the user tries to move it, it will go back to the variable location you set it to.
Private Sub MyFormLock()
Me.Location = New Point(0, 0)
End Sub
Private Sub SearchSDR_LocationChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LocationChanged
Call MyFormLock()
End Sub
You can try:
this.Locked = true;

How to override the minimize control?

I want to override the minimize control to instead of sending the window to the taskbar it would do what ever I write it to do.
Basicly this is what I wanted my new minimized and restored effects to be:
private void ChangeForm(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
this.Height = 80;
iDebug.Visible = false;
mainMenu.Visible = false;
}
else
{
this.Height = 359;
iDebug.Visible = true;
mainMenu.Visible = true;
}
}
I have tried to fire an Event on the Resize to do this but without success
this.Resize += new EventHandler(ChangeForm);
Cancel A WinForm Minimize?
Just tested this and it will make the form 100 pixels shorter when minimize is clicked without flicker.
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_MINIMIZE = 0xf020;
protected override void WndProc(ref Message m) {
if (m.Msg == WM_SYSCOMMAND) {
if (m.WParam.ToInt32() == SC_MINIMIZE) {
m.Result = IntPtr.Zero;
Height -= 100;
return;
}
}
base.WndProc(ref m);
}
The Minimize command has a very well defined meaning to a user, it shouldn't be messed with. Winforms accordingly doesn't have an event for it. But not a real problem, you can detect any Windows message by overriding WndProc(). Like tihs:
private void OnMinimize() {
this.Close(); // Do your stuff
}
protected override void WndProc(ref Message m) {
// Trap WM_SYSCOMMAND, SC_MINIMIZE
if (m.Msg == 0x112 && m.WParam.ToInt32() == 0xf020) {
OnMinimize();
return; // NOTE: delete if you still want the default behavior
}
base.WndProc(ref m);
}

How to avoid flickering in treeview

how to avoid flickering in treeview,
when some property of nodes is gettng updated,
or the node is added
Try the following:
try
{
treeView.BeginUpdate();
// Update your tree view.
}
finally
{
treeView.EndUpdate();
}
I was fighting this, too. Here is my solution for those of you searching out there. Add this to your treeview subclass.
private const int WM_VSCROLL = 0x0115;
private const int WM_HSCROLL = 0x0114;
private const int SB_THUMBTRACK = 5;
private const int SB_ENDSCROLL = 8;
private const int skipMsgCount = 5;
private int currentMsgCount;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_VSCROLL || m.Msg == WM_HSCROLL)
{
var nfy = m.WParam.ToInt32() & 0xFFFF;
if (nfy == SB_THUMBTRACK)
{
currentMsgCount++;
if (currentMsgCount % skipMsgCount == 0)
base.WndProc(ref m);
return;
}
if (nfy == SB_ENDSCROLL)
currentMsgCount = 0;
base.WndProc(ref m);
}
else
base.WndProc(ref m);
}
I got the idea here: treeview scrollbar event
Basically I am just ignoring a significant percentage of the scroll messages. It reduces flicker a lot for me.

Categories

Resources