Friday, October 5, 2012

Dealing with create_task in WinRT using C++/CX


Getting into Windows8 C++/CX

Tutorials and introductions to C++/CX
http://msdn.microsoft.com/en-us/library/windows/apps/hh465045.aspx
from that link:
"When you use Windows Runtime objects, you're (typically) using C++/CX, which provides special syntax to create and access Windows Runtime objects in a way that enables C++ exception handling, delegates, events, and automatic reference counting of dynamically created objects. When you use C++/CX, the details of the underlying COM and Windows architecture are almost completely hidden from your app code. For more information, see C++/CX Language Reference. However, you can also program directly against the COM interfaces by using the Windows Runtime C++ Template Library."
"You're primarily programming against a new, easy-to-navigate, object-oriented API, the Windows Runtime, although Win32 is still available for some functionality."
Some functionality has me concerned as the threading and concurrency namespaces are useful for what we were doing in the previous C# version.
This continues into a tutorial about what the different components in a new project are. The partial ref and auto keyword are also mentioned in breif detail.
in the first paragraph of that page there were a couple of links to the C++/CX language reference including...
as a note the example shows Grid^ grid = ref new Grid(); the ^ is used when dealing with anything that uses ref new to create;
I guess this feels sort of like

int s = int(0);
int *i = &s;

where when a pointer is used you need to use a reference operator to get the value at the address of a pointer.
in my test i wrote the following.

auto grid = ref new Grid();//this is the same as Grid^
grid->Width = 600;
grid->Height = 500;
auto red = ref new SolidColorBrush(Colors::Red);
grid->Background = red;
if(grid->Parent == nullptr)
{
LayoutRoot->Children->Append(grid);
}

One important thing is that Colors::Red is not Colors->Red. As -> points to properties of a class and :: points to static members of a class.
"In the most basic sense, a ref class is a COM object that implements the IInspectable interface and whose lifetime is managed by a smart pointer."
"The partial keyword tells the compiler that the declaration of this class is continued in another code file."
good to know, sort of nice you can break up a big source file into a few small ones.

"If you, the programmer, have to add variables or functions to the MainPage class, do so in MainPage.xaml.h and MainPage.xaml.cpp." As you normally would.
"If the XAML editor has to add variables or other boilerplate code, it does so in the *.g.h and *.g.hpp files."

I've got to find where the .g. files are hiding in our project, I'm pretty sure I saw them somewhere, but i'll check if adding things into these files will allow for better cross talk between the C++ and C++/CX stuff.

"In general, you can safely ignore the *.g.* files. That's why Solution Explorer hides them by default."
Hey, hiding them by default? What if we, the programmer, need to edit the xaml?? WTF. Weird I can't find these files. oh well, moving on...
further down in the post there's a special include for

#include <ppltasks.h>

I didn't catch this include before, wasn't in any documentation other than the tutorial. Things like this can't be missed so I think something that important should be a bit more highlighted.

auto grid = ref new Grid();
grid->Width = 600;
grid->Height = 500;
auto red = ref new SolidColorBrush(Colors::Red);
grid->Background = red;

create_task([grid]{
grid->Height = 100; //this throws an error
}).then([grid]{});

if(grid->Parent == nullptr)
{
LayoutRoot->Children->Append(grid);
}

In the previous test code I found that this throws an error when trying to execute anything inside of the lambda in the create_task function. The red squiggle under the [grid] says a local lambda is not allowed in a member function of a WinRT class. Not sure why that is.
expanding on the create_task function. In

I created the following code to stick a wait timer.
auto i = 0.5;

create_task([this, i]{
auto thispage = this;
        thispage->Dispatcher->RunAsync(
CoreDispatcherPriority::Normal,
ref new DispatchedHandler([thispage,i]()
       {
thispage->GridControlElement->Opacity = i;
       }));
wait(SomeRandomInteger); //a static global variable.
}).then([this, i]{
auto thispage = this;
        thispage ->Dispatcher->RunAsync(
CoreDispatcherPriority::Normal,
ref new DispatchedHandler([thispage]()
        {
thispage->GridControlElement->Opacity = 1.0;
        }));
});

So this is scoped as the page that the create_task lives within. It's then passed through the lambda into the create_task function I also added an number value to see how that will work when passed into the [this,i] part of the create_task.

Then I created another auto so that this can be used as thispage. so now the create_task has access to elements on the page. so then we can create a new DispatchedHandler and pass along another referenced task.

Elements in the thispage reference can be accessed and modified asynchronously from the rest of the UI.
So after some amount of time while the wait is running, the UI element will be mostly translucent. then after the timer is up it goes back to being fully opaque.

all the while the wait is running the rest of the interface is doing just fine.

Adding this into a touch event...

http://msdn.microsoft.com/en-us/library/windows/apps/hh699871.aspx
from that link:
"Visual C++ component extensions (C++/CX) is a set of extensions to the C++ language that enable the creation of Windows Store apps and Windows Runtime components in an idiom that is as close as possible to modern C++. Use C++/CX to write Windows Store apps and components in native code that easily interact with Visual C#, Visual Basic, and JavaScript, and other languages that support the Windows Runtime. In those rare cases that require direct access to the raw COM interfaces, or non-exceptional code, you can use the Windows Runtime C++ Template Library (WRL)." and "Windows Store DirectX games and graphics-intensive apps. For more information, see Create your first Windows Store app using DirectX." the DirectX + Xaml are the core of what we're doing. also, that page has a "quick reference" for the other components for C++/CX

A collection of links to various C++/CX documentation dealing with the new extensions for WinRT

http://blogs.msdn.com/b/vcblog/archive/2012/08/29/cxxcxpart00anintroduction.aspx
http://sridharpoduri.com/2012/08/13/programming-windows-8-applications-using-c-cxan-update-on-the-book/

Thursday, October 4, 2012

Timers in windows8 using c++


Just getting a basic timer in c++ isn't as easy as in C#.
So I'm stepping myself through this and documenting my findings.
I just want to start a timer on a touch event to fade out a control when the finger leaves the screen.
So to do this I want that control to wait for a few seconds before going back to it's home position.
I could use wait, but then the rest of the screen locks up till after the wait.
Since I want to use multi touch features this is bad.
The best way to do this *I think* is concurrency and the call function, but finding a good example for this has been really hard.

http://msdn.microsoft.com/en-us/library/dd504870.aspx I started here to get a start on the concurrency run time.
Also writing a windows 8 metro app in WPF, so that's adding some little hitches here and there with various features that I can and can't use.
Also can't use 3rd party libs like boost.asio which is because the client doesn't like those things, doh.
Google for running multuple tasks and I get to
this link http://msdn.microsoft.com/en-us/library/dd728065.aspx.
In here was the following code snippet...

int wmain()
{
// Create a call object that prints a single character to the console.
call<wchar_t> report_progress([](wchar_t c) {
wcout << c;
});
// Create a timer object that sends the dot character to the  
// call object every 100 milliseconds.
timer<wchar_t> progress_timer(100, L'.', &report_progress, true);
wcout << L"Performing a lengthy operation";
// Start the timer on a separate context.
progress_timer.start();
// Perform a lengthy operation on the main context.
perform_lengthy_operation();
// Stop the timer and print a message.
progress_timer.stop();
wcout << L"done.";
}

This looked pretty helpful. There's the call and the timer functions that look pretty good.
Unfortunately in report_progress([] (wchar_t c) {...} there's a lambda and I get the following error

Error: a local lambda is not allowed in a member function of a WinRT class.

damn.

So now what? Dig around more for timer class in WinRT and I find
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/fd9c3010-484b-4881-88c8-765473fd5b1e
What's going on here?

Instead of SetTimer(), you should use Windows::UI::Xaml::DispatcherTimer.
See the MSDN article here: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.dispatchertimer.aspx.

Okay, so lets go there.
http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.dispatchertimer.aspx.
and...

Server Error in '/' Application.
The resource cannot be found.Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly. Requested URL: /en-us/library/windows/apps/windows.ui.xaml.dispatchertimer.aspx.

Crap, so look up xaml dispatch timer and get to  http://msdn.microsoft.com/en-us/library/windows/apps/xaml/windows.ui.xaml.dispatchertimer
I think im getting closer. This is looking a bit better, something that seems to be useful, finally.
I just used this in C# for the previous version of the interface I was building in C#, perfect!
I think I can use this. The example is in C# so i need to find a C++ example,
get to this http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/edff3bf2-4223-49fe-b66b-119702458700
The thread goes through a few iterations. I get to what I think is really close but get stuck at.

timer->Tick += ref new  Windows::Foundation::EventHandler<Object^>(this, &DispatcherTimer_Tick); 

I get an error:

object not needed for the specified function

So I delete "this" and the following "," and that seems to do the trick.
No more errors...
So I start my vars with...

Windows::UI::Xaml::DispatcherTimer ^SomeTimer;

and then add in a way to count ticks...

int Ticks;

and when the xaml page is initialized i add in

XAMLPage()
{
InitializeComponent();
//other init stuff...
SomeTimer = ref new DispatcherTimer;
SomeTimer->Tick += ref new  Windows::Foundation::EventHandler<Object^>( &Timer_Tick); 
TimeSpan t;
t.Duration=1;
SomeTimer->Interval = t;
}

Then I precede the page initialization with my Timer_Tick function that looks something like...

void Timer_Tick(Platform::Object^ sender, Platform::Object^ e)
{
OutputDebugString(L"TIMER!!!");
Ticks++;
if(Ticks>10)
SomeTimer->Stop();
}

so after 10 ticks the timer stops.

I'm far from a super c++ programmer, and mostly a C# or unrealscript game programmer guy.
I've been doing this stuff for a while and I learn fast, and that's pretty important.
I do these little process blog entries to help myself out.
It's like a breadcrumb trail I can follow to avoid backtracking.
Hope this helps someone.

rxokita's shared items