декодирование символов в блокноте - PullRequest
2 голосов
/ 09 января 2012

Я читаю текст из блокнота, открытого моей программой. И это мой код

const int WM_GETTEXT = 0x000D;
const int WM_GETTEXTLENGTH = 0x000E;

[DllImport("User32.dll", EntryPoint = "SendMessage")]
extern static int SendMessageGetTextLength(IntPtr hWnd, int msg, IntPtr wParam,     IntPtr lParam);
[DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
extern static IntPtr SendMessageGetText(IntPtr hWnd, int msg, IntPtr wParam, [Out] StringBuilder lParam);

[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

public static string GetText(IntPtr hwnd)
{
    if (hwnd == IntPtr.Zero)
        throw new ArgumentNullException("hwnd");
    IntPtr handler = FindWindowEx(hwnd, new IntPtr(0), "Edit", null);
    int length = SendMessageGetTextLength(handler, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
    if (length > 0 && length < int.MaxValue)
    {
        length++;
        StringBuilder sb = new StringBuilder(length);

        SendMessageGetText(handler, WM_GETTEXT, (IntPtr)sb.Length, sb);
        return sb.ToString();
    }
    return String.Empty;
}

Он получает текст, но в специальной кодировке.Например, если введенный текст «привет», он получает «興 梀 ㇨ ȿ ڳ ㇺ».Какова кодировка этого текста, чтобы я мог декодировать его в ASCII?

Ответы [ 2 ]

4 голосов
/ 09 января 2012

Ваша проблема на самом деле в том, что вы передаете sb.Length в сообщении WM_GETTEXT, когда на самом деле вы должны передавать sb.Capacity или даже просто length.

Я бы сделал это такэто:

if (length > 0 && length < int.MaxValue)
{
    StringBuilder sb = new StringBuilder(length+1);
    SendMessageGetText(handler, WM_GETTEXT, (IntPtr)length+1, sb);
    return sb.ToString();
}

Я бы также отметил, что WM_GETTEXT не вернет больше, чем 64 000 символов, к length < int.MaxValue не то, что вам нужно.


ИзКонечно, в более долгосрочной перспективе может быть лучше использовать Unicode повсеместно, чтобы вы могли поддерживать международный текст.

Я лично всегда выбрал бы использование API Unicode и использовал бы следующие объявления p / invoke:

[DllImport("User32.dll", EntryPoint = "SendMessage", 
    CharSet = CharSet.Unicode, SetLastError = true)]
extern static int SendMessageGetTextLength(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", EntryPoint = "SendMessage",
    CharSet = CharSet.Unicode, SetLastError = true)]
extern static IntPtr SendMessageGetText(IntPtr hWnd, int msg, IntPtr wParam, StringBuilder lParam);
[DllImport("user32.dll", EntryPoint = "FindWindowEx",
    CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
3 голосов
/ 09 января 2012

Поскольку вы пишете в управляемом коде, вы также можете использовать интерфейсы автоматизации управляемого кода, которые делают все взаимодействие за вас. Зачем изобретать велосипед?

using System.Windows.Automation;
public static string GetText(IntPtr hwnd)
{
  IntPtr hwndEdit = FindWindowEx(hwnd, IntPtr.Zero, "Edit", null);
  return (string)AutomationElement.FromHandle(hwndEdit).
     GetCurrentPropertyValue(AutomationElement.NameProperty);
}

Вы даже можете заставить автоматизацию сделать FindWindowEx для вас:

public static string GetText(IntPtr hwnd)
{
  var editElement = AutomationElement.FromHandle(hwnd).
                    FindFirst(TreeScope.Subtree,
                              new PropertyCondition(
                                     AutomationElement.ClassNameProperty, "Edit"));
  return (string)editElement.GetCurrentPropertyValue(AutomationElement.NameProperty);
}
...