Custom WndProc doesn't stop resizing - c#

I made a form that handles WM_CREATE, WM_ACTIVATE, WM_NCCALCSIZE and WM_NCHITTEST. It also overrides the paint method.
The problem is when I resize the form it doesn't stop resizing. I tried to compare the messages with a working window but spy++ keeps crashing.
Here is my WndProc code:
protected override void WndProc(ref Message m)
{
IntPtr result = IntPtr.Zero;
bool callDWP = !Win32Interop.DwmDefWindowProc(m.HWnd, m.Msg, m.WParam, m.LParam, out result);
switch (m.Msg)
{
case Win32Messages.WM_CREATE:
{
int style = Win32Interop.GetWindowLong(m.HWnd, Win32Constants.GWL_STYLE);
int styleEx = Win32Interop.GetWindowLong(m.HWnd, Win32Constants.GWL_EXSTYLE);
Win32Interop.AdjustWindowRectEx(out RECT rc, style, false, styleEx);
}
break;
case Win32Messages.WM_ACTIVATE:
{
MARGINS margins = new MARGINS
{
cxLeftWidth = Math.Abs(BorderLeft),
cxRightWidth = Math.Abs(BorderRight),
cyBottomHeight = Math.Abs(BorderBottom),
cyTopHeight = Math.Abs(BorderTop)
};
int hr = Win32Interop.DwmExtendFrameIntoClientArea(m.HWnd, ref margins);
result = IntPtr.Zero;
}
break;
case Win32Messages.WM_NCCALCSIZE:
{
if (m.WParam != IntPtr.Zero)
{
result = IntPtr.Zero;
callDWP = false;
}
}
break;
case Win32Messages.WM_NCHITTEST:
{
{
int ht = DoHitTest(m);
Console.WriteLine(ht);
if (callDWP)
{
callDWP = (ht == Win32Constants.HTNOWHERE);
result = new IntPtr(ht);
}
}
break;
}
default:
{
base.WndProc(ref m);
break;
}
}
m.Result = result;
if (callDWP)
{
base.WndProc(ref m);
}
}

Don't call base.WndProc(ref m); in default

Related

Support Windows 11 Snap Layout in WPF app

I want to enable SnapLayout for WPF, because I use Customized Window, according to the documentation, I have to do it myself.
For Win32 apps, make sure you are responding appropriately to
WM_NCHITTEST (with a return value of HTMAXBUTTON for
the maximize/restore button).
I used the following code
private const int HTMAXBUTTON = 9;
private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wparam,
IntPtr lparam, ref bool handled)
{
switch (msg)
{
case InteropValues.WM_NCHITTEST:
try
{
int x = lparam.ToInt32() & 0xffff;
int y = lparam.ToInt32() >> 16;
var rect = new Rect(_ButtonMax.PointToScreen(
new Point()),
new Size(_ButtonMax.Width, _ButtonMax.Height));
if (rect.Contains(new Point(x, y)))
{
handled = true;
}
return new IntPtr(HTMAXBUTTON);
}
catch (OverflowException)
{
handled = true;
}
break;
}
return IntPtr.Zero;
}
SnapLayout is displayed well But the maximize button does not work and if I click on it, a button will be created next to it. How can I solve this problem?
Update:
This is complete code and works fine (without any issues (mouse hover, click,...))
private const double DPI_SCALE = 1.5;
private const int HTMAXBUTTON = 9;
private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
switch (msg)
{
case 0x0084:
try
{
int x = lparam.ToInt32() & 0xffff;
int y = lparam.ToInt32() >> 16;
Button _button;
if (WindowState == WindowState.Maximized)
{
_button = _ButtonRestore;
}
else
{
_button = _ButtonMax;
}
var rect = new Rect(_button.PointToScreen(
new Point()),
new Size(_button.Width * DPI_SCALE, _button.Height * DPI_SCALE));
if (rect.Contains(new Point(x, y)))
{
handled = true;
_button.Background = OtherButtonHoverBackground;
}
else
{
_button.Background = OtherButtonBackground;
}
return new IntPtr(HTMAXBUTTON);
}
catch (OverflowException)
{
handled = true;
}
break;
case 0x00A1:
int x = lparam.ToInt32() & 0xffff;
int y = lparam.ToInt32() >> 16;
Button _button;
if (WindowState == WindowState.Maximized)
{
_button = _ButtonRestore;
}
else
{
_button = _ButtonMax;
}
var rect = new Rect(_button.PointToScreen(
new Point()),
new Size(_button.Width * DPI_SCALE, _button.Height * DPI_SCALE));
if (rect.Contains(new Point(x, y)))
{
handled = true;
IInvokeProvider invokeProv = new ButtonAutomationPeer(_button).GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProv?.Invoke();
}
break;
default:
handled = false;
break;
}
return IntPtr.Zero;
}
you need to define OtherButtonHoverBackground and OtherButtonBackground or replace with SolidColorBrush.

C# WPF WndProc Message capture not working

I am working with a Finger Print Sensor by ZkTeco. The below code in WFA works fine and the input from Finger Print Sensor is captured successfully.
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case MESSAGE_CAPTURED_OK:
{
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(FPBuffer, mfpWidth, mfpHeight, ref ms);
Bitmap bmp = new Bitmap(ms);
this.picFPImg.Image = bmp;
if (IsRegister)
{
// Logic here
}
}
}
default:
base.DefWndProc(ref m);
break;
}
But the alternative in WPF below code doesn't work.
HwndSource source;
protected override void OnSourceInitialized(EventArgs e)
{
var window = Application.Current.MainWindow;
base.OnSourceInitialized(e);
if (window != null)
{
HwndSource source = PresentationSource.FromVisual(window) as HwndSource;
source?.AddHook(WndProc);
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case MESSAGE_CAPTURED_OK:
{
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(FPBuffer, mfpWidth, mfpHeight, ref ms);
}
}
}
While Debugging the function is being called but the Switch statement MESSAGE_CAPTURED_OK never becomes true. What could be the reason ?

How to detect a USB HDD programatically using c#

Hi I have to develop an app that detects a USB HDD using C#. Is it possible?. I have a code for detecting a USB Mass storage device.
I added reference to System.Runtime.InteropServices
I tried to override WndProc() method. I will include the snippet
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
if ((message.Msg != WM_DEVICECHANGE) || (message.LParam == IntPtr.Zero))
return;
DEV_BROADCAST_VOLUME volume = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(message.LParam, typeof(DEV_BROADCAST_VOLUME));
if (volume.dbcv_devicetype == DBT_DEVTYP_VOLUME)
{
switch (message.WParam.ToInt32())
{
// New device inserted...
case DBT_DEVICEARRIVAL:
MessageBox.Show(
string.Format("A storage device has been inserted; Drive :{0}", ToDriveName(volume.dbcv_unitmask)), "Detect USB");
break;
// Device Removed.
case DBT_DEVICEREMOVECOMPLETE:
MessageBox.Show("Storage has been removed.", "Detect USB");
break;
}
}
}
}
I developed an application for the USB Pen drives below is my declarations:
const int WM_DEVICECHANGE = 0x0219;
const int DBT_DEVICEARRIVAL = 0x8000;
const int DBT_DEVICEREMOVALCOMPLETE = 0x8004;
const int DBT_DEVTYPVOLUME = 0x00000002;
Below is my override of WinProc :
protected override void WndProc(ref Message m)
{
try
{
if (m.Msg == WM_DEVICECHANGE)
{
DEV_BROADCAST_VOLUME vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
if ((m.WParam.ToInt32() == DBT_DEVICEARRIVAL) && (vol.dbcv_devicetype == DBT_DEVTYPVOLUME))
{
usb_drive = DriveMaskToLetter(vol.dbcv_unitmask).ToString();
if (usb_drive.Replace(" ", "").Length > 0)
{
// USB Inserted
}
}
if ((m.WParam.ToInt32() == DBT_DEVICEREMOVALCOMPLETE) && (vol.dbcv_devicetype == DBT_DEVTYPVOLUME))
{
//USB Removed
}
}
base.WndProc(ref m);
}
catch
{
}
}

Get Window Object in WPF ResourceDictionary based window

In VS2008, I add a Resource Dictionary template in my solution, I named this template as "MyWinStyle.xaml".
Below is the style used in my window:
......
<!--Window Template-->
<ControlTemplate x:Key="MyWindowTemplate" TargetType="{x:Type Window}">
.....
</ControlTemplate>
<!--Window Style-->
<Style x:Key="MacWindowStyle" TargetType="Window">
....
<Setter Property="Template" Value="{StaticResource MyWindowTemplate}" />
</Style>
</ResourceDictionary>
this is my XMAL code, when I want to add the function to make the ownerdraw window resizable, I encounter a problem, that is, I can't get the Window Object in its constructor.(based on this article, I want to make my window resizable: http://blog.kirupa.com/?p=256)
below is my code:
public partial class MyStyledWindow : ResourceDictionary
{
private const int WM_SYSCOMMAND = 0x112;
private HwndSource hwndSource;
IntPtr retInt = IntPtr.Zero;
public MacStyledWindow()
{
InitializeComponent();
/**
**Would anyone suggest on this? I can't get window object
**/
Window.SourceInitialized += new EventHandler(MainWindow_SourceInitialized);
}
private void MainWindow_SourceInitialized(object sender, EventArgs e)
{
hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
Debug.WriteLine("WndProc messages: " + msg.ToString());
//
// Check incoming window system messages
//
if (msg == WM_SYSCOMMAND)
{
Debug.WriteLine("WndProc messages: " + msg.ToString());
}
return IntPtr.Zero;
}
public enum ResizeDirection
{
Left = 1,
Right = 2,
Top = 3,
TopLeft = 4,
TopRight = 5,
Bottom = 6,
BottomLeft = 7,
BottomRight = 8,
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private void ResizeWindow(ResizeDirection direction)
{
SendMessage(hwndSource.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero);
}
private void ResetCursor(object sender, MouseEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
if (Mouse.LeftButton != MouseButtonState.Pressed)
{
window.Cursor = Cursors.Arrow;
}
}
private void Resize(object sender, MouseButtonEventArgs e)
{
Rectangle clickedRectangle = sender as Rectangle;
var window = (Window)((FrameworkElement)sender).TemplatedParent;
switch (clickedRectangle.Name)
{
case "top":
window.Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Top);
break;
case "bottom":
window.Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Bottom);
break;
case "left":
window.Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Left);
break;
case "right":
window.Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Right);
break;
case "topLeft":
window.Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.TopLeft);
break;
case "topRight":
window.Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.TopRight);
break;
case "bottomLeft":
window.Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.BottomLeft);
break;
case "bottomRight":
window.Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.BottomRight);
break;
default:
break;
}
}
private void DisplayResizeCursor(object sender, MouseEventArgs e)
{
Rectangle clickedRectangle = sender as Rectangle;
var window = (Window)((FrameworkElement)sender).TemplatedParent;
switch (clickedRectangle.Name)
{
case "top":
window.Cursor = Cursors.SizeNS;
break;
case "bottom":
window.Cursor = Cursors.SizeNS;
break;
case "left":
window.Cursor = Cursors.SizeWE;
break;
case "right":
window.Cursor = Cursors.SizeWE;
break;
case "topLeft":
window.Cursor = Cursors.SizeNWSE;
break;
case "topRight":
window.Cursor = Cursors.SizeNESW;
break;
case "bottomLeft":
window.Cursor = Cursors.SizeNESW;
break;
case "bottomRight":
window.Cursor = Cursors.SizeNWSE;
break;
default:
break;
}
}
private void Drag(object sender, MouseButtonEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
window.DragMove();
}
}
}
Why are you using ResourceDictionary as a base class for your window? Change your base class to Window and you'll be able to subscribe to SourceInitialized event. That is:
public partial class MyStyledWindow : Window
{
//other code

How to use Matrix and scrollbar translate offsets for drawing

I'm using a Matrix to set a transformation on my Graphics object during OnPaint. I would like the scrollbars to translate the matrix when scrolled; something like this in OnScroll:
float offset = se.NewValue - se.OldValue;
if (offset == 0)
{
return;
}
if (se.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
this.TransformMatrix.Translate(-offset, 0);
}
else
{
this.TransformMatrix.Translate(0, -offset);
}
I'm pretty sure that both WM_VSCROLL and WM_HSCROLL send a WM_PAINT because the control is redrawn without me actually calling Refresh(). I find that this painting isn't very fluid and is jittery and doesn't draw with the right transformation it seems. Should I intercept the WM_V/HSCROLL messages and manually set the scrollbar's properties (like position etc) with SetScrollInfo? If not, what should I do?
I ended up catching WM_V/HSROLL and doing the painting on my own. It works great!
Here's what I'm using if anyone wants it:
protected override CreateParams CreateParams
{
get
{
var p = base.CreateParams;
p.Style |= NativeMethods.WindowStyles.WS_BORDER;
p.Style |= NativeMethods.WindowStyles.WS_HSCROLL;
p.Style |= NativeMethods.WindowStyles.WS_VSCROLL;
return p;
}
}
private Point ScrollPosition
{
get
{
var info = new NativeMethods.ScrollInfo();
info.cbSize = (uint)Marshal.SizeOf(info);
info.fMask = NativeMethods.ScrollInfoMask.SIF_POS;
NativeMethods.GetScrollInfo(this.Handle, NativeMethods.SBFlags.SB_HORZ, out info);
int x = info.nPos;
NativeMethods.GetScrollInfo(this.Handle, NativeMethods.SBFlags.SB_VERT, out info);
int y = info.nPos;
return new Point(x, y);
}
set
{
var info = new NativeMethods.ScrollInfo();
info.cbSize = (uint)Marshal.SizeOf(info);
info.fMask = NativeMethods.ScrollInfoMask.SIF_POS;
info.nPos = value.X;
NativeMethods.SetScrollInfo(this.Handle, NativeMethods.SBFlags.SB_HORZ, ref info, true);
info.nPos = value.Y;
NativeMethods.SetScrollInfo(this.Handle, NativeMethods.SBFlags.SB_VERT, ref info, true);
}
}
protected override void OnPaint(PaintEventArgs e)
{
// Clear the background color.
e.Graphics.Clear(Color.White);
e.Graphics.Transform = this.TransformMatrix.Clone();
// Do drawing here.
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do nothing.
}
private void OnScroll(ScrollEventArgs se)
{
float offset = se.NewValue - se.OldValue;
if (se.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
this.TransformMatrix.Translate(-offset, 0);
}
else
{
this.TransformMatrix.Translate(0, -offset);
}
this.Refresh();
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case NativeMethods.WindowMessages.WM_HSCROLL:
case NativeMethods.WindowMessages.WM_VSCROLL:
this.WmScroll(ref m);
m.Result = IntPtr.Zero;
break;
default:
base.WndProc(ref m);
break;
}
}
private void WmScroll(ref Message m)
{
int smallChange = 20;
uint sb = NativeMethods.SBFlags.SB_HORZ;
var orientation = ScrollOrientation.HorizontalScroll;
if(m.Msg == NativeMethods.WindowMessages.WM_VSCROLL)
{
sb = NativeMethods.SBFlags.SB_VERT;
orientation = ScrollOrientation.VerticalScroll;
}
// Get current scroll Page and Range.
var info = new NativeMethods.ScrollInfo();
info.cbSize = (uint)Marshal.SizeOf(info);
info.fMask = NativeMethods.ScrollInfoMask.SIF_PAGE | NativeMethods.ScrollInfoMask.SIF_POS;
NativeMethods.GetScrollInfo(this.Handle, sb, out info);
int newValue = info.nPos;
var type = ScrollEventType.SmallDecrement;
switch (Unmanaged.LoWord(m.WParam))
{
case NativeMethods.SBCommands.SB_BOTTOM:
type = ScrollEventType.Last;
break;
case NativeMethods.SBCommands.SB_ENDSCROLL:
type = ScrollEventType.EndScroll;
break;
case NativeMethods.SBCommands.SB_LINEDOWN:
newValue += smallChange;
type = ScrollEventType.SmallIncrement;
break;
case NativeMethods.SBCommands.SB_LINEUP:
newValue -= smallChange;
type = ScrollEventType.SmallDecrement;
break;
case NativeMethods.SBCommands.SB_PAGEDOWN:
newValue += (int)info.nPage;
type = ScrollEventType.LargeIncrement;
break;
case NativeMethods.SBCommands.SB_PAGEUP:
newValue -= (int)info.nPage;
type = ScrollEventType.LargeDecrement;
break;
case NativeMethods.SBCommands.SB_THUMBPOSITION:
type = ScrollEventType.ThumbPosition;
break;
case NativeMethods.SBCommands.SB_THUMBTRACK:
newValue = Unmanaged.HiWord(m.WParam);
type = ScrollEventType.ThumbTrack;
break;
case NativeMethods.SBCommands.SB_TOP:
type = ScrollEventType.First;
break;
}
var newInfo = new NativeMethods.ScrollInfo();
newInfo.cbSize = (uint)Marshal.SizeOf(newInfo);
newInfo.fMask = NativeMethods.ScrollInfoMask.SIF_POS;
newInfo.nPos = newValue;
NativeMethods.SetScrollInfo(this.Handle, sb, ref newInfo, false);
int realNewValue = (orientation == ScrollOrientation.HorizontalScroll) ? this.ScrollPosition.X : this.ScrollPosition.Y;
// Fire the scroll event.
// TODO - Create a Scroll event.
this.OnScroll(new ScrollEventArgs(type, info.nPos, realNewValue, orientation));
}

Categories