Ste
Ste

Reputation: 1520

What causes my borderless C++/CLI app to crash when overriding WndProc?

I use a form with border NONE. I need to override WndProc for resize and move form. However, using this code, my app crashes!

 static const int WM_NCHITTEST = 0x0084;
 static const int HTCLIENT = 1;
 static const int HTCAPTION = 2;

 protected: virtual void Form1::WndProc(System::Windows::Forms::Message %m) override 
 {        
     switch (m.Msg)
     {
         case WM_NCHITTEST:
             if (m.Result == IntPtr(HTCLIENT))
             {
                 m.Result = IntPtr(HTCAPTION);
             }
             break;
     }
     Form1::WndProc(m);
 }       


virtual System::Windows::Forms::CreateParams^ get() override
{

    System::Windows::Forms::CreateParams^ cp = __super::CreateParams;
    cp->Style |= 0x40000; 
    return cp;
}

How can I fix my code not to crash but still allow my form to be moved and resized?

Upvotes: 1

Views: 1333

Answers (2)

Hans Passant
Hans Passant

Reputation: 941675

Check out the warnings you get on this code:

warning C4717: 'cpptemp5::Form1::WndProc' : recursive on all control paths, function will cause runtime stack overflow

Which is why your code crashes with this web site name. That could have been a bit more than a warning. Fix:

 Form::WndProc(m);

Or use the __super keyword. It should be called first, before you change the return value.


warning C4490: 'override' : incorrect use of override specifier; 'cpptemp5::Form1::get' does not match a base ref class method

Which prevents your attempt at overriding from working, the form still has borders. The better mousetrap is to assign the FormBorderStyle property in the constructor:

    Form1(void)
    {
        InitializeComponent();
        this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::None;
    }

Although you'd normally just do this with the designer, using the Properties window. For completeness, the override doesn't work because you made it a function, not a property. The correct syntax is:

protected:
    property System::Windows::Forms::CreateParams^ CreateParams {
        virtual System::Windows::Forms::CreateParams^ get() override {
            System::Windows::Forms::CreateParams^ cp = __super::CreateParams;
            cp->Style |= 0x40000;
            return cp;
        }
    }

But not quite good enough to make the form borderless.

Upvotes: 1

Cody Gray
Cody Gray

Reputation: 244802

You have to call the base class's WndProc method first, in order for m.Result to be set to the correct value. The code you posted doesn't call it until the end.

Additionally, you're trying to call the base class with Form1::WndProc, which actually calls the current class's implementation of the WndProc method. That's why your application is "crashing" every time you try to run it with a StackOverflowException—your code within the WndProc method is calling itself recursively. Directly calling the superclass's implementation (like you did in the CreateParams property) with the __super keyword works just fine.

So, you need to re-write that method like this:

virtual void Form1::WndProc(System::Windows::Forms::Message %m) override 
{
    __super::WndProc(m);

    switch (m.Msg)
    {
    case WM_NCHITTEST:
        if (m.Result == IntPtr(HTCLIENT))
        {
            m.Result = IntPtr(HTCAPTION);
        }
        break;
    }
}

Upvotes: 3

Related Questions