Custom form designer, move/resize controls using WinAPI - c#

I have to fix some problems and enchance form designer written long ago for a database project.
In Design Panel class code I encountered these lines
private void DesignPanel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
(sender as Control).Capture = false;
switch (FMousePosition)
{
case MousePosition.mpNone:
SendMessage((sender as Control).Handle, WM_SYSCOMMAND, 0xF009, 0);
break;// Move
case MousePosition.mpRightBottom:
SendMessage((sender as Control).Handle, WM_SYSCOMMAND, 0xF008, 0);
break;//RB
case MousePosition.mpLeftBottom:
SendMessage((sender as Control).Handle, WM_SYSCOMMAND, 0xF007, 0);
// ... here are similar cases ...
case MousePosition.mpLeft:
SendMessage((sender as Control).Handle, WM_SYSCOMMAND, 0xF001, 0);
break;//L
}
}
}
FMousePosition indicates whether mouse was over any edge of selected control.
What confusing me is these windows messages: it seems there is no documentation on WM_SYSCOMMAND with parameters 0xF001-0xF009 (maybe it starts some kind of 'drag/resize sequence'). Any ideas?
If my suggestion is right, then how can I cancel these sequences?

They are undocumented parameters. After searching I managed to find this list.
0xF000 (SC_SIZE, Center cursor on the form)
0xF001 (SC_SZLEFT, Resize from left)
0xF002 (SC_SZRIGHT, Resize from right)
0xF003 (SC_SZTOP, Resize from top)
0xF004 (SC_SZTOPLEFT, Lock the bottom right corner of the form, the top left corner move for resize)
0xF005 (SC_SZTOPRIGHT, Same from bottom left corner)
0xF006 (SC_SZBOTTOM, Lock top right and left border, resize bottom)
0xF007 (SC_SZBOTTOMLEFT, Lock top and right border, resize other border)
0xF008 (SC_SZBOTTOMRIGHT, Lock left and top border and resize other)
0xF009 (SC_SIZE|0x9, Drag from anywhere)
0xF00F (SC_SEPARATOR)
0xF010 (SC_MOVE, Put cursor centered at the upper order)
0xF012 (SC_DRAGMOVE, move by dragging)
0xF020 (SC_MINIMIZE, Auto-Minimize Form)
0xF030 (SC_MAXIMIZE, Auto-Maximize Form)
0xF040 (SC_NEXTWINDOW, Stop! You don't want that, it will lock all mouse click and make you reboot)
0xF148 (SC_SCREENSAVE|0x8, Activate ScreenSaver)
0xF13E (SC_TASKLIST|0xE, Activate StartButton)
Reference: http://www.delphi3000.com/articles/article_1054.asp#Comments

Based on my Win32 Programming (Rector and Newcomer) p902-903 explains WM_SYSCOMMAND is sent when the user selects an item from the system menu (rather than sending the normal WM_COMMAND).
The MSDN help says SC_SIZE = 0xF000 and it and Win32 Programming also say Windows uses the four low-order bits of the predefined system menu IDs internally but doesn't go on to clarify their use. Thanks stukelly for clarifying them.

Related

Prevent rendering of the desktop selection rectangle

I'm working on small program that basically animates the wallpaper using OpenGL.
The wallpaper is all interactive(I use a global mouse hook for the mouse events), but to make it perfect when I hold down the left mouse button, I'd like the selection rectangle to not appear at all.
All I could change was disable the translucent selection rectangle using a registry key and a P/Invoke function to force the desktop to reload it's registry settings, resulting in this:
On the image you can see the selection outline which would be great if wasn't rendered when I hold and drag.
Is it possible to achieve using C#?
EDIT:
There is a partial solution to this problem that #Jonathan Potter provided:
W32.EnumChildWindows(W32.GetDesktopWindow(), (hwnd, param) =>
{
var WM_CANCELMODE = 0x001F;
var sb = new StringBuilder(256);
if (W32.GetClassName(hwnd, sb, 256) > 0)
{
if (sb.ToString() == "SysListView32")
W32.SendMessage(hwnd, WM_CANCELMODE, 0, IntPtr.Zero);
}
return true;
}, IntPtr.Zero);
The problem with this solution is that now whenever I try selecting anything on the desktop, it won't, since I am literally cancelling the selection just as I begin holding the mouse button.

Winrt - Adjusting flyout according to where it appears

I have a GridView in a windows store project, that contains some big squares, and inside those i have a list of user images, when i tap on of those images a flyout appears on the right showing some information like this.
the problem is that my gridview extends to the edges of the screen and beyond, and when that does i get this situation, i press the user with the red border near the edge of the screen and flyout appears on left.
My flyout placement is set to Right, and im guessing since the element i press is near the edge it follows the Fall back order with according to this is Right > Left > Top > Bottom.
What i would like to know is how to detect this happens, so i can adjust my flyout position, or another viable alternative :)
After searching through properties and Dependency properties on Flyout and FlyoutBase, I haven't found a way to simply get the actual placement of the Flyout (which is unfortunate because I think that can be important, as we see in your case). Perhaps you can try what was proposed here by implementing a method that compares the desired size of the Flyout with the available space.
You can subscribe to FlyOut.Opened event and compare absolute coordinates of the flyout and the element you're showing it at. Here is an example for top/bottom flyout placement (easily extendable to check for left/right as well):
private void FlyOut_Opened(object sender, object e)
{
GeneralTransform flyOutTransform =
flyOut.Content.TransformToVisual(Window.Current.Content);
Point flyOutPosition =
flyOut.TransformPoint(new Point(0, 0));
GeneralTransform showAtElementTransform =
showAtElementTransform.TransformToVisual(Window.Current.Content);
Point showAtElementPosition =
showAtElementPosition.TransformPoint(new Point(0, 0));
if(flyOutPosition.Y < showAtElementPosition.Y)
{
// top
}
else
{
// bottom
}
}

Moving Borderless Forms

I need your help with some code I found on the web a long time ago. Sadly I don't remember from where it is :( To move the borderless forms in my project I use this code snipped:
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
this.Capture = false;
Message msg = Message.Create(this.Handle, 0XA1, new IntPtr(2), IntPtr.Zero);
this.WndProc(ref msg);
}
}
My problem is that I don't completely understand how the code works. As far as I understand the event gets activated when a mouse button is clicked on the forms. Then follows the query, if the mouse click is a left click. And from there I don't know what the following code does :(
The this.Capture=false tells the OS to stop capturing mouse events. The Message.Create creates a new message to be send to the message loop of the current application. 0xA1 is WM_NCLBUTTONDOWN; which is a non-client left-button down message. Meaning it simulated clicking the left mouse button on the missing border.
Windows then picks up the rest of the process.
At a basic level, you are sending a message to your window and having it handle it.
You are giving it a 0xA1 (WM_NCLBUTTONDOWN) and by sending a 0x02 as the parameter (HTCAPTION) you fool the process into thinking you are on the caption bar. Drags on a caption bar move the window around, hence you can drag the window by using your code.
Samples of doing this at:
C#: How to drag a from by the form and it's controls?
http://www.catch22.net/tuts/win32-tips-tricks
You're basically posting a message to the window. A little MSDN research uncovers that the message you're posting is WM_NCLBUTTONDOWN. Basically, you're telling the underlying window that the left mouse button is being held down and it needs to respond to that. That response typically happens to be dragging the window about.

Windows 8.1 application and Top vs. Bottom edge gestures

I'm implementing windows 8.1. application and I'd like to show some menus on edge gestures. On top edge gesture Menu A and on bottom gesture Menu B. I found out that it is probably not possible.
In following code
void EdgeGesture_Completed(object sender, EdgeGestureEventArgs e)
{
if (e.Kind == EdgeGestureKind.Touch)
{
Scenario1OutputText.Text = "Invoked with touch.";
}
else if (e.Kind == EdgeGestureKind.Keyboard)
{
Scenario1OutputText.Text = "Invoked with keyboard.";
}
else if (e.Kind == EdgeGestureKind.Mouse)
{
Scenario1OutputText.Text = "Invoked with right-click.";
}
}
we have possible to recognize if top/bottom menu is invoked by Touch, Keyboard or Right click but EdgeGestureEventArgs doesn't contain any other info.
Do you have any idea how to recognize edge gestures? I mean, if it is Top or Bottom edge gesture.
The standard behaviour is to show both the top and the bottom together. If you use the built-in AppBar control then you'll get this automatically.
If you want to separate the top and bottom app bars then it's trickier and you'll need to implement that yourself. There isn't any direct way to tell if edgie was triggered from the top or the bottom, but you can track PointerEvents and if the EdgeGestureKind isTouch then you can guess based on the pointer location.
There is no difference if edgie was triggered by keyboard or mouse since those gestures aren't location dependant.
Also note that the standard appbar and charms behaviour is different in the Windows 10 Technical Preview than on Windows 8.1, so if you implement it yourself your app's behaviour may end up farther from standard than you intend.

C# - Create a styled winforms like in Windows 7

I would like to create a winform like this:
I already accomplished the visual effect (like as seen in the picture), by following other question. But I can't disallow resizing the form, since to have the border, it must be "Sizeable". Someone suggested putting Minimum Size and Maximum Size values equal to the current Form Size. This solves part of the issue, but when the mouse hovers the border, it still shows the double-ended arrow, suggesting the form is resizeable. Is there any way of disable this cursor change? My goal is to mimic the original systray popups in Windows 7, like the network, sound, etc.
Thank you!
Example code:
private const int WM_NCHITTEST = 0x84;
private const int HTCLIENT = 0x1;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCHITTEST:
m.Result = (IntPtr)HTCLIENT;
return;
}
base.WndProc(ref m);
}
This way, when the cursor hovers the borders, the pointer doesn't change, because it's treated as if it was inside the form, achieving the desired effect.
Add a message handler to your form and handle WM_NCHITTEST. When the original returns HTSIZE (etc.), return HTNONE or HTCAPTION.
Something like this question should get you started.
To explain:
When Windows wants to know which cursor to use for your window, it first sends you a WM_NCHITTEST message (non-client hit test). This message is handled by the WndProc method. Your window is supposed to return one of the HT* codes to tell Windows which part of the window the mouse is over. For example, return HTCAPTION for the caption area, HTCLIENT for the client area, or HTSIZENESW for the bottom left sizing corner. The default message handler (calling base.WndProc) deals with this for standard windows.
We don't have a standard window.
What we're trying to do here is ask the original window what the mouse is over. If it returns any of the HTSIZE* values, we want to replace that return value with HTNONE (for no action) or HTCLIENT (if you want the cursor to be treated as inside the window -- probably not this one) or HTCAPTION (if you want to be able to drag the window by the edges -- might be useful).

Categories