如何在C++/WinRT/UWP项目中从CoreWindow获取ICoreWindowInterop
Hey there, let's get this sorted out for you—getting the right HWND and HINSTANCE is key to making DirectInput recognize your joystick in a UWP app, and I know the COM interop part can feel confusing when coming from traditional Win32 or dealing with C++/WinRT's unique model.
First, forget GetTopMostWindow—UWP uses a different window model
UWP apps don't expose their windows through old Win32 top-level window functions like that. You need to use the ICoreWindowInterop interface to bridge the C++/WinRT CoreWindow type to the HWND you need. And don't worry about CComPtr—C++/WinRT has its own smart pointer, winrt::com_ptr, that plays nicely with its types.
Step-by-Step Implementation
1. Include the necessary headers
Add these to your source file (likely App.cpp):
#include <windows.ui.core.interop.h> #include <winrt/Windows.UI.Core.h> #include <dinput.h> // For DirectInput types
Don't forget to link against dinput8.lib in your project settings (under Linker > Input > Additional Dependencies).
2. Convert CoreWindow to ICoreWindowInterop in App::OnLaunched
Here's how to get the interop interface, extract the HWND, and grab a valid HINSTANCE:
void App::OnLaunched(LaunchActivatedEventArgs const& e) { // Keep your existing window setup code (like creating the root Frame) Frame rootFrame = Window::Current().Content().as<Frame>(); if (rootFrame == nullptr) { rootFrame = Frame(); rootFrame.NavigationFailed({ this, &App::OnNavigationFailed }); Window::Current().Content(rootFrame); } if (e.PrelaunchActivated() == false) { if (rootFrame.Content() == nullptr) { rootFrame.Navigate(xaml_typename<YourAppName::MainPage>(), e.Arguments()); } Window::Current().Activate(); } // --- Start of DirectInput setup code --- // Get the current CoreWindow winrt::Windows::UI::Core::CoreWindow coreWindow = Window::Current().CoreWindow(); // Get the underlying IUnknown pointer from the CoreWindow wrapper winrt::com_ptr<ICoreWindowInterop> coreWindowInterop; winrt::check_hresult( winrt::get_unknown(coreWindow)->QueryInterface( winrt::guid_of<ICoreWindowInterop>(), reinterpret_cast<void**>(coreWindowInterop.put()) ) ); // Extract the HWND HWND hwnd = nullptr; winrt::check_hresult(coreWindowInterop->get_WindowHandle(&hwnd)); // Get a valid HINSTANCE for your UWP app HINSTANCE hInstance = GetModuleHandleW(nullptr); // Now initialize DirectInput with these values LPDIRECTINPUT8 di = nullptr; winrt::check_hresult( DirectInput8Create( hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, reinterpret_cast<void**>(&di), nullptr ) ); // Set the correct cooperative level (critical for joystick enumeration) winrt::check_hresult( di->SetCooperativeLevel( hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND // Adjust to DISCL_NONEXCLUSIVE if needed ) ); // Now you can enumerate joysticks as usual! // ... your joystick enumeration code here ... }
Key Notes to Avoid Headaches
- Use
winrt::check_hresult: This macro throws an exception if a COM call fails, making it way easier to debug issues instead of silently ignoring errors. - UI Thread Only: Run this code on the UI thread—
OnLaunchedis already on the UI thread, so this is safe. If you need to access the HWND later from a background thread, marshal back to the UI thread first. - Add Game Controller Capability: Enable this in your
Package.appxmanifestotherwise your app won't have permission to access joystick devices:<Capabilities> <DeviceCapability Name="gameController" /> </Capabilities>
Why this works
C++/WinRT types like CoreWindow are wrappers around COM objects. winrt::get_unknown retrieves the underlying IUnknown* from the wrapper, which we use to query the ICoreWindowInterop interface. This interface gives us direct access to the HWND UWP uses under the hood—something DirectInput needs to properly associate with input devices (including joysticks).
内容的提问来源于stack exchange,提问作者SebKun

