How can I use WINRT c++ APIs in at Qt WINRT app?
-
Well, depending on the approach it's either smooth ride or a horror show. Here's a "world of pain" type example that gets current date using WRL and puts it on a Qt's label:
#include <QApplication> #include <QLabel> #include <wrl/client.h> #include <wrl/wrappers/corewrappers.h> #include <windows.globalization.h> #include <windows.globalization.datetimeformatting.h> namespace WRL = Microsoft::WRL; namespace Wrap = Microsoft::WRL::Wrappers; namespace Fnd = Windows::Foundation; namespace ABIFnd = ABI::Windows::Foundation; namespace ABIGlob = ABI::Windows::Globalization; auto format = L"{year.full}-{month.integer(2)}-{day.integer(2)}"; int main(int argc, char *argv[]) { QApplication a(argc, argv); QLabel lbl; lbl.setAlignment(Qt::AlignCenter); lbl.show(); //Qt initializes COM for us so we don't need to call RoInitialize WRL::ComPtr<ABIGlob::ICalendar> calendar; Wrap::HStringReference calendarClassId(RuntimeClass_Windows_Globalization_Calendar); if (SUCCEEDED(Fnd::ActivateInstance(calendarClassId.Get(), calendar.GetAddressOf()))) { ABIFnd::DateTime dateTime; if (SUCCEEDED(calendar->GetDateTime(&dateTime))) { WRL::ComPtr<ABIGlob::DateTimeFormatting::IDateTimeFormatterFactory> dateTimeFormatterFactory; Wrap::HStringReference dateTimeFormatterId(RuntimeClass_Windows_Globalization_DateTimeFormatting_DateTimeFormatter); if (SUCCEEDED(Fnd::GetActivationFactory(dateTimeFormatterId.Get(), dateTimeFormatterFactory.GetAddressOf()))) { WRL::ComPtr<ABIGlob::DateTimeFormatting::IDateTimeFormatter> dateTimeFormatter; Wrap::HStringReference dateTimeFormat(format); if (SUCCEEDED(dateTimeFormatterFactory->CreateDateTimeFormatter(dateTimeFormat.Get(), dateTimeFormatter.GetAddressOf()))) { Wrap::HString formattedDateTime; if (SUCCEEDED(dateTimeFormatter->Format(dateTime, formattedDateTime.GetAddressOf()))) { uint buff_len; auto buff = formattedDateTime.GetRawBuffer(&buff_len); lbl.setText(QString::fromWCharArray(buff, buff_len)); } } } } } return a.exec(); }
And yes, before you manage to say "H O L Y F U U U ..." this is exactly the same as:
#include <QApplication> #include <QLabel> #include <QDate> int main(int argc, char *argv[]) { QApplication a(argc, argv); QLabel lbl(QDate::currentDate().toString("yyyy-MM-dd")); lbl.setAlignment(Qt::AlignCenter); lbl.show(); return a.exec(); }
To spare yourself from going absolutely insane you might want to look into wrapper libraries like Modern.
-
@Chris-Kawa Thanks! I was actually hoping to use the HoloLens gestures as Qt has major problems with mouse and clicking on HoloLens. Or if Qt can be fixed I wouldn't have to.
I need to make the mouse follow and make clicking work on HoloLens. Like before Tuesday, haha!
-
Hi, thanks @Chris-Kawa for that example!
Because I like to hurt myself I had to try it on my Windows 10 PC (worked fine).
Just want to add, if you want to run it as well, you need to add:LIBS += -lruntimeobject
to your .pro file.
Edit: forgot to say: I tested with a vanilla Widgets app using the kit Desktop Qt 5.7.0 MSVC2015. However, if you instead select the Universal Windows Platform kit then that LIBS line above is not needed.
-
As much as I hate language extensions it would probably be easier to use C++/CX. It would make the example not much longer than that with Qt, but I can't seem to enable it.
Passing/ZW
and/AI <path to Platform.winmd>
to the compiler (via QMAKE_CXXFLAGS in .pro file) should be enough AFAIK, but I get errors on as simple line as this:String^ foo = ref new String(L"Hello");
error: C2664: 'long __winRT::__getActivationFactoryByPCWSTR(void *,Platform::Guid &,void **)': cannot convert argument 1 from 'const wchar_t []' to 'void *'
Probably some switch still missing somewhere... -
Hmm, never tried those pesky extensions, but being curious, I tried to reproduce your error but no luck :-( Maybe you're not on Windows 10 and MSVC2015?
I got it to run with your example above, by adding #include <qdebug.h> and these lines just before
return a.exec();
at the end:using namespace Platform; String^ foo = ref new String(L"Hello"); qDebug() << QString::fromWCharArray(foo->Data());
I tested both the 5.7.0 Desktop MSVC2015 32-bit and the Universal Windows Platform kit.
And yeah, those /ZW and /AI switches (no space between /AI and dirname!) have to be in the .pro file:
QMAKE_CXXFLAGS += /ZW /AI\"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcpackages\"
-
@hskoglund said:
Maybe you're not on Windows 10 and MSVC2015?
I'm on Win10 and MSVC2015 with Qt5.7UWP. Yeah, sorry, I mixed up my tests. The string alone works indeed, but try this full example and you should see the errors:
#include <QApplication> #include <QLabel> using namespace Platform; using namespace Windows::Globalization; using namespace Windows::Globalization::DateTimeFormatting; int main(int argc, char *argv[]) { QApplication a(argc, argv); auto calendar = ref new Calendar(); auto dateTime = calendar->GetDateTime(); String^ format = L"{year.full}-{month.integer(2)}-{day.integer(2)}"; auto dateTimeFormatter = ref new DateTimeFormatter(format); auto formatted = dateTimeFormatter->Format(dateTime); QLabel lbl(QString::fromWCharArray(formatted->Data())); lbl.setAlignment(Qt::AlignCenter); lbl.show(); return a.exec(); }
-
Great information, Thanks!
Unfortunately I don't think UWP HoloLens Gestures will work as it is 3D based and with a UWP app that's tough if not impossible. Well it would take some time and I have to have this project done before Tuesday. Probably not going to be possible.
Unless either of you know how to do this:
So the UWP apps are run in a container. Not sure if it is a Windows App Container or not but I want to be able to access the raw mouse & keyboard from the container level.Thanks so much for your help!
-
@Rad-B: Hi, I know games need to do this, and since some of them are UWP apps, raw mouse and keyboard access should be possible, for an example see stackoverflow
@Chris-Kawa: Indeed this time I got the errors (2 of them):
C:\Projects\untitled\main.cpp:23: error: C2664: 'long __winRT::__getActivationFactoryByPCWSTR(void *,Platform::Guid &,void **)': cannot convert argument 1 from 'const wchar_t [31]' to 'void *'
Googling a bit it seems this interesting error has struck more people than you (i.e you have not forgotten any switch or something similar).
So in conclusion I think this is a Monday morning bug and, while waiting for Microsoft to fix it (perhaps in Update 3?) you can always resort to a kludge, insert these fine lines of code just before
int main(...
:HRESULT __stdcall GetActivationFactoryByPCWSTR(void*,Guid&, void**); namespace __winRT { HRESULT __stdcall __getActivationFactoryByPCWSTR(const void* str, ::Platform::Guid& pGuid, void** ppActivationFactory) { return GetActivationFactoryByPCWSTR(const_cast<void*>(str), pGuid, ppActivationFactory); } }
This will cast away that const problem for you :-)
-
@hskoglund Thanks for the workaround. I wonder how such a blatant bug could have slipped in :/
@Rad-B I don't have HoloLens so I can only speculate, but looking at the examples it doesn't seem to be that different from my calendar example, you just use the classes from the
Windows::UI::Input::Spatial
namespace. It seems the C++/CX is the easiest here, so you will probably have to use the workaround @hskoglund provided.
See here for some code examples (the SpatialInputHandler.h/.cpp files). -
@Chris-Kawa @hskoglund How can I access Windows.UI.Core.CoreWindow?
namespace Windows::UI does not seem to work.
Thanks for both of your help!
-
Hey, good news! After years of begging Microsoft released a WinRT C++ library that doesn't suck like WRL: C++/WinRT
It's actually kinda simple to use. Close to Qt if not for the long names and namespaces. I gave it a whirl with the calendar example:
#include <QApplication> #include <QLabel> #include "winrt/Windows.Globalization.h" #include "winrt/Windows.Globalization.DateTimeFormatting.h" #pragma comment(lib, "windowsapp") using namespace winrt::Windows::Globalization; using namespace winrt::Windows::Globalization::DateTimeFormatting; int main(int argc, char *argv[]) { QApplication a(argc, argv); std::wstring formatted = DateTimeFormatter(L"{year.full}-{month.integer(2)}-{day.integer(2)}").Format(Calendar().GetDateTime()); QLabel lbl(QString::fromWCharArray(formatted.c_str())); lbl.setAlignment(Qt::AlignCenter); lbl.show(); return a.exec(); }