Общие сведения о взаимодействии WPF и Win32
Обновлен: Ноябрь 2007
Этот раздел содержит обзор способов взаимодействия WPF и кода Win32. Windows Presentation Foundation (WPF) предоставляет богатую среду для создания приложений. Однако если имеется сложный код Win32, возможно, более эффективным будет повторное использование части этого кода.
В этом разделе содержатся следующие подразделы.
- Основы взаимодействия WPF и Win32
- Проекты взаимодействия WPF
- Как WPF использует Hwnds
- Размещение содержимого WPF в окне Microsoft Win32
- Размещение окна Microsoft Win32 в WPF
- Переходы, назначенные клавиши и сочетания клавиш
- Связанные разделы
Основы взаимодействия WPF и Win32
Существуют два основные метода взаимодействия между WPF и кодом Win32.
Размещение содержимого WPF в окне Win32. С помощью этого способа можно использовать дополнительные графические возможности WPF в структуре стандартных окон и приложений Win32.
Размещение окна Win32 в содержимом WPF. С помощью этого способа можно использовать существующий пользовательский элемент управления Win32 в контексте другого содержимого WPF и передавать данные через границы.
Каждый из этих способов детально представлен в этом разделе. Дополнительные пояснения о коде относительно размещения WPF в Win32, см. в разделе Пошаговое руководство. Размещение простого элемента управления Win32 в приложении Windows Presentation Foundation. Дополнительные пояснения о коде относительно размещения Win32 в WPF, см. в разделе Пошаговое руководство по размещению содержимого Windows Presentation Foundation в приложении Win32.
Проекты взаимодействия WPF
API-интерфейсы приложения WPF являются управляемым кодом, но большинство существующих программ Win32 записываются в неуправляемом приложении C++. Невозможно вызвать API-интерфейсыWPF из подлинной неуправляемой программы. Однако с помощью параметра /clr с компилятором Microsoft Visual C++ можно создать смешанную управляемую-неуправляемую программу, где могут равномерно смешиваться управляемые и неуправляемые вызовы API-интерфейс.
Существует одна сложность на уровне проекта, которая заключается в том, что не нельзя скомпилировать файлы Язык XAML (Extensible Application Markup Language) в проекте C++. Имеется несколько методов разделения проектов для решения данной проблемы.
Создайте библиотеку DLL C#, содержащую все страницы XAML, как скомпилированную сборку, и затем используйте исполняемый файл C++, включая эту DLL, как ссылку.
Создайте исполняемый файл C# для содержимого WPF и используйте его ссылку на DLLC++ с содержимым Win32.
Используйте Load для загрузки любого XAML во время выполнения, вместо компиляции XAML.
Не используйте XAML вообще, и записывайте все приложение WPF в коде, создавая дерево элементов из Application.
Используйте любой, наиболее подходящий способ.
![]() |
---|
Если раньше не использовалось приложение C++/CLI, можно заметить некоторые «новые» ключевые слова, такие как gcnew и nullptr, в примерах кода взаимодействия. Эти ключевые слова заменяют старый синтаксис с двойным подчеркиванием (__gc) и предоставляют более естественный синтаксис для управляемого кода в C++. Чтобы узнать больше о возможностях управляемого кода C++/CLI, см. статью Language Features for Targeting the CLR и Hello, C + +/ CLI. |
Как WPF использует Hwnds
Чтобы расширить «взаимодействие HWND» с WPF, необходимо понимать, как WPF использует HWND. Для любого HWND нельзя смешивать отрисовку WPF с отрисовкой DirectX или отрисовкой Интерфейс GDI / GDI+. Это имеет ряд последствий. Главным образом, для смешивания этих моделей отрисовки необходимо создать решение взаимодействия и использовать разработанные сегменты взаимодействия для каждой модели рендеринга, которая выбрана для использования. Также получаемое при отрисовке изображение создает ограничение «airspace» для решения взаимодействия, которое можно применить. Концепция «airspace» объясняется более подробно в разделе Взаимодействие с WPF. Общие сведения об областях "airspace" и областях окна.
Все элементы WPF на экране поддерживаются HWND. При создании WPF объект Window, WPF создает HWND верхнего уровня и использует HwndSource для размещения Window и его содержимого WPF внутри HWND. Остальная часть содержимого WPF в приложении используется этим единственным HWND. Исключением являются меню, поля с раскрывающимся списком и другие всплывающие окна. Эти элементы создают свое собственное окно верхнего уровня, поэтому меню WPF может потенциально выйти за край HWND окна, которое содержит его. При использовании HwndHost для размещения HWND внутри WPF приложение WPF информирует Win32, как разместить новый дочерний HWND относительно HWND WindowWPF.
Связанный c HWND концепт является прозрачным внутри и между каждым HWND. Это также рассматривается в разделе Взаимодействие с WPF. Общие сведения об областях "airspace" и областях окна.
Размещение содержимого WPF в окне Microsoft Win32
Ключом к размещению WPF в окне Win32 является класс HwndSource. Этот класс переносит WPF содержимое в окно Win32 таким образом, что содержимое WPF может быть включено в пользовательский интерфейс в качестве дочернего окна. Следующий подход объединяет Win32 и WPF в одном приложении.
Реализуйте содержимое WPF (содержимое корневого элемента) в виде управляемого класса. Как правило, класс наследуется из одного из классов, который может содержать несколько дочерних элементов и/или использоваться в качестве корневого элемента, например DockPanel или Page. В последующих шагах этот класс называется классом содержимого WPF, и экземпляры класса называются объектами содержимого WPF.
Реализуйте приложение Win32 с приложением C++/CLI. При запуске существующего неуправляемого приложения C++ обычно включается вызов управляемого кода путем изменения параметров проекта, чтобы включить флаг компилятора /clr (полное описание того, что может потребоваться для поддержки /clr компиляции, не содержится в этом разделе).
Установите для модели потоков режим однопотокового подразделения. WPF использует эту поточную модель.
Обработайте уведомления WM_CREATE в процедуре окна.
В обработчике (или функции, которую вызывает обработчик) выполните следующие действия.
Создайте новый объект HwndSource с родительским HWND окна в качестве его параметра parent.
Создайте экземпляр класса содержимого WPF.
Назначьте ссылку в объекте содержимого WPF на объект HwndSource свойства RootVisual.
Объект HwndSource свойства Handle содержит дескриптор окна (HWND). Для получения HWND, который можно использовать в неуправляемой части приложения, преобразуйте Handle.ToPointer() в HWND.
Реализуйте управляемый класс, содержащий статическое поле, которое хранит ссылку на объект содержимого WPF. Этот класс позволяет получить ссылку на объект содержимого WPF из кода Win32, но что более важно — защищает HwndSource от случайного удаления сборщиком мусора.
Получите уведомления из объекта содержимого WPF путем присоединения обработчика к одному или нескольким событиям объекта содержимого WPF.
Свяжитесь с объектом содержимого WPF с помощью ссылки, которая хранится в статическом поле для установки свойств, вызова методов и т.д.
![]() |
---|
Можно задать некоторые или все определения класса содержимого WPF для первого шага в XAML, используя разделяемый класс содержимого по умолчанию класса, если создается отдельная сборка и затем ссылка на нее. Хотя обычно в сборку включается объект Application как часть компиляции XAML, не завершайте использование Application в качестве части взаимодействия, просто используйте один или несколько корневых классов для файлов XAML, на которые ссылается приложение, и ссылайтесь на их разделяемые классы. Оставшаяся часть процедуры по существу аналогична описанной выше. Каждое из этих действий будет показано в коде в разделе Пошаговое руководство по размещению содержимого Windows Presentation Foundation в приложении Win32. |
Размещение окна Microsoft Win32 в WPF
Ключом к размещению окна Win32 внутри другого содержимого WPF является класс HwndHost. Этот класс переносит окно в элемент WPF, который может быть добавлен к элементу дерева WPF. HwndHost также поддерживает API-интерфейсы, которые позволяют выполнять такие задачи, как обработка сообщений для размещаемого окна. Основная процедура:
Создайте дерево элемента для приложения WPF (можно через код или разметку). Найдите соответствующую и допустимую точку в дереве элемента, где реализация HwndHost может быть добавлена в качестве дочернего элемента. В оставшихся шагах этих действий этот элемент называется элементом резервирования.
Создайте класс производный от HwndHost для создания объекта, который хранит содержимое Win32.
В размещаемом классе переопределите метод BuildWindowCore объекта HwndHost. Возвратите HWND размещенного окна. Может потребоваться перенос элементов управления в качестве дочерних окон возвращаемого окна; перенос элементов управления в окно размещения предоставляет простой способ для содержимого WPF получать уведомления от элементов управления. Этот способ позволяет избежать некоторых проблем Win32, касающихся обработки сообщений на границе размещаемых элементов управления.
Переопределите методы DestroyWindowCore и WndProc объекта HwndHost. Цель этого — обработать очистку и удаление ссылок в размещаемом содержимом, особенно если созданы ссылки на неуправляемые объекты.
В файле с выделенным кодом создайте экземпляр элемента управления, размещающего класс, и сделайте его дочерним элемента резервирования. Обычно используется обработчик событий, такой как Loaded, или конструктор разделяемого класса. Но можно также добавить содержимое взаимодействия с помощью поведения среды выполнения.
Обработка сообщений выбранного окна, таких как уведомления элементов управления. Существуют два подхода. Оба предоставляют идентичный доступ к потоку сообщений, поэтому выбор во многом определяется удобством программирования.
Реализуйте обработку сообщений для всех сообщений (не только сообщений о завершении работы) в переопределении метода WndProc объекта HwndHost.
Разместите обработку сообщения элемента WPF посредством обработки события MessageHook. Это событие вызывается для каждого сообщения, которое отправляется в главную процедуру окна размещенного окна.
Нельзя обрабатывать сообщения из окон, которые не участвуют в процессе, с помощью метода WndProc.
Свяжитесь с размещенным окном с помощью запуска платформы для вызова неуправляемых функций SendMessage.
Следующие действия создают приложение, которое работает с вводом мыши. Можно добавить поддержку перехода с помощью клавиши табуляции для размещенного, реализацией интерфейса IKeyboardInputSink.
Каждое из этих действий будет показано в коде в разделе Пошаговое руководство. Размещение простого элемента управления Win32 в приложении Windows Presentation Foundation.
Hwnds внутри WPF
Можно представить HwndHost как специальный элемент управления. (Технически, HwndHost является производным классом FrameworkElement, а не производным классом Control, но его можно рассматривать как элемент управления для целей взаимодействия.) HwndHost абстрагирует базовую природу Win32 размещенного содержимого таким образом, что оставшаяся часть WPF считает, что размещенное содержимое будет другим объектом, подобным элементу управления, который должен отображать и обрабатывать входные данные. HwndHost обычно действует как любой другой WPFFrameworkElement, хотя существуют важные различия вывода (рисование и графика) и ввода (мышь и клавиатура), в зависимости от ограничений базовых HWND, которые могут поддерживаться.
Важные различия в режиме вывода
Объект FrameworkElement, который является базовым классом HwndHost, имеет несколько свойств, которые подразумевают изменение пользовательского интерфейса. Они включают свойства, такие как FrameworkElement.FlowDirection, которые меняют расположение элементов внутри этого элемента как родительского. Однако большая часть этих свойств не сопоставляются с возможными эквивалентами Win32, даже если такие эквиваленты могут существовать. Слишком многие из этих свойств и их значений слишком специфичны для технологии отрисовки, чтобы быть практически применимыми. Поэтому свойства параметров, такие как FlowDirection для объекта HwndHost, не оказывают влияния.
Объект HwndHost не могут быть повернут, масштабированы, наклонен или, в противном случае, он будет подвергнут преобразованию.
HwndHost не поддерживает свойство Opacity (альфа-смешение). Если содержимое внутри HwndHost выполняет операции System.Drawing, включающие сведения об альфа-составляющей, это не является нарушением, но HwndHost, так как единое целое, поддерживает только Opacity = 1.0 (100 %).
HwndHost будет отображаться в верхней части других элементов WPF в окне верхнего уровня. Однако созданное меню ToolTip или ContextMenu является отдельным окном верхнего уровня и поэтому будет работать правильно с объектом HwndHost.
HwndHost не поддерживает кадрирование области его родительского объекта UIElement. Эта является потенциальной проблемой при попытке поместить класс HwndHost внутри области прокрутки или Canvas.
Важные различия в режиме ввода
В общем случае, когда устройства ввода находятся внутри размещенной области Win32 объекта HwndHost, события ввода поступают непосредственно в приложение Win32.
В то время как указатель мыши находится над объектом HwndHost, приложение не получает событий мыши WPF, и значением свойства IsMouseOver приложения WPF будет false.
В то время как HwndHost имеет фокус клавиатуры, приложение не получает событий клавиатуры WPF, и значением свойства IsKeyboardFocusWithin приложения WPF будет false.
Когда фокус находится внутри HwndHost и переходит в другой элемент управления внутри HwndHost, приложение не получает события GotFocus или LostFocus приложения WPF.
Связанные свойства пера и события являются аналогами и не предоставляют отчет, когда перо находится над объектом HwndHost.
Переходы, назначенные клавиши и сочетания клавиш
Интерфейсы IKeyboardInputSink и IKeyboardInputSite позволяют создавать непрерывное взаимодействие с клавиатурой для смешанных приложений WPF и Win32:
Переход между компонентами Win32 и WPF.
Назначенные клавиши и сочетания клавиш, которые работают, когда фокус находится внутри компонента Win32 или WPF.
Классы HwndHost и HwndSource обеспечивают реализацию IKeyboardInputSink, но они могут не обрабатывать все входные сообщения, необходимые для дополнительных сценариев. Переопределите соответствующие методы, чтобы получить нужное поведение клавиатуры.
Интерфейсы только обеспечивают поддержку событий переходов между областями WPF и Win32. Внутри области Win32 поведение переключения полностью контролируется реализованной логикой Win32 для переходов, если таковые имеются.
См. также
Основные понятия
Пошаговое руководство по размещению содержимого Windows Presentation Foundation в приложении Win32