Skip to content

Instantly share code, notes, and snippets.

@fincs
Created May 19, 2012 22:37
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fincs/2732608 to your computer and use it in GitHub Desktop.
Save fincs/2732608 to your computer and use it in GitHub Desktop.
Fully native C++ WinRT (Metro-style) app
//
// 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;
}
@teodorbaciu
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment