如何在Win32窗口上更改文字?

4

寻找更改C# win32窗口上文本的提示,技巧和搜索词。

更具体地说,我试图将打印对话框上的文本从“打印”更改为“确定”,因为我使用此对话框创建打印票据而不是进行任何打印操作。

如何找到对话框的窗口句柄?一旦找到了,如何在窗体的子窗口中查找按钮?找到后,如何更改按钮上的文本?如何在对话框显示之前执行所有这些操作?

这里有一个类似的问题,但它指向的CodeProject文章比需要的要复杂得多,花费时间比我想象中的长。谢谢。


1
你能稍微澄清一下你的问题吗?我有点困惑哪些部分正在改变(我的电脑上打印对话框中的接受按钮已经显示为“确定”)。 - Jon Seigel
对Jon的评论点赞 - 我在Windows Vista Business下也遇到了同样的问题。 - Jon Cage
@jon(还有JonJon)当通过System.Windows.Controls.PrintDialog使用时,它总是“Print”。然而,这并不影响问题的核心。按钮显示X,我想让它显示Y,请问如何实现。 - user1228
1个回答

9
您应该使用Spy++查看对话框。类名和按钮的控件ID很重要。如果是本地Windows对话框,则类名应为“#32770”。在这种情况下,您将需要使用我在此线程中的帖子。这里是另一个使用C#的帖子。您可以通过在按钮句柄上P/Invoke SetWindowText()来更改按钮文本。
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);
}

使用方法:

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

1
@Hans,该死。我成功利用了你的代码来找到对话框,然后我能够枚举子窗口并更改其中所有文本。但是我需要更改的那个按钮没有被更改。参见:http://i43.tinypic.com/6xvr7m.png 有什么想法吗? - user1228
嗯,我逐步执行了我的代码,按钮窗口显示它的文本是“OK”,并且它显示它已经更改了,但是当对话框出现时,它仍然是“Print”... - user1228
再次,我获取第一个对话框项,其上的文本为“OK”。这似乎是在我更改后将“Print”放置在按钮上。 - user1228
我只是复制/粘贴了这段代码,用于完全相同的目的(将“打印”按钮替换为“确定”按钮),它可以直接使用。干得好! - Evren Kuzucuoglu
我使用了这段代码,PrintDialog打印按钮上的图例变成了“确定”——非常棒。但是有没有办法防止计时器重绘使按钮文本闪烁? - Brian THOMAS
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接