Today I’ve got a requirement from my customer to prevent showing the system menu when WinForm’s icon (top left) is right-clicked. The form is painted by DevExpress skin. Here is how I’ve done it.
1. Intercept proper mouse messages
I had to intercept two mouse messages: WM_NCRBUTTONDOWN (0xa4) and WM_NCRBUTTONUP (0xa5). These two guys shows up when right click is performed on non client (NC) are of the form (where icon is located). That’s also the reason I couldn’t use Mouse* events which fire only for client area.
The interception is done by overriding Form’s WndProc method and it looks something like this:
2. Finding icon bounds
If you are doing DevExpress form skinning it means that your form has to derive from XtraForm which does all of the skinning work for you. XtraForm holds a reference to FormPainter instance (which is responsible for painting the skin) through FormPainter property which in turn holds the icon bounds through its IconBounds property of Rectangle type. Now, the problem is that FormPainter.IconBounds property is protected and reflection has to be used to retrieve the value:
3. Figuring out if right click is within icon bounds and ignore such clicks
To get the click’s location I simply used Cursor.Position which is easier than retrieving the position from Message but less accurate – still enough for me.The position is in screen coordinates and they have to be transformed to form’s coordinates. Form.PointToClient method won’t help because it transforms to form’s client area which border isn’t. The solution to this is rather simple – just Offset the position by Form’s –Left, –Top.
If click is positioned within icon bounds just return without delegating to base.WndProc. That’s it. Here is the complete code:
This method works only for DevExpress skinned forms. If you want to use for normal forms the you should modify the icon bounds retrieval.