Introduction
Windows Phone 8 is a somehow unknown platform but it works like Windows on the desktop in many ways. So it would be very handy to get desktop code running and doing the hard work and only generate a new UI. The content expanded under my fingers and so a real bunch of interesting technologies are here unveiled which I discovered by Googling the internet which are resulting in that tiny App.
Background
I have been working a lot on the iPhone but wondering what the Windows Phone can do. So I read some links and found a sample from Microsoft which led the way to create the DLL which serves the C# UI.
The Big Picture
A picture says more than a thousand words, so I provided one clearly to describe my software architecture.
For who is real curious: rename the xap to a zip and expand it to see the content.
Interesting Points of the Code
It is a lot inside, but the main goal is to showcase you to access some C++ threads and fetching the data to the C# UI in a nonblocking way.
The Easy Part in C#
To wire up the UI, we set a callback to get an update when data from the working thread arrives.
worker.OnNewData += worker_OnNewData;
The callback got called from the C++ thread in the NativeWorker
class.
OnNewData( this, new PropertyChangedEventArgs( "DataBuffer" ) );
After the new data is read and ready to get presented, more interesting is the data transfer via the Buffer
class. It looks simple in C# but got tricky in C++.
Windows.Storage.Streams.Buffer iBuffer = new Windows.Storage.Streams.Buffer( (uint) count );
runtime.FillBuffer( iBuffer );
DataReader reader = DataReader.FromBuffer(iBuffer);
To get a responsive UI, we need threading. That also makes this architecture interesting for streaming or communication projects.
Thread workerThread = new Thread( runtime.StartStream );
workerThread.Start();
And now, we are ready for the harder stuff.
The Harder Part in C#
The C++ component exposes an interface and class which we imported per reference.
So we can create an object and access the functions.
public static NativeBackend runtime = null;
runtime = new NativeBackend();
runtime.setCallback( this );
runtime.SetUrl( s );
And we implement the interfaces, so it can get called from C++ if new data arrives.
The Easy Part in C++
The easy part in C++ is the C# interface in C++. It is the layer which is "visible" to C#: interface and the class. Inside of the class runs the native C++. It is important that the top-most namespace is the same as the name of the component. Microsoft knows why - I'm not.
namespace WPComponent
{
public interface class INativeInterface
{
void OnNewState(Platform::String^ state);
void OnSendData(int count);
};
This interface is also implemented in C#:
class NativeWorker : INativeInterface
And here starts the class:
public ref class NativeBackend sealed
The mysterious keywords are needed to expose the class properly in the Windows Runtime.
The Filthy Part in C++
I want to express some anger about the Microsoft classes because in the Apple world much is going really smarter. The Apple guys name that "boiler plate code" and hate it. I hate it also because "you only live once".
size_t Len = url->Length();
char *Data = new char[Len+1];
wcstombs_s( &Len, Data, Len+1, url->Data(), Len );
In Apple, is it one call (message) to the NSString object and you are done. Yeah!!!
char* Data = [url UTF8String];
The Hard Part in C++
The hard part in C++ is the Run()
function. In my demonstration, it only waits and fills a buffer. Here is point in all coders can do their heavy work: downloading, processing or uploading. For an upload, the Buffer
transfer only needs to be the other direction.
do
{
i++;
DWORD wait = WaitForSingleObjectEx( hWait, 1000, 0 );
int count = sprintf_s( buffer, "%s. Here it comes from C++ %ld\n", Data, i );
SendData( (BYTE*) buffer, count );
}
while( Running );
The Hardest Part in C++
The hardest part in C++ is the function which copies the bits from C++ to the C# interface. The reason is that is a big deal copying real memory native bits into the managed runtime. It is "COM at its best" and works with smart pointers. I found this outstanding solution here.
ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
reinterpret_cast<IInspectable*>(iBuffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess));
if( bufferByteAccess != NULL )
{
byte* dest = nullptr;
bufferByteAccess->Buffer(&dest);
memcpy( dest, m_pBuffer, m_nBuffer );
iBuffer->Length = m_nBuffer;
}
To understand it, you need to know about IInspectable which bridges between the "code worlds". This code really rocks.
One More Thing
Debugging works fine, but you need to choose whether debugging the managed code or the native code. Here is a screenshot where you can switch.
Points of Interest
It shows that Windows Phone is really an interesting and powerful platform which has huge potential and to which a lot of C++ code can get adopted with not much huzzle. In that way, a lot of big libraries could get to work like PJSIP or Live 555. The PJSIP has also a own version of its stack for Windows Phone which only needs to be referenced.
History