65.9K
CodeProject 正在变化。 阅读更多。
Home

手机满电

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (17投票s)

2014年5月28日

CPOL

4分钟阅读

viewsIcon

23434

downloadIcon

164

在 Windows Phone 8.0 上赋能 C++

引言

Windows Phone 8 是一个有些陌生的平台,但它在很多方面都像桌面版的 Windows 一样工作。因此,让桌面代码运行起来并完成繁重的工作,只生成新的 UI 将会非常方便。内容在我指尖展开,于是许多有趣的技术在这里被揭示出来,这些是我通过谷歌搜索互联网发现的,最终造就了这个小小的应用程序。

背景

我在 iPhone 上做了很多工作,但很好奇 Windows Phone 能做什么。于是我阅读了一些链接,找到了一个 微软的示例,它指导我创建了用于 C# UI 的 DLL。

全局概览

一张图片胜过千言万语,所以我提供了一张图来清楚地描述我的软件架构。

对于真正好奇的人:将 xap 文件重命名为 zip 文件并解压缩以查看内容。

代码的有趣之处

里面有很多东西,但主要目标是向你展示如何访问一些 C++ 线程并以非阻塞方式将数据获取到 C# UI。

C# 中的简单部分

为了连接 UI,我们设置了一个回调,以便在工作线程中的数据到达时获得更新。

//Callback if new data arrived
worker.OnNewData += worker_OnNewData; 

回调是从 `NativeWorker` 类中的 C++ 线程调用的。

//Propagating the new Data to the UI
OnNewData( this, new PropertyChangedEventArgs( "DataBuffer" ) ); 

在读取了新数据并准备好显示后,通过 `Buffer` 类的数据传输更有趣。它在 C# 中看起来很简单,但在 C++ 中却很棘手。

Windows.Storage.Streams.Buffer iBuffer = new Windows.Storage.Streams.Buffer( (uint) count );
//this is the final call to get data from the component 
runtime.FillBuffer( iBuffer );
DataReader reader = DataReader.FromBuffer(iBuffer); 

为了获得响应式 UI,我们需要多线程。这也使得该架构对于流媒体或通信项目很有吸引力。

Thread workerThread = new Thread( runtime.StartStream ); 
// Start the worker thread.
 workerThread.Start(); 

现在,我们准备好处理更难的部分了。

C# 中的难点

C++ 组件通过引用暴露了一个接口和类。

因此,我们可以创建一个对象并访问其函数。

 public static NativeBackend runtime = null;//only one 
 runtime = new NativeBackend();
 runtime.setCallback( this );
 runtime.SetUrl( s );  

我们实现了这些接口,这样当新数据到达时,C++ 就可以调用它们。

C++ 中的简单部分

C++ 中简单部分是 C++ 中的 C# 接口。它是对 C# “可见”的层:接口和类。类内部运行着本地 C++。最顶层的命名空间必须与组件的名称相同,这一点很重要。微软知道为什么——我不。

 namespace WPComponent
{
    public interface class INativeInterface
    {
        void OnNewState(Platform::String^ state);
        void OnSendData(int count);
    }; 

这个接口也在 C# 中实现。

 class NativeWorker : INativeInterface 

类从这里开始。

 public ref class NativeBackend sealed 

神秘的关键词是使类在 Windows Runtime 中正确公开所必需的。

C++ 中的肮脏部分

我想对微软的类表达一些愤怒,因为在苹果的世界里,很多事情都做得更聪明。苹果的人称之为“样板代码”并憎恨它。我也憎恨它,因为“你只活一次”。

size_t Len = url->Length();
char *Data = new char[Len+1];
wcstombs_s( &Len, Data, Len+1, url->Data(), Len ); 

在苹果公司,只需一个调用(消息)到 NSString 对象,你就完成了。是!!!

 char* Data = [url UTF8String]; 

C++ 中的难点

C++ 中难点是 `Run()` 函数。在我的演示中,它只是等待并填充缓冲区。在这里,所有编码员都可以完成他们繁重的工作:下载、处理或上传。对于上传,`Buffer` 传输只需要是另一个方向。

do
{
    //do the hard work
    i++;
    DWORD wait = WaitForSingleObjectEx( hWait, 1000, 0 );
    //::SetEvent(hWait);
    //prepare some output
    int count = sprintf_s( buffer, "%s. Here it comes from C++ %ld\n", Data, i );

    SendData( (BYTE*) buffer, count );
}
while( Running ); 

C++ 中的最难部分

C++ 中最难的部分是将位从 C++ 复制到 C# 接口的函数。原因是将真正的内存原生位复制到托管运行时是一件大事。这“是 COM 的最佳体现”,并与智能指针一起工作。我在这里找到了这个出色的解决方案 here

ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
// Query the IBufferByteAccess interface.
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;
} 

要理解这一点,你需要了解 IInspectable,它在“代码世界”之间架起了桥梁。这段代码真的很棒

再一点

调试效果很好,但你需要选择调试托管代码还是本地代码。这里有一个截图,你可以在其中进行切换。

关注点

这表明 Windows Phone 确实是一个有趣且强大的平台,它具有巨大的潜力,并且可以轻松地将大量 C++ 代码移植过来。通过这种方式,许多大型库都可以投入使用,例如 PJSIPLive 555。PJSIP 还有一个自己的 Windows Phone 版本堆栈,只需要引用即可。

历史

  • 初始版本
© . All rights reserved.