Click here to Skip to main content
15,881,172 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Form imagehttp://img534.ph.126.net/ceLGsnOo4iCmrYrfB-wBwQ==/1322087965611128436.bmp[^]

The project can be downloaded at http://www.badongo.com/file/25080153[^].
From the day before yesterday, I have been implementing a Form that can Auto collapse it client area whem mouse move out and auto expend when mouse move in.

It need a button that used to enable or disable auto collapsing to be painted close to the left of the ControlBox. None client area cannot be custom painted on Win 7. So I make a no-border-form's(that its FormBorderSytle set to None) client area shrink for the custom-paint border and caption by process the WM_NCCALCSIZE message.

C#
private void WmNCCalcSize(ref Message m
{
    if (m.WParam == NativeMethods.FALSE)
    {
        NativeMethods.RECT ncRect = (NativeMethods.RECT)m.GetLParam(typeof(NativeMethods.RECT));
        Rectangle proposed = ncRect.Rect;
        RecalcNonClientArea(ref proposed);
        ncRect = NativeMethods.RECT.FromRectangle(proposed);
        Marshal.StructureToPtr(ncRect, m.LParam, false);
    }
    else if (m.WParam == NativeMethods.TRUE)
    {
        NativeMethods.NCCALCSIZE_PARAMS ncParams =
            (NativeMethods.NCCALCSIZE_PARAMS)m.GetLParam(typeof(NativeMethods.NCCALCSIZE_PARAMS));
        Rectangle proposed = ncParams.rectProposed.Rect;
        RecalcNonClientArea(ref proposed);
        ncParams.rectProposed = NativeMethods.RECT.FromRectangle(proposed);
        Marshal.StructureToPtr(ncParams, m.LParam, false);
    }
    m.Result = IntPtr.Zero;
}

private void RecalcNonClientArea(ref Rectangle proposed)
{
    int captionHeight = 3;

    if (_captionVisible)
        captionHeight = _captionHeight;

    proposed = new Rectangle(proposed.Left + _borderWidth,
                    proposed.Top + captionHeight + 4,
                    proposed.Width - (_borderWidth + _borderWidth),
                    proposed.Height - (_borderWidth + captionHeight + 4));
}

This bring serveral unexpected situation.
1 The Form's size will shrink by the width of double the width of border and by the height of the width of border plus the height of caption every time I use NativeMethods.SendMessage(this.Handle, WM_SYSCOMMAND, SC_RESTORE, 0) to make the form restore form Maxmize.

2 The Form's size will shrink by the width of double the width of border and by the height of width of border and height of caption every second time open it in From design view after the project was opened.

3 If the Form does not have the default caption height after startup its client area will extend to the caption area.http://img74.ph.126.net/k6Vk6axU4cY1UFMLT52kgQ==/1853231246665109116.bmp[^]


Resizing have not been implemented, so what kind of exceptions is still unknown. But these exceptios give us enough clues to identify the problem that it all because of WmNCCalcSize method was invoked when don't needed but was not invoked when needed.

Will any body help me! I very appreciate it.

If somebody can tell me how to send a WM_NCCALCSIZE message?
Sending WM_NCCALCSIZE message is not as easy as sending other messages for me. One must pass each parameter of SendMessage precisely to send a WM_NCCALCSIZE successfully. I have tried many time according to http://msdn.microsoft.com/en-us/library/ms632634(v=vs.85).aspx but failed each time.

The project can be downloaded at http://www.badongo.com/file/25080153[^].
:)
Posted
Updated 13-Feb-11 18:25pm
v3

I don't want to search for a bug in this code and would advice you don't waste time on it, too.
Better do a different thing. There is absolutely no point to do what your want using inter-operation and Marshal. In fact, you do not need any native (unmanaged) code at all.

The pure .NET API can do everything you're trying to do. Also, it will make you code portable (my Form applications run even on Linux under Mono). As soon as you don't want, for example, to paint on non-client area. As I understand, you're using different approach, which is good. For example, you can calculate all non-client metrics using Window.Size and Window.ClientRectangle.

—SA
 
Share this answer
 
Comments
tgis.top 12-Feb-11 3:37am    
Thinks, but i want to how to solve this problem. May someone can tell me how to use SendMessage Api to send a WM_NCCALCSIZE message?
Sergey Alexandrovich Kryukov 12-Feb-11 14:17pm    
Yes, I know, can tell you. I still didn't get why you're not considering doing in in pure .NET.
--SA
tgis.top 13-Feb-11 23:52pm    
Because it have already been done by using inter-operation and Marshal. You may think I should drag in another Control(may be label) to serve as caption and some other controls serve as border. Than track the mousein and mouseleave event of the caption to make the form Collapse and expend. There are some shortcomings. So I try to make the client area shrink for border and Caption. If I make form's client area shrank, message hook is the only method to track the set-aside none client area mouse message.

Pure .NET can not make client area shrink and paint the none client area.
Sergey Alexandrovich Kryukov 16-Feb-11 13:26pm    
Please use my other answer showing use of P/Invoke. It should be enough, from what I know about your issue (but I would do in pure .NET, you still didn't convince me).
--SA
Sergey Alexandrovich Kryukov 12-Feb-11 14:36pm    
All right, I've added another showing how to declare API SendMessage and PostMessage using P/Invoke.
--SA
Answering follow-up message:

Use this declaration (for Win32):

C#
using System;
using System.Runtime.InteropServices;

//...

[StructLayout(LayoutKind.Sequential)]
public struct RECT {
     public int _Left;
     public int _Top;
     public int _Right;
     public int _Bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT {
     public X, Y;
}

[DllImport("user32.dll", EntryPoint = "SendMessageW")]
static extern IntPtr SendMessageW(
    IntPtr hWnd,
    UInt32 Msg,
    IntPtr wParam,
    [MarshalAs(UnmanagedType.LPWStr)] string lParam);

// below I put different variants of SendMessage depending in by ref parameter,
// one can use them all

[DllImport("user32.dll", EntryPoint = "SendMessage")]
static extern void SendMessageRect(
    IntPtr hWnd,
    UInt32 msg,
    IntPtr wParam,
    ref RECT lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
static extern IntPtr SendMessagePoint(
    IntPtr hWnd,
    UInt32 msg,
    IntPtr wParam,
    ref POINT lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
static extern IntPtr SendMessageInt32(
    IntPtr hWnd,
    UInt32 Msg,
    Int32 wParam,
    Int32 lParam);

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(
    HandleRef hWnd,
    uint Msg,
    IntPtr wParam,
    IntPtr lParam);


Do you need explanation on how Interop works? Basically, you just use these declarations.
You can use your variants of ref types, depending on Msg parameters, see Win32 documentation.

—SA
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900