Search code examples
c#.netwinapidialogprintdialog

How can I change text on a win32 window?


Looking for hints, tips and search terms for changing the text on a win32 window from C#.

More specifically, I'm trying to change the text on the print dialog from "Print" to "OK", as I am using the dialog to create a print ticket and not do any printing.

How can I find the dialog's window handle? Once I've got it, how would I go about finding the button in the child windows of the form? Once I've found that, how would I change the text on the button? And how can I do all this before the dialog is shown?

There's a similar question here, but it points to a CodeProject article that is waaay more complex than needed and is taking me a bit longer to parse through than I'd like to spend on this. TIA.


Solution

  • You should use Spy++ to take a look at the dialog. The class name is important and the control ID of the button. If it is a native Windows dialog then the class name should be "#32770". In which case you'll have a lot of use for my post in this thread. Here is another in C#. You change the button text by P/Invoking SetWindowText() on the button handle.


    using System;
    using System.Text;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    class SetDialogButton : IDisposable {
        private Timer mTimer = new Timer();
        private int mCtlId;
        private string mText;
    
        public SetDialogButton(int ctlId, string txt) {
            mCtlId = ctlId;
            mText = txt;
            mTimer.Interval = 50;
            mTimer.Enabled = true;
            mTimer.Tick += (o, e) => findDialog();
        }
    
        private void findDialog() {
            // Enumerate windows to find the message box
            EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
            if (!EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero)) mTimer.Enabled = false;
        }
        private bool checkWindow(IntPtr hWnd, IntPtr lp) {
            // Checks if <hWnd> is a dialog
            StringBuilder sb = new StringBuilder(260);
            GetClassName(hWnd, sb, sb.Capacity);
            if (sb.ToString() != "#32770") return true;
            // Got it, get the STATIC control that displays the text
            IntPtr hCtl = GetDlgItem(hWnd, mCtlId);
            SetWindowText(hCtl, mText);
            // Done
            return true;
        }
        public void Dispose() {
            mTimer.Enabled = false;
        }
    
        // P/Invoke declarations
        private const int WM_SETFONT = 0x30;
        private const int WM_GETFONT = 0x31;
        private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
        [DllImport("user32.dll")]
        private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
        [DllImport("kernel32.dll")]
        private static extern int GetCurrentThreadId();
        [DllImport("user32.dll")]
        private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
        [DllImport("user32.dll")]
        private static extern IntPtr GetDlgItem(IntPtr hWnd, int item);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool SetWindowText(IntPtr hWnd, string txt);
    }
    

    Usage:

            using (new SetDialogButton(1, "Okay")) {
                printDialog1.ShowDialog();
            }