Возможно ли отловить ошибку WinApi на C#?

279
03 октября 2017, 02:56

Добрый вечер, товарищи!

В проекте на C# понадобилось использовать WinApi. В том числе - метод GetWindowText. И все бы было нормально, если бы GetWindowText переодически не выкидывал ошибку Access_Denied при переборе списка хэндлеров и не ломал всего сущего.

Вопрос следующий: можно ли как-то отловить и отработать ошибку (аки try-catch, который тут работать отказывается) или же проверить наличие у меня доступа к элементу, имея только его IntPtr хэндлер?

Пример кода:

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
            private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
            public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
public static IntPtr[] FindWindowsByName(string Name)
            {
                List<IntPtr> windows = new List<IntPtr>();
            EnumWindows(delegate (IntPtr wnd, IntPtr param)
            {
                try
                {
                    StringBuilder str = new StringBuilder();
                    int code = GetWindowText(wnd, str, GetWindowTextLength(wnd) + 1);
                    if (str.ToString().Contains(Name)) windows.Add(wnd);
                } catch { }
                return true;
            }, IntPtr.Zero);
            return windows.ToArray();
            }

Падает все именно при получении текста окна (не любого, элементов 20 проходит нормально), отладчик выдает, что возвращена ошибка Access Denied. Укажите, пожалуйста, на ошибку и объясните, что я не так делаю

Answer 1

Вы выделяете пустой буфер, и сообщаете функции GetWindowText, что его длина равна GetWindowTextLength(wnd) + 1. Неудивительно, что вы затираете какую-то чужую память и падаете.

StringBuilder str = new StringBuilder(); // нулевого размера
int code = GetWindowText(wnd, str, GetWindowTextLength(wnd) + 1);

Вы должны быть очень осторожны с P/Invoke, понимать в деталях значение каждой строчки и заглядывать в документацию к каждой вызываемой функции. Управляемый код прощает ошибки и контролирует вас, а вот нативный код требует отчётливо понимать, что вы делаете и для чего.

По поводу вопроса, вынесенного в заголовок. В общем случае, ошибки в нативном коде ловятся очень сложно, они не заявляют о себе прямо, а приводят к крешам (в лучшем случае), к крешам в совсем другом месте и в другое время (в более плохом случае), и к молчаливому «необъяснимому» неправильному поведению нормального кода (в ужасном случае). Старайтесь избегать нативного кода, если вы не уверены в собственных силах.

READ ALSO
Как отловить Ctrl+C в telnet приложении

Как отловить Ctrl+C в telnet приложении

Написал для одной задачки простенькую консольПодключаюсь по 500 порту из Putty, ввожу команду "tail" и получаю в бесконечном цикле вывод на экран...

207
Парсинг параметров с помощью Regex

Парсинг параметров с помощью Regex

Есть строка - ответ от веб сервера, приблизительно такого содержания

265
Гайд или пример PJSIP

Гайд или пример PJSIP

Уже достаточно долго ищу и не могу найти нормального гайда по библиотеке pjsip, для написания простенького softphoneНа сайте pjsip не информативно...

269
Загрузка сцены из Bundle

Загрузка сцены из Bundle

Подскажите почему мой сцена не добавляется в build list - что не так сделал?

249