Содержание
- System. Windows. Interop Namespace
- Classes
- Structs
- Interfaces
- Enums
- Delegates
- MSG Структура
- Определение
- Комментарии
- Свойства
- System. Windows. Interop Пространство имен
- Классы
- Структуры
- Интерфейсы
- Перечисления
- Делегаты
- Component Dispatcher Класс
- Определение
- Комментарии
- Свойства
- Методы
- События
- Hwnd Source Class
- Definition
- Remarks
- Constructors
- Properties
- Methods
- Events
- Explicit Interface Implementations
System. Windows. Interop Namespace
Provides supporting types for interoperation between Windows Presentation Foundation (WPF) and other technologies such as Windows APIs and provides base classes for other specific interoperation scenarios involving WPF.
Classes
Hosts an ActiveX control as an element within Windows Presentation Foundation (WPF) content.
A helper class that provides information about the browser environment in which a XAML browser application (XBAP) application is hosted.
Enables shared control of the message pump between Win32 and WPF in interoperation scenarios.
Provides a static helper class for WPF/Win32 interoperation with one method, which is used to obtain a Windows Presentation Foundation (WPF) Cursor object based on a provided Win32 cursor handle.
An ImageSource that displays a user-created Direct3D surface.
This type or member supports the Windows Presentation Foundation (WPF) infrastructure and is not intended to be used directly from your code.
Enables calls from a XAML browser application (XBAP) to the HTML window that hosts the application.
Hosts a Win32 window as an element within Windows Presentation Foundation (WPF) content.
Presents Windows Presentation Foundation (WPF) content in a Win32 window.
Represents a binding to a window handle that supports visual composition.
Provides managed to unmanaged interoperation support for creating image objects.
InteropBitmap enables developers to improve rendering performance of non-WPF UIs that are hosted by WPF in interoperability scenarios.
Assists interoperation between Windows Presentation Foundation (WPF) and Win32 code.
Structs
Contains the parameters that are used to create an HwndSource object using the HwndSource(HwndSourceParameters) constructor.
Contains message information from a thread’s message queue.
Interfaces
Defines the interaction between Windows Presentation Foundation (WPF) applications that are hosting interoperation content and interpreted by the Windows Presentation Foundation (WPF) executable, and a host supplied error page.
Provides a keyboard sink for components that manages tabbing, accelerators, and mnemonics across interop boundaries and between HWNDs. This interface implements keyboard message management in WPF-Win32 interoperation scenarios.
Manages keyboard focus within the container. This interface implements keyboard message management in WPF-Win32 interoperation scenarios.
Defines the interaction between Windows Presentation Foundation (WPF) applications that are hosting interoperation content, and a host supplied progress page.
Defines the contract for Win32 window handles.
Enums
Specifies the Direct3D surface types that are compatible with the D3DImage class.
Specifies the rendering preference.
Delegates
Represents the method that handles Win32 window messages.
Represents the method that handles the ThreadFilterMessage and ThreadPreprocessMessage events.
MSG Структура
Определение
Содержит информацию сообщения из очереди сообщений потока. Contains message information from a thread’s message queue.
Комментарии
Этот тип предоставляет аналогичные сведения для неуправляемой структуры сообщенияWin32. This type provides similar information to the unmanaged Win32 MSG structure.
Свойства
Возвращает или задает дескриптор (HWND) окна, оконная процедура которого получает данное сообщение. Gets or sets the window handle (HWND) to the window whose window procedure receives the message.
Возвращает или задает значение lParam , задающее дополнительную информацию о сообщении. Gets or sets the lParam value that specifies additional information about the message. Точный смысл зависит от значения члена message. The exact meaning depends on the value of the message member.
Возвращает или задает идентификатор сообщения. Gets or sets the message identifier.
Возвращает или задает координату x позиции курсора на экране в момент, когда было сгенерировано сообщение. Gets or sets the x coordinate of the cursor position on the screen, when the message was posted.
Возвращает или задает координату y позиции курсора на экране в момент, когда было сгенерировано сообщение. Gets or sets the y coordinate of the cursor position on the screen, when the message was posted.
Возвращает или задает время, когда было передано сообщение. Gets or sets the time at which the message was posted.
Возвращает или задает значение wParam , задающее дополнительную информацию о сообщении. Gets or sets the wParam value for the message, which specifies additional information about the message. Точный смысл зависит от значения сообщения. The exact meaning depends on the value of the message.
System. Windows. Interop Пространство имен
Предоставляет типы для поддержки взаимодействия между Windows Presentation Foundation (WPF) и другими технологиями, такими как API Windows, а также предоставляет базовые классы для других сценариев взаимодействия, в которых задействуется WPF. Provides supporting types for interoperation between Windows Presentation Foundation (WPF) and other technologies such as Windows APIs and provides base classes for other specific interoperation scenarios involving WPF.
Классы
Размещает элемент ActiveX как элемент в пределах содержимого Windows Presentation Foundation (WPF). Hosts an ActiveX control as an element within Windows Presentation Foundation (WPF) content.
Вспомогательный класс, предоставляющий сведения о среде браузера, в которой размещается приложение обозревателя XAML (XBAP). A helper class that provides information about the browser environment in which a XAML browser application (XBAP) application is hosted.
Разрешает совместное управление конвейером сообщений между Win32 и WPF в сценариях взаимодействия. Enables shared control of the message pump between Win32 and WPF in interoperation scenarios.
Предоставляет статический вспомогательный класс для взаимодействия между WPF и Win32 с одним методом, используемым для получения объекта Cursor Windows Presentation Foundation (WPF) на основе заданного дескриптора курсора Win32. Provides a static helper class for WPF/Win32 interoperation with one method, which is used to obtain a Windows Presentation Foundation (WPF) Cursor object based on a provided Win32 cursor handle.
Объект ImageSource, который отображает созданную пользователем поверхность Direct3D. An ImageSource that displays a user-created Direct3D surface.
Этот тип или член поддерживает инфраструктуру Windows Presentation Foundation (WPF) и не предназначен для непосредственного использования из кода. This type or member supports the Windows Presentation Foundation (WPF) infrastructure and is not intended to be used directly from your code.
Позволяет совершать вызовы из приложения обозревателя XAML к HTML-окну, в котором размещается приложение. Enables calls from a XAML browser application (XBAP) to the HTML window that hosts the application.
Размещает окно Win32 как элемент в пределах содержимого Windows Presentation Foundation (WPF). Hosts a Win32 window as an element within Windows Presentation Foundation (WPF) content.
Представляет содержимое Windows Presentation Foundation (WPF) в окне Win32. Presents Windows Presentation Foundation (WPF) content in a Win32 window.
Представляет связь с дескриптором окна, поддерживающего визуальную композицию. Represents a binding to a window handle that supports visual composition.
Предоставляет поддержку взаимодействия между управляемым и неуправляемым кодом для создания объектов изображений. Provides managed to unmanaged interoperation support for creating image objects.
InteropBitmap позволяет разработчикам повышать производительность отрисовки пользовательских интерфейсов не на основе WPF, размещаемых на платформе WPF, в сценариях взаимодействия. InteropBitmap enables developers to improve rendering performance of non-WPF UIs that are hosted by WPF in interoperability scenarios.
Используется для взаимодействия между кодом Windows Presentation Foundation (WPF) и Win32. Assists interoperation between Windows Presentation Foundation (WPF) and Win32 code.
Структуры
Содержит параметры, используемые для создания объекта HwndSource с помощью конструктора HwndSource(HwndSourceParameters). Contains the parameters that are used to create an HwndSource object using the HwndSource(HwndSourceParameters) constructor.
Содержит информацию сообщения из очереди сообщений потока. Contains message information from a thread’s message queue.
Интерфейсы
Определяет взаимодействие между приложениями Windows Presentation Foundation (WPF), в которых размещается содержимое взаимодействия, интерпретируемыми исполняемым кодом Windows Presentation Foundation (WPF), и страницей ошибки, предоставленной ведущим приложением. Defines the interaction between Windows Presentation Foundation (WPF) applications that are hosting interoperation content and interpreted by the Windows Presentation Foundation (WPF) executable, and a host supplied error page.
Предоставляет приемник сообщений от клавиатуры для компонентов, управляющих переходами по табуляции и действиями, выполняемыми с использованием сочетаний клавиш и мнемоник между границами взаимодействия и между HWND. Provides a keyboard sink for components that manages tabbing, accelerators, and mnemonics across interop boundaries and between HWNDs. Этот интерфейс реализует управление сообщениями от клавиатуры в сценариях взаимодействия WPF и Win32. This interface implements keyboard message management in WPF-Win32 interoperation scenarios.
Управляет фокусом ввода в контейнере. Manages keyboard focus within the container. Этот интерфейс реализует управление сообщениями от клавиатуры в сценариях взаимодействия WPF и Win32. This interface implements keyboard message management in WPF-Win32 interoperation scenarios.
Определяет взаимодействие между приложениями Windows Presentation Foundation (WPF), в которых размещается содержимое взаимодействия, и страницей хода выполнения, предоставленной ведущим приложением. Defines the interaction between Windows Presentation Foundation (WPF) applications that are hosting interoperation content, and a host supplied progress page.
Определяет контракт для дескрипторов окон Win32. Defines the contract for Win32 window handles.
Перечисления
Указывает типы поверхностей Direct3D, совместимые с классом D3DImage. Specifies the Direct3D surface types that are compatible with the D3DImage class.
Задает параметры отрисовки. Specifies the rendering preference.
Делегаты
Представляет метод, обрабатывающий сообщения окна Win32. Represents the method that handles Win32 window messages.
Представляет метод, обрабатывающий события ThreadFilterMessage и ThreadPreprocessMessage. Represents the method that handles the ThreadFilterMessage and ThreadPreprocessMessage events.
Component Dispatcher Класс
Определение
Разрешает совместное управление конвейером сообщений между Win32 и WPF в сценариях взаимодействия. Enables shared control of the message pump between Win32 and WPF in interoperation scenarios.
Комментарии
Хотя сам класс является статическим, все члены ComponentDispatcher относятся к конкретному потоку. Although the class itself is static, all members of ComponentDispatcher are specific to a particular thread. Например, если проверить значение IsThreadModal в двух разных потоках, могут быть получены разные значения. For example, if you examine the value of IsThreadModal on two different threads, you might get different values.
Методы являются статическими, но поддерживаются структурами данных для каждого потока. The methods are static but they are backed by per-thread data structures. Статические методы обеспечивают одноэлементный доступ, но ComponentDispatcher выполняют сортировку соответствующих операций для каждого потока. The static methods allow singleton access but the ComponentDispatcher is sorting out the appropriate per-thread operations.
Владелец конвейера сообщений определяется кодом, который вызывает функцию Win32- сообщение. The owner of the message pump is defined by the code that calls the Win32 function GetMessage. Владелец вызывает RaiseThreadMessage для каждого сообщения клавиатуры. The owner calls RaiseThreadMessage for every keyboard message. Этот метод вызывает ThreadFilterMessage событие с сообщениями, содержащимися в данных события. This method raises the ThreadFilterMessage event with the messages contained in the event data. Если это событие не обрабатывается, владелец вызывает ThreadPreprocessMessage событие с сообщениями, содержащимися в аргументе события. If that event is not handled, the owner raises the ThreadPreprocessMessage event with the messages contained in the event argument.
Поддерживаются только сообщения клавиатуры. Only keyboard messages are supported.
Свойства
Получает последнее созданное сообщение. Gets the last message that was raised.
Получает значение, указывающее, является ли поток модальным. Gets a value that indicates whether the thread is modal.
Методы
Вызывается для указания, что модальный поток более не является модальным. Called to indicate that a modal thread is no longer modal.
Вызывается для указания, что поток является модальным. Called to indicate that the thread is modal.
Вызывается для указания, что поток бездействует. Called to indicate that a thread is idle.
Указывает, что доступно новое сообщение для возможной обработки. Indicates that a new message is available for possible handling.
События
Возникает, когда поток становится модальным. Occurs when a thread becomes modal.
Возникает, когда модальный поток становится немодальным. Occurs when a modal thread becomes nonmodal.
Возникает, когда конвейер сообщений получает сообщение от клавиатуры. Occurs when the message pump receives a keyboard message.
Возникает, когда поток бездействует. Occurs when the thread is idle.
Возникает, когда конвейер сообщений получает сообщение от клавиатуры. Occurs when the message pump receives a keyboard message.
Hwnd Source Class
Definition
Presents Windows Presentation Foundation (WPF) content in a Win32 window.
Many members of this class are unavailable in the Internet security zone.
An HwndSource implements a Win32 window that can contain WPF content. The WPF content in the window is arranged, measured, and rendered; and is interactive to input. Because the HwndSource is specifically designed to interoperate with Win32, this class exposes several low-level Win32 features. You can use this class to do the following:
Specify window styles, window class styles, and extended window styles.
Hook the window procedure.
Provide access to the window handle (HWND).
Destroy the window.
The HwndSource class is designed for general interoperability and is not designed as a managed HWND wrapper. In general, it does not provide managed methods for manipulating the window or properties for inspecting its state. Instead, the HwndSource class provides access to the Win32 window handle (HWND) through the Handle property, which can be passed by means of PInvoke techniques to Win32 APIs in order to manipulate the window.
Construction
Many aspects of the HwndSource can only be specified at construction time. To create an HwndSource, first create an HwndSourceParameters structure and populate it with the desired parameters. These parameters include the following:
The class, window, and extended window styles. You must use PInvoke to change the styles after the window is created. Not all styles can be changed after the window is created. Consult the Win32 documentation before changing window styles.
The initial position of the window.
The initial size of the window, which includes whether the size is specified or should be determined from the determined size of the WPF content.
The parent window.
The HwndSourceHook to include in the window procedure chain. If you specify a hook at construction time, it receives all messages for the window. You can use AddHook to add a hook after the window is created.
The transparency settings. A top-level window can be configured to blend with the other windows on the desktop according to the per-pixel transparency of the WPF content. To enable this, set the UsesPerPixelOpacity property in the HwndSourceParameters to true . This property can only be specified at construction time, and only through the HwndSource(HwndSourceParameters) constructor signature, and it imposes several limitations.
After you populate the HwndSourceParameters structure, pass it to the HwndSource(HwndSourceParameters) constructor for the HwndSource.
Object Lifetime
An HwndSource is a regular common language runtime (CLR) object, and its lifetime is managed by the garbage collector. Because the HwndSource represents an unmanaged resource, HwndSource implements IDisposable. Synchronously calling Dispose immediately destroys the Win32 window if called from the owner thread. If called from another thread, the Win32 window is destroyed asynchronously. Calling Dispose explicitly from the interoperating code might be necessary for certain interoperation scenarios.
Window Procedures
The HwndSource class implements its own window procedure. This window procedure is used to process important window messages, such as those related to layout, rendering, and input. However, you can also hook the window procedure for your own use. You can specify your own hook during construction by setting the HwndSourceParameters.HwndSourceHook property, or you can also use AddHook and RemoveHook to add and remove hooks after the window is created. The hooks are called by last-in first-out order, which enables your hooks to execute before the built-in processing. The actual hooks are held by a weak reference. Therefore, make sure that you manage the lifetime of your hook delegate.
For more information about HwndSource and other interoperation classes, see WPF and Win32 Interoperation.
Notice how the constructors for HwndSource take parameters that resemble the parameters for Win32 functions such as CreateWindowEx.
Scale transformations should not be applied to the RootVisual of an HwndSource. See Remarks for RootVisual.
Constructors
Initializes a new instance of the HwndSource class by using a structure that contains the initial settings.
Initializes a new instance of the HwndSource class with a specified class style, style, extended style, x-y position, width, height, name, and parent window.
Initializes a new instance of the HwndSource class with a specified class style, style, extended style, x-y position, width, height, name, and parent window, and by specifying whether the window is autosized.
Initializes a new instance of the HwndSource class with a specified class style, style, extended style, x-y position, name, and parent window.
Properties
Gets the value that determines whether to acquire Win32 focus for the WPF containing window for this HwndSource.
Gets a sequence of registered input sinks.
Gets the visual manager for the hosted window.
Gets or sets the default AcquireHwndFocusInMenuMode value for new instances of HwndSource.
Gets the Dispatcher this DispatcherObject is associated with.
(Inherited from DispatcherObject) Handle
Gets the window handle for this HwndSource.
Gets a value that indicates whether Dispose() has been called on this HwndSource.
Gets or sets a reference to the component’s container’s IKeyboardInputSite interface.
Gets the RestoreFocusMode for the window.
Gets or sets the RootVisual of the window.
Get or sets whether and how the window is sized to its content.
Gets a value that declares whether the per-pixel opacity of the source window content is respected.
Methods
Adds an event handler that receives all window messages.
Adds a PresentationSource derived class instance to the list of known presentation sources.
(Inherited from PresentationSource) CheckAccess()
Determines whether the calling thread has access to this DispatcherObject.
(Inherited from DispatcherObject) ClearContentRenderedListeners()
Sets the list of listeners for the ContentRendered event to null .
(Inherited from PresentationSource) CreateHandleRef()
Gets the window handle for the HwndSource. The window handle is packaged as part of a HandleRef structure.
Releases all managed resources that are used by the HwndSource, and raises the Disposed event.
Determines whether the specified object is equal to the current object.
(Inherited from Object) FromHwnd(IntPtr)
Returns the HwndSource object of the specified window.
Gets the visual target of the window.
Serves as the default hash function.
(Inherited from Object) GetType()
Gets the Type of the current instance.
(Inherited from Object) HasFocusWithinCore()
Gets a value that indicates whether the sink or one of its contained components has focus.
Creates a shallow copy of the current Object.
(Inherited from Object) OnDpiChanged(HwndDpiChangedEventArgs)
Called when the DPI is going to change for the window.
Called when one of the mnemonics (access keys) for this sink is invoked.
Registers the IKeyboardInputSink interface of a contained component.
Removes the event handlers that were added by AddHook(HwndSourceHook).
Removes a PresentationSource derived class instance from the list of known presentation sources.
(Inherited from PresentationSource) RootChanged(Visual, Visual)
Provides notification that the root Visual has changed.
(Inherited from PresentationSource) TabIntoCore(TraversalRequest)
Sets focus on either the first tab stop or the last tab stop of the sink.
Returns a string that represents the current object.
(Inherited from Object) TranslateAcceleratorCore(MSG, ModifierKeys)
Processes keyboard input at the key-down message level.
Processes WM_CHAR, WM_SYSCHAR, WM_DEADCHAR, and WM_SYSDEADCHAR input messages before the OnMnemonic(MSG, ModifierKeys) method is called.
Enforces that the calling thread has access to this DispatcherObject.
(Inherited from DispatcherObject)
Events
Occurs when layout causes the HwndSource to automatically resize.
Occurs when content is rendered and ready for user interaction.
(Inherited from PresentationSource) Disposed
Occurs when the Dispose() method is called on this object.
Occurs when the DPI of the monitor of this Hwnd has changed, or the Hwnd is moved to a monitor with a different DPI.
Occurs when the value of the SizeToContent property changes.
Explicit Interface Implementations
For a description of this member, see IList.Remove(Object).
For a description of this member, see KeyboardInputSite.
For a description of this member, see OnMnemonic(MSG, ModifierKeys).
For a description of this member, see TabInto(TraversalRequest).
For a description of this member, see TranslateChar(MSG, ModifierKeys).
В кратце суть такова. Есть программа, написанная на C#. Довольно долго работала без сбоев, но с недавних пор все переменилось и теперь она зачастила падать выбрасывая вышеупомянутое исключение, при том входные параметры не меняются. Воспроизвести ошибку у себя с отладчиком никак не выходит. Предположительно возникает при формировании WPF форм.
Вот стек ошибки, если кому поможет:
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Runtime.InteropServices.SEHException
Stack:
at System.IO.UnmanagedMemoryStream.ReadByte()
at System.IO.BinaryReader.ReadByte()
at System.IO.BinaryReader.Read7BitEncodedInt()
at System.Resources.ResourceReader._LoadObjectV2(Int32, System.Resources.ResourceTypeCode ByRef)
at System.Resources.ResourceReader.LoadObjectV2(Int32, System.Resources.ResourceTypeCode ByRef)
at System.Resources.ResourceReader.LoadObject(Int32, System.Resources.ResourceTypeCode ByRef)
at System.Resources.RuntimeResourceSet.GetObject(System.String, Boolean, Boolean)
at System.Resources.RuntimeResourceSet.GetObject(System.String, Boolean)
at System.Resources.ResourceManager.GetObject(System.String, System.Globalization.CultureInfo, Boolean)
at System.Resources.ResourceManager.GetStream(System.String, System.Globalization.CultureInfo)
at MS.Internal.Resources.ResourceManagerWrapper.GetStream(System.String)
at MS.Internal.AppModel.ResourcePart.EnsureResourceLocationSet()
at MS.Internal.AppModel.ResourcePart.GetContentTypeCore()
at System.IO.Packaging.PackagePart.get_ContentType()
at System.Windows.Application.LoadComponent(System.Object, System.Uri)
at Тестер.DigitInputQuestUIElement.InitializeComponent()
at Тестер.DigitInputQuestUIElement..ctor(DigitInputQuest)
at Тестер.Tester+DigitInputQuest.Show()
at Тестер.Tester+Test.showQuest(Int32)
at Тестер.Tester+Test.questAnsvered(System.Collections.Generic.List`1)
at Тестер.Tester+SingleSelectQuest.ansvered(Int32)
at Тестер.SingleSelectQuestUIElement+<>c__DisplayClass7.<.ctor>b__5(System.Object, System.Windows.Input.MouseButtonEventArgs)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(System.Delegate, System.Object)
at System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate, System.Object)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(System.Object, System.Windows.RoutedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(System.Object, System.Windows.RoutedEventArgs, Boolean)
at System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject, System.Windows.RoutedEventArgs)
at System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs)
at System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs, Boolean)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs)
at System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr, System.Windows.Input.InputMode, Int32, System.Windows.Input.RawMouseActions, Int32, Int32, Int32)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr, MS.Internal.Interop.WindowMessage, IntPtr, IntPtr, Boolean ByRef)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
at MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)
at System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
at System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(System.Object)
at System.Windows.Application.RunInternal(System.Windows.Window)
at System.Windows.Application.Run(System.Windows.Window)
at System.Windows.Application.Run()
at Тестер.App.Main()
Выручайте, друзья! Уже неделю мозги сушу…
Introduction
Modern C# and the .NET platform usually abstracts all the underlying platform stuff away (e.g. see Kestrel, Windows Forms, etc.).
But isn’t it cool to use the same basic primitives that the teams building the frameworks use?
An additional perk is that you can have much more control over that!
And it’s fun.
Let’s see how we can open a native window using Win32 API. And draw something on it.
In order to do that, we will need to follow the next steps:
- Configuring the project
- Registering the window class
- Defining WindowProc function
- Creating a window
- Adding a message loop
- Drawing something on the window
Full Program.cs code is available in the Win32CsharpCreateWindow github repository.
Configuring the project
Firstly, .NET relies on a mechanism called P/Invoke that communicates with the underlying platform.
Usually, people call all the code that interacts with the platform — interop code.
In my recent post, I showed how to generate the interop code for OBS.
Luckily, there is already a Nuget package with generated interop code for Win32 called TerraFX.Interop.Windows.
Let’s add it to the project.
Additionally, we need to enable Unsafe code, so that we can use the pointers ( yeah, we will need to deal with pointers ).
That can be done by adding a simple AllowUnsafeBlocks
XML tag to your project file (.csproj):
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Registering the window class
To create a window, one must use a window class to describe the window they are trying to create.
Even though there are some system classes already there, but usually we would want to create our own one.
In Win32, we would use the function RegisterClassExW
to register the window class.
The function expects a single argument — pointer to the WNDCLASSEXW
structure that contains all the parameters.
It provides shared settings for every window created with that class.
These settings include a bunch of things, but one of the most important ones is the WndProc (Window Procedure) — a pointer to the function that will receive the messages sent to the window.
We will talk about it in the later section.
Let’s imagine we created that function and called it WinProc
.
An additional caveat is that Windows expects UTF-16 encoded characters for the window class name.
Luckily, .NET also stores characters as UTF-16 under the hood, so we can capitalise on that.
Another thing to consider, is that all managed objects (meaning things you create on the heap) can be moved by Garbage Collector (GC) at any point.
So we need to say to GC that it can’t move the string when we pass it to Win32 API.
In .NET, that concept is called «pinning».
In C# we can use the fixed
keyword to achieve that.
With that knowledge, let’s define the window class:
static unsafe HWND CreateWindow() { var className = "windowClass"; fixed (char* classNamePtr = className) { var windowClass = new WNDCLASSEXW(); windowClass.cbSize = (uint)sizeof(WNDCLASSEXW); windowClass.hbrBackground = HBRUSH.NULL; windowClass.hCursor = HCURSOR.NULL; windowClass.hIcon = HICON.NULL; windowClass.hIconSm = HICON.NULL; windowClass.hInstance = HINSTANCE.NULL; windowClass.lpszClassName = (ushort*)classNamePtr; windowClass.lpszMenuName = null; windowClass.style = 0; windowClass.lpfnWndProc = &WinProc; var classId = RegisterClassExW(&windowClass); } }
Defining WindowProc function
One may wonder — why does Windows need a function pointer for my window to work?
Here’s the deal — the reason lies in the way the OS communicates with the created windows.
When events connected to the window occur in the operating system or when the OS expects the window to do something, Windows sends a Message to the window (more about messaging here).
- The user pressed the mouse button? Windows sends
WM_LBUTTONDOWN
message. - The user pressed something on the keyboard? Windows sends
WM_KEYDOWN
message. - Windows wants the window to redraw itself? Windows sends
WM_PAINT
message.
WinProc is the function that handles these messages and makes the window do something in response to them.
It accepts the window, the message and some additional data related to the message.
Handling all messages in existence is very hard, so Win32 helpfully provides a default handler called DefWindowProcW
that you can call in the procedure.
One gotcha is that it expects you to handle WM_PAINT
(render requests) messages in any case, or it will send you them infinitely.
Thankfully, we can just do an empty draw call via BeginPaint
and EndPaint
function pair.
How can we pass the function as the pointer to the operating system? Well, for that .NET has a [UnmanagedCallersOnly]
attribute.
The attribute makes the compiler validate that the function can be called from unmanaged code safely (in this case, from the OS).
From that, let’s define our WinProc function:
[UnmanagedCallersOnly] static unsafe LRESULT WinProc(HWND window, uint message, WPARAM wParam, LPARAM lParam) { if(message == WM.WM_PAINT) { var ps = new PAINTSTRUCT(); var deviceContextHandle = BeginPaint(window, &ps); EndPaint(window, &ps); return 0; } return DefWindowProcW(window, message, wParam, lParam); }
Creating a window
Creating the window is an easy part.
We have already registered the class of our window, so all we need to decide now is the style, position and the size of our window.
There are numerous styles that can apply, but a sensible default is the WS_OVERLAPPEDWINDOW
(see here for more styles).
This kind of window has a title bar (with a window menu), border, a sizing border, a button to minimize and maximize the window.
We can make the window visible by default by adding the WS_VISIBLE
flag.
In addition to window styles (where we chose WS_OVERLAPPEDWINDOW
and WS_VISIBLE
), there are also extended window styles. But we are not interested in the latter right now, so we can just pass 0.
In this example, we will choose a 500×500 window opened at position (0, 0):
static unsafe HWND CreateWindow() { var className = "windowClass"; var windowName = "windowName"; fixed (char* windowNamePtr = windowName) fixed (char* classNamePtr = className) { var width = 500; var height = 500; var x = 0; var y = 0; var styles = WS.WS_OVERLAPPEDWINDOW | WS.WS_VISIBLE; var exStyles = 0; return CreateWindowExW((uint)exStyles, (ushort*)classNamePtr, (ushort*)windowNamePtr, (uint)styles, x, y, width, height, HWND.NULL, HMENU.NULL, HINSTANCE.NULL, null); } }
Adding a message loop
If we run the program at this point, it will exit instantly.
Even if we make it pause via something like while(true)
, it will not behave as we expect.
What is the solution?
When we defined the WinProc procedure, we mentioned that OS communicates with the window via messages.
Sometimes, they go directly to the WinProc function.
But in most cases, we need to «read» those messages from a message queue and pass them on to the function.
The process of getting the messages from the message queue is called «the message loop».
To pick up a message, we need to call GetMessageW
.
Then, to pass this message to our WinProc, we need to call DispatchMessage
.
And that’s it! (NB: if we cared about keyboard input, we would also need TranslateMessageW
before dispatching the message)
static unsafe void RunMessageLoop(HWND window) { MSG msg; while(GetMessageW(&msg, window, 0, 0)) { DispatchMessageW(&msg); } }
Then we just need to call our CreateWindow
and RunMessageLoop
functions.
var window = CreateWindow();
RunMessageLoop(window);
Drawing something on the window
The window is rather bland.
What if we could draw something a bit more interesting?
Let’s, for example, draw the last positions of the mouse which is moving across the window.
Our data structure is pretty trivial — a queue of last mouse positions and the maximum number of them that we should track.
static Queue<MousePoint> LastPositions = new(); const int MaxPositions = 200; record MousePoint(int X, int Y);
To fill the LastPositions
queue, let’s handle WM_MOUSEMOVE
message in the WinProc function.
There, we would want to remember the position of the mouse we receive from the OS.
Since that new position should be drawn to the screen, we need to tell the OS that the window should be redrawn by using InvalidateRect
function.
[UnmanagedCallersOnly] static unsafe LRESULT WinProc(HWND window, uint message, WPARAM wParam, LPARAM lParam) { ... if (message == WM.WM_MOUSEMOVE) { var xPos = LOWORD(lParam); var yPos = HIWORD(lParam); LastPositions.Enqueue(new MousePoint(xPos, yPos)); InvalidateRect(window, null, BOOL.FALSE); return 0; } ... }
Now, we need to update the WM_PAINT handling.
We need to do two things:
- Remove the tail by hiding points that were inserted long ago.
- Draw the pixels that are in the queue.
SetPixel
function allows us to do both of those things.
[UnmanagedCallersOnly] static unsafe LRESULT WinProc(HWND window, uint message, WPARAM wParam, LPARAM lParam) { if (message == WM.WM_PAINT) { var ps = new PAINTSTRUCT(); var deviceContextHandle = BeginPaint(window, &ps); while (LastPositions.Count > MaxPositions) { var extraPosition = LastPositions.Dequeue(); SetPixel(deviceContextHandle, extraPosition.X, extraPosition.Y, RGB(255, 255, 255)); } foreach (var point in LastPositions) { SetPixel(deviceContextHandle, point.X, point.Y, RGB(0, 0, 0)); } EndPaint(window, &ps); return 0; } ... }
And we have the final result (full Program.cs is in the Win32CsharpCreateWindow github repository):
Conclusions
Even though the Win32 API was designed for C, we can easily use it from C# via some interop bindings.
In this way, we can take the best from two worlds: utilise the full power of the Windows platform we are developing on and use as much of type safety as C# can provide.
Tags: csharp interop win32
The Msg method offered by the Interop external object enables displaying a message in a pop-up window.
Below is an example of how this feature is used.
Step 1
Create a new Panel object.
Step 2
Define a variable based on VarChar(200). Suppose you call it &MsgPopup and it is present in the Panel Layout. This variable will allow entering a message to be shown in a pop-up window on the device.
Step 3
Add a new button in the Panel Layout (associated with an Event called PopMSG).
Step 4
Go to the event by double-clicking on the button and define the following code:
Event 'PopMSG'
Interop.Msg(&MsgPopup)
EndEvent
Done! The entry Panel will accept a message and when the button is tapped, the text in a message dialogue will be prompted.
Since GeneXus 16 upgrade 9, the Msg method accepts two parameters: the message and the button text. For example:
Event 'PopMSG'
Interop.Msg("This is a test", "Ok, thanks")
EndEvent