-
-
Save fincs/2732608 to your computer and use it in GitHub Desktop.
// | |
// Fully native C++ WinRT application example | |
// Programmed by fincs | |
// | |
#include <windows.h> | |
#include <roapi.h> | |
#include <wchar.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <wrl.h> | |
#include <Windows.UI.Xaml.h> | |
#include <Windows.UI.Xaml.Markup.h> | |
#include <Windows.ApplicationModel.Activation.h> | |
using namespace Microsoft::WRL; | |
using namespace Microsoft::WRL::Wrappers; | |
using namespace Windows::Foundation; | |
using namespace ABI::Windows::UI::Xaml; | |
using namespace ABI::Windows::UI::Xaml::Markup; | |
using namespace ABI::Windows::ApplicationModel::Activation; | |
//--------------------------------------------------------------------------- | |
// Error handling | |
//--------------------------------------------------------------------------- | |
// Even though this is officially unsupported and the corresponding declaration in | |
// the header files is left out for WinRT apps, it is actually possible to use these | |
// "forbidden" functions via manually including the declaration like as follows: | |
extern "C" int WINAPI MessageBoxW(HWND parent, LPCWSTR aText, LPCWSTR aTitle, int opt); | |
// Error checking helper | |
void CheckHRESULT(HRESULT hr, LPCWSTR message) | |
{ | |
if (FAILED(hr)) | |
{ | |
WCHAR aBuf[1024]; | |
swprintf_s(aBuf, L"Error 0x%08X during: %s", hr, message); | |
MessageBoxW(NULL, aBuf, L"BareMetalMetroApp", MB_ICONERROR); | |
exit(1); | |
} | |
} | |
//--------------------------------------------------------------------------- | |
// Application class | |
//--------------------------------------------------------------------------- | |
class MyApp: public RuntimeClass<IApplicationOverrides> | |
{ | |
InspectableClass(L"BareMetalMetroApp.MyApp", BaseTrust); | |
protected: | |
ComPtr<IApplicationOverrides> pBaseImpl; | |
public: | |
void SetBase(IApplicationOverrides* _pBaseImpl) | |
{ | |
pBaseImpl = _pBaseImpl; | |
} | |
STDMETHOD(OnActivated)(IActivatedEventArgs* args) { return pBaseImpl->OnActivated(args); } | |
STDMETHOD(OnLaunched)(ILaunchActivatedEventArgs* args); | |
STDMETHOD(OnFileActivated)(IFileActivatedEventArgs* args) { return pBaseImpl->OnFileActivated(args); } | |
STDMETHOD(OnSearchActivated)(ISearchActivatedEventArgs* args) { return pBaseImpl->OnSearchActivated(args); } | |
STDMETHOD(OnShareTargetActivated)(IShareTargetActivatedEventArgs* args) { return pBaseImpl->OnShareTargetActivated(args); } | |
STDMETHOD(OnFileOpenPickerActivated)(IFileOpenPickerActivatedEventArgs* args) { return pBaseImpl->OnFileOpenPickerActivated(args); } | |
STDMETHOD(OnFileSavePickerActivated)(IFileSavePickerActivatedEventArgs* args) { return pBaseImpl->OnFileSavePickerActivated(args); } | |
STDMETHOD(OnCachedFileUpdaterActivated)(ICachedFileUpdaterActivatedEventArgs* args) { return pBaseImpl->OnCachedFileUpdaterActivated(args); } | |
}; | |
//--------------------------------------------------------------------------- | |
// OnLaunched event | |
//--------------------------------------------------------------------------- | |
#define MARKUP_TO_LOAD \ | |
L"<Grid xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">" \ | |
L" <TextBlock Text=\"Hello, fully native world!\" VerticalAlignment=\"Center\" HorizontalAlignment=\"Center\" FontSize=\"48\" />" \ | |
L"</Grid>" | |
// TODO: find out how to listen to events coming from e.g. buttons | |
// L" <Button Content=\"Click me\" VerticalAlignment=\"Center\" HorizontalAlignment=\"Center\" />" | |
/* | |
// This is what this function looks like under C++/CX: | |
void MyApp::OnLaunched(ILaunchActivatedEventArgs^ args) | |
{ | |
Window::Current->Content = XamlReader::Load(MARKUP_TO_LOAD); | |
} | |
*/ | |
STDMETHODIMP MyApp::OnLaunched(ILaunchActivatedEventArgs* args) | |
{ | |
// Prepare HSTRING versions of class names | |
HStringReference WindowClsName(RuntimeClass_Windows_UI_Xaml_Window); | |
HStringReference XamlReaderClsName(RuntimeClass_Windows_UI_Xaml_Markup_XamlReader); | |
HStringReference MarkupData(MARKUP_TO_LOAD); | |
// pCurWin = Window::Current | |
ComPtr<IWindow> pCurWin; | |
{ | |
ComPtr<IWindowStatics> pWinStatics; | |
CheckHRESULT(GetActivationFactory(WindowClsName.Get(), &pWinStatics), L"IWinStatics"); | |
CheckHRESULT(pWinStatics->get_Current(&pCurWin), L"get_Current"); | |
} | |
ComPtr<IUIElement> pContent; | |
{ | |
ComPtr<IXamlReaderStatics> pXamlReaderStatics; | |
ComPtr<IInspectable> pObj; | |
// pContent = XamlReader::Load(MarkupData) | |
CheckHRESULT(GetActivationFactory(XamlReaderClsName.Get(), &pXamlReaderStatics), L"IXamlReaderStatics"); | |
CheckHRESULT(pXamlReaderStatics->Load(MarkupData.Get(), &pObj), L"Markup loading failure"); | |
CheckHRESULT(pObj.As(&pContent), L"IUIElement"); | |
} | |
// pCurWin->Content = pContent | |
pCurWin->put_Content(pContent.Get()); | |
pCurWin->Activate(); | |
return S_OK; | |
} | |
//--------------------------------------------------------------------------- | |
// Application initialization function | |
//--------------------------------------------------------------------------- | |
/* | |
// This is what this function looks like under C++/CX: | |
static void InitApplication(IApplicationInitializationCallbackParams^ args) | |
{ | |
auto app = ref new MyApp(); | |
} | |
*/ | |
static STDMETHODIMP InitApplication(IApplicationInitializationCallbackParams* args) | |
{ | |
// Prepare HSTRING versions of class names | |
HStringReference ApplicationClsName(RuntimeClass_Windows_UI_Xaml_Application); | |
ComPtr<IApplicationFactory> pAppFactory; | |
CheckHRESULT(GetActivationFactory(ApplicationClsName.Get(), &pAppFactory), L"IApplicationFactory"); | |
ComPtr<MyApp> pMyApp = Make<MyApp>(); | |
ComPtr<IApplication> pApp; | |
{ | |
// This is done like this because pInner is set to a reference to the same object as the | |
// return value (albeit with a different VTable (offset)), and the Microsoft guys *FORGOT* | |
// to AddRef(). Therefore we need to throw out the pInner pointer. | |
IInspectable* pInner; | |
CheckHRESULT(pAppFactory->CreateInstance(pMyApp.Get(), &pInner, &pApp), L"CreateInstance"); | |
} | |
// Set the inherited Application object | |
ComPtr<IApplicationOverrides> pBaseImpl; | |
CheckHRESULT(pApp.As(&pBaseImpl), L"IApplicationOverrides"); | |
pMyApp->SetBase(pBaseImpl.Get()); | |
return S_OK; | |
} | |
//--------------------------------------------------------------------------- | |
// Application entrypoint | |
//--------------------------------------------------------------------------- | |
/* | |
// This is what this function looks like under C++/CX: | |
int main() | |
{ | |
Application::Start(ref new ApplicationInitializationCallback(InitApplication)); | |
return 0; | |
} | |
*/ | |
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) | |
{ | |
// Initialize WinRT | |
RoInitializeWrapper init(RO_INIT_MULTITHREADED); | |
CheckHRESULT(init, L"RoInitialize"); | |
ComPtr<IApplicationStatics> pAppStatics; | |
HStringReference ApplicationClsName(RuntimeClass_Windows_UI_Xaml_Application); | |
CheckHRESULT(GetActivationFactory(ApplicationClsName.Get(), &pAppStatics), L"IApplicationStatics"); | |
// Application::Start(AppMain) | |
ComPtr<IApplicationInitializationCallback> pCallback = Callback<IApplicationInitializationCallback>(InitApplication); | |
pAppStatics->Start(pCallback.Get()); | |
return 0; | |
} |
- This code was written in the days of Windows 8 CP, so the interface may have changed.
- You need to link to
user32.lib
.
I was able to get this code to compile and run in Windows 8 RTM by adding the following to MyApp:
STDMETHOD(OnWindowCreated)(IWindowCreatedEventArgs* args) { return S_OK; }
if I attempted to add
STDMETHOD(OnWindowCreated)(IWindowCreatedEventArgs* args) { return pBaseImpl->OnWindowCreated(args);}
as adrushya suggested above, then at runtime the app would crash due to a stack overflow. pBaseImpl is the same as 'this' at runtime. Perhaps your comment in InitApplication about the VTable is no longer applicable to Win8 RTM?
Thanks for this enlightening sample!
Tom
Hi
I'm new under the metro. I had try your source. It compiled and ran simple, but didn't do anything (I mean nothing show up). Did I do something wrong?
FreeVili
Sorry but this is not a complete Windows store Application. Thanks anyway.
This crashes on startup :/
windows\dxaml\xcp\dxaml\lib\frameworkapplication_partial.cpp(143)\Windows.UI.Xaml.dll!00007FFF204C5EA0: (caller: 00007FF7D8D3D169) FailFast(1) tid(3694) 8000FFFF Catastrophic failure
To run the application, you need an application package manifest. The XAML UI APIs require an application to have a package identity. For more information see Creating a minimal UWP app using the WRL and Run, debug, and test an MSIX package. Another option would be to create a Win32 app and use XAML islands (this option requires an application manifest): Host a standard UWP control in a C++ Win32 app
Hi Fincs,
One has to add one more method
STDMETHOD(OnWindowCreated)(IWindowCreatedEventArgs* args) { return pBaseImpl->OnWindowCreated(args);}
so that one can create an instance of this class MyApp.
Also the MessageBox thingy does not compile.
Even after removing all the compile time error I could not get this to work. It simply crashes.
Any ideas what might be going wrong.
Thanks,
--=> Adru.