Share via

what is button in winform is that in win32?

mc 7,001 Reputation points
2026-03-20T07:23:35.7966667+00:00

is that button in winform is equal to button in win32?

maybe not

I use SendMessage in winform to send SETTEXT message to the handle of the button but the text is not changed.

Developer technologies | Windows Forms
0 comments No comments

Answer accepted by question author

  1. KOZ6.0 6,810 Reputation points
    2026-03-21T03:47:31.0666667+00:00

    Setting the FlatStyle property of a Button control to FlatStyle.System allows the OS to handle its rendering, which makes WM_SETTEXT effective.

        using System.Runtime.InteropServices;
    
        public partial class Form1 : Form
        {
            private const int WM_SETTEXT = 0x000C;
    
            [DllImport("user32.dll", CharSet = CharSet.Unicode)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, string lParam);
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                button2.FlatStyle = FlatStyle.System;
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                SendMessage(button1.Handle, WM_SETTEXT, IntPtr.Zero, "Hello, World!");
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                SendMessage(button2.Handle, WM_SETTEXT, IntPtr.Zero, "Hello, World!");
            }
    
        }
    

    Was this answer helpful?


Answer accepted by question author

  1. Taki Ly (WICLOUD CORPORATION) 1,340 Reputation points Microsoft External Staff Moderator
    2026-03-20T10:10:01.24+00:00

    Hello @mc ,

    In Windows Forms, the displayed text is typically managed through the control’s Text property. The Button control overview also describes the button as a Windows Forms control with its own managed behavior. By contrast, WM_SETTEXT is a Win32 message used to set the text of a native window/control. Because of this, in a WinForms app there can be a difference between the native window text and the managed WinForms state.

    I tested a small WinForms reproduce like this:

    using System;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows.Forms;
    
    namespace WinFormsButtonLab
    {
        public partial class Form1 : Form
        {
            private Button targetButton;
            private Button btnChangeByProperty;
            private Button btnChangeBySendMessage;
            private Button btnShowCurrentText;
            private TextBox logBox;
    
            private const int WM_SETTEXT = 0x000C;
            private const int WM_GETTEXT = 0x000D;
            private const int WM_GETTEXTLENGTH = 0x000E;
    
            [DllImport("user32.dll", CharSet = CharSet.Unicode)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, string lParam);
    
            [DllImport("user32.dll", CharSet = CharSet.Unicode)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, StringBuilder lParam);
    
            [DllImport("user32.dll", CharSet = CharSet.Unicode)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
    
            public Form1()
            {
                InitializeComponent();
                BuildLabUi();
            }
    
            private void BuildLabUi()
            {
                this.Text = "WinForms Button Lab";
                this.Width = 700;
                this.Height = 400;
    
                targetButton = new Button
                {
                    Left = 30,
                    Top = 30,
                    Width = 200,
                    Height = 50,
                    Text = "Original Text"
                };
    
                btnChangeByProperty = new Button
                {
                    Left = 30,
                    Top = 100,
                    Width = 200,
                    Height = 40,
                    Text = "Change by Property"
                };
                btnChangeByProperty.Click += (s, e) =>
                {
                    targetButton.Text = "Changed by Property";
                    targetButton.Refresh();
                    Log("Changed targetButton.Text directly.");
                    DumpState("After property change");
                };
    
                btnChangeBySendMessage = new Button
                {
                    Left = 250,
                    Top = 100,
                    Width = 220,
                    Height = 40,
                    Text = "Change by SendMessage"
                };
                btnChangeBySendMessage.Click += (s, e) =>
                {
                    SendMessage(targetButton.Handle, WM_SETTEXT, IntPtr.Zero, "Changed by WM_SETTEXT");
                    targetButton.Refresh();
                    Log("Sent WM_SETTEXT to targetButton.Handle.");
                    DumpState("After SendMessage");
                };
    
                btnShowCurrentText = new Button
                {
                    Left = 490,
                    Top = 100,
                    Width = 150,
                    Height = 40,
                    Text = "Show Current Text"
                };
                btnShowCurrentText.Click += (s, e) =>
                {
                    DumpState("Manual state check");
                };
    
                logBox = new TextBox
                {
                    Left = 30,
                    Top = 170,
                    Width = 610,
                    Height = 150,
                    Multiline = true,
                    ScrollBars = ScrollBars.Vertical
                };
    
                targetButton.HandleCreated += (s, e) =>
                {
                    Log("HandleCreated: " + targetButton.Handle);
                    DumpState("After handle created");
                };
    
                this.Controls.Add(targetButton);
                this.Controls.Add(btnChangeByProperty);
                this.Controls.Add(btnChangeBySendMessage);
                this.Controls.Add(btnShowCurrentText);
                this.Controls.Add(logBox);
            }
    
            private void DumpState(string title)
            {
                Log("---- " + title + " ----");
                Log("Managed Text: [" + targetButton.Text + "]");
                Log("Native Text : [" + GetNativeText(targetButton.Handle) + "]");
                Log("Handle      : " + targetButton.Handle);
                Log("Visible UI  : check button caption manually");
            }
    
            private string GetNativeText(IntPtr hwnd)
            {
                int length = (int)SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
                StringBuilder sb = new StringBuilder(length + 1);
                SendMessage(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
                return sb.ToString();
            }
    
            private void Log(string message)
            {
                logBox.AppendText(message + Environment.NewLine);
            }
        }
    }
    

    In my test, setting targetButton.Text changed the visible caption as expected. However, sending WM_SETTEXT directly to the WinForms button handle did not update the visible button text. The native text changed, but the WinForms button caption did not.

    User's image

    I also tried the following workaround:

    btnChangeBySendMessage.Click += (s, e) =>
    {
        string requestedText = "Changed by WM_SETTEXT";
    
        IntPtr result = SendMessage(targetButton.Handle, WM_SETTEXT, IntPtr.Zero, requestedText);
        Log("Sent WM_SETTEXT to targetButton.Handle. Result = " + result);
    
        string nativeText = GetNativeText(targetButton.Handle);
        Log("Native text after WM_SETTEXT = [" + nativeText + "]");
    
        // Workaround: sync managed WinForms layer from native text
        targetButton.Text = nativeText;
        targetButton.Refresh();
    
        Log("Applied workaround: targetButton.Text synchronized from native text.");
        DumpState("After SendMessage workaround");
    };
    

    With this workaround, the button text was updated in my test.

    User's image

    Hope this clarifies your question. If you have any further questions, please let me know in the comments. If you find the answer helpful, I would appreciate it if you could leave feedback by following this guide.

    Thank you.

    Was this answer helpful?


1 additional answer

Sort by: Most helpful
  1. Q&A Assist
    2026-03-20T07:23:45.7566667+00:00
    AI generated content. This question contains an answer created with AI from Q&A Assist. Learn more

    A Windows Forms Button is not a raw Win32 BUTTON control, but a managed wrapper that ultimately uses the underlying Win32 button class. Because of this abstraction, sending Win32 messages directly with SendMessage to a WinForms control handle is not the supported way to change its properties.

    To change the text of a WinForms Button, set its Text property in managed code:

    myButton.Text = "New caption";
    

    Using SendMessage with WM_SETTEXT (or BM_SETSTYLE, BM_SETSTATE, etc.) is intended for native Win32 BUTTON controls as described in the button messages documentation. In a WinForms application, the framework manages the control’s state and painting; bypassing it with direct SendMessage calls can fail silently or cause inconsistent behavior, such as the text not updating.

    If native-style behavior is required (for example, custom drawing or state changes), use the WinForms APIs and events (Paint, FlatStyle, OwnerDraw, etc.) rather than sending Win32 button messages directly to the handle.


    References:

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.