Some third-party hardware and software SDKs for Windows communicate with the host application via Windows messages. When trying to integrate such SDKs into Unreal Engine 4 plug-ins, access to the Windows message queue is required. There are many examples on the internet that show how to use the message queue, and it is often tempting to shoehorn such code into the Windows platform layer in UE4. However, this makes the plug-in less modular and more dependent on future Engine changes, and excludes a potentially large number of users, because not everyone is able or willing to merge Engine code changes. It also prevents the plug-in from making it into the Unreal Engine Marketplace.
Luckily, there is an Engine API that allows any plug-in to intercept and process Windows messages without requiring such modifications. This article explains how to use it and provides working sample code on Github.
Getting access to Windows messages in UE4 can be accomplished by registering a so called message handler with the underlying platform application. A message handler is a class in your plug-in that implements the IWindowsMessageHandler interface. This interface is currently very simple and contains a single a method that will be executed each time a message has been received from the operating system:
virtual bool ProcessMessage(
HWND hwnd, uint32 msg, WPARAM wParam, LPARAM lParam, int32& OutResult) = 0;
The handler is registered via the platform application object, which can be obtained from the Slate UI framework:
FWindowsApplication* Application =
Note that we downcast the application object to FWindowsApplication in order to bypass the platform abstraction layer. Downcasting is often a symptom of poorly designed APIs, and you should not make a habit of it, but here it is acceptable, because we need to access Windows platform-specific features. Since the plug-in is only supported on Windows, and because we do not intend to mock platform objects in UE4, we can be near certain that the returned object will always be an FWindowsApplication.
Once we have a pointer to the Windows application object, we can use it to register and unregister the message handler:
When our plug-in is being unloaded, either on shutdown or by the user’s request, we need to make sure that the handler is properly unregistered:
And that is all there is to it. Your message handler object will now have its ProcessMessage method called for each Windows message. If the plug-in consumes the message and no other handlers should receive it, the method may return true, otherwise false. Make sure to not consume messages not intended for your plug-in, or funny things may happen.
For a fully working example of message handler registration and unregistration take a look at the FWindowsMessageHandlerExampleModule class in the WindowsMessageHandlerExample plug-in on GitHub.
What about Platform-agnostic Code?
We go to great lengths to keep the Unreal Engine code base platform-agnostic, which means that there should be as little code as possible that depends on a particular target platform, such as Windows or PS4. We mainly achieve this with the platform abstraction layer in Core, which hides the particularities of each platform behind a generic facade. In very rare cases we also use platform-specific #ifdefs. While this is frowned upon and highly discouraged in Engine code, it is often acceptable in plug-ins.
For obvious reasons, the code described above is Windows-specific, and that is OK, because we are integrating a Windows-specific feature that is not intended to be used on non-Windows platforms. Hence there is no contradiction between our striving for platform-agnostic code and creating a Windows-specific plug-in.
If the SDK you are integrating contains several different platform-specific APIs, i.e. for Windows, MacOS and Linux, you could quickly prototype it out with #ifdef PLATFORM_XYZ directives, and later refactor it into your own platform abstraction layer inside your plug-in.
General Words of Advice
Whenever you find yourself in need of modifying existing Engine code, alarm bells should be going off in your head. Chances are that you are not fully understanding how the relevant parts of the Engine work, or which extensibility APIs are available. There is no shame in that, because no single person in the world knows the entire code base. Many Engine APIs are also frequently being changed and extended.
However, once you’re trying to solve one particular problem, it pays off to dig into the existing code base. Refactoring tools, such as VAX make this pretty straightforward, but you can also simply search for related text strings as we try to choose meaningful and self-explanatory names for all of our classes, functions, and variables.
Finally, keep in mind that there are often different ways to solve a problem, and the first option may not be the best. For example, we do not currently have a platform-agnostic API for handling drag & drop operations in games, so rolling your own implementation via Windows messages is not a terrible idea. However, using this approach in the Editor is not advisable, because there we do, in fact, have platform-agnostic support for dragging and dropping files into the Content Browser via asset factories.