Windows Management Instrumentation. Опрос свойств, методов и описателей. Разработка компонента WMIControl, страница 33

¨  Ищется поток, который владеет ресурсом HWND, принадлежащим элементу управления,

¨  Метод Invoke запускает в этом потоке функцию, соответствующую указанному делегатному типу.

Попробуйте на русском выразить эту мысль так же коротко. Если сможете, покажите ваш текст. Как бы там ни было, я не хотел признавать факт наличия еще одного потока, кроме потока, в котором выполняется наше приложение Client, и в адресное пространство которого загружена наша DLL Library. Но ведь меня не спрашивают и COM-объект на самом деле работает в другом потоке. Ситуация с Invoke похожа на посылку сообщения самому себе, как в случае с функцией PostMessage).

PostMessage — традиционный прием Win32-программиста. Он означает: выполни то, что хочешь, но позже, после окончания обработки текущего сообщения и сделай это в функции обратного вызова, то есть реакции на посланное себе же сообщение. Напомню, что рассматриваемая проблема возникла потому, что я забыл установить объект SynchronizingObject.

Синтаксис вызова Invoke мы рассматривали ранее, поэтому не будем к нему возвращаться и отметим лишь, что с помощью Invoke можно решить проблему отладки нашего кода, без установки SynchronizingObject=this. Но при этом код станет значительно менее понятным. Вместо прямого воздействия на узел:

node.Nodes.Add(new TreeNode(GetFolderName(fullPath), id, id + 1));

придется воздействовать на TreeView таким образом:

tree.Invoke(new Action<TreeNode,TreeNode>(DoAdd, node, new TreeNode(GetFolderName(fullPath),id,id+1));

Кроме этого придется добавить метод DoAdd с сигнатурой Action<TreeNode,TreeNode>.

void DoAdd (TreeNode parent, TreeNode node) { parent.Nodes.Add(node); }

Функция, вызываемая с помощью Invoke, должна иметь сигнатуру, соответствующую делегатному типу. В этом месте почти все без исключения говорят—соответствующую делегату, а не делегатному типу. Это упрощение, так как делегат создаеттся с помощью операции new. Головоломно, не правда ли? Но зато все работает всегда. Чтобы избежать путаницы, приведем полный код альтернативной версии реализации события Created.

void AddFolder(string fullPath, bool bHidden)

{

TreeNode node = FindNode(Path.GetDirectoryName(fullPath));

if (node != null)

{

if (node.Tag != null)

{

int id = bHidden ? 16 : 14;

tree.Invoke(new Action<TreeNode,TreeNode>(DoAdd),node,new TreeNode(GetFolderName(fullPath),id,id+1));

}

else

FillFolder(node, 2);

}

}

void OnAddFolder(TreeNode parent, TreeNode node) { parent.Nodes.Add(node); }

Некоторые пояснения особенностей вызова Invoke можно найти в MSDN. Например, массив объектов (new object[]), который создается по ходу дела, позволяет создать делегатный тип с произвольным числом параметров. Мы используем лишь два параметра: родительский узел и дочерний узел, а могли бы передать и два и три и т.д.

Мы познакомились со способом запуска произвольного метода (в нашем случае DoAdd) в рамках другого потока. Запуск метода с помощью Invoke называется синхронным, так как наш (главный) поток, при этом, ждет завершения вспомогательного потока, то есть временно стоит. Особенность синхронного запуска в том, что нам не надо создавать другой поток—он выбирается из специального множества дежурных потоков (thread pool). Метод Invoke автоматически создает другой поток и запускает его в синхронном режиме.  Существует и другой способ запуска любого метода любого класса—асинхронный (при этом работает пара методов BeginInvoke-EndInvoke), но об этом в другой раз.

Некоторые наши студенты: Глухов А.А. и Тихановский А.С. проявили нестандартные и весьма интересные подходы к управлению как деревом, так и списком. Их решения надежно работают, но я не готов обсуждать их сейчас. Отмечу лишь, что Тихановский А.С. почти все манипуляции с объектами файловой системы производит с помощью классов WMI, без помощи классов DirectoryInfo и FileInfo.

Скрытые папки

Вспомните, что у нас имеется кнопка CheckBox checkHidden, которая должна включать и выключать режим видимости системных или скрытых папок. Обработчик события CheckStateChanged для этой кнопки вы должны были создать ранее. Теперь добавим в него код, который будет переключать режим видимости.