跨平台编程:Windows Phone与C#和C++的融合

在现代软件开发中,跨平台技术越来越受到重视。Windows Phone作为一个有潜力的平台,其开发环境允许开发者利用C#和C++技术来构建应用。本文将探讨如何将桌面代码迁移到Windows Phone,并展示如何结合C#和C++来实现高效的数据处理和UI更新。

笔者一直在iPhone平台上进行开发,但对Windows Phone的能力感到好奇。通过阅读微软提供的资料和示例,发现了一种创建DLL的方法,该DLL可以服务于C#用户界面。

大局观

为了更直观地描述软件架构,提供了一张清晰的图片。对于真正好奇的读者,可以将xap文件重命名为zip并解压以查看内容。

代码中的有趣点

代码中有许多内容,但主要目标是展示如何访问C++线程并以非阻塞方式将数据获取到C#UI。

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

worker.OnNewData += worker_OnNewData;

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

OnNewData(this, new PropertyChangedEventArgs("DataBuffer"));

在新数据读取并准备好呈现后,更有趣的是通过Buffer类进行数据传输。在C#中看起来简单,但在C++中却变得棘手。

Windows.Storage.Streams.Buffer iBuffer = new Windows.Storage.Streams.Buffer((uint)count); runtime.FillBuffer(iBuffer); DataReader reader = DataReader.FromBuffer(iBuffer);

为了获得响应式的UI,需要线程。这也使得这种架构对于流处理或通信项目变得有趣。

Thread workerThread = new Thread(runtime.StartStream); workerThread.Start();

现在,准备好进行更困难的部分了。

C++组件公开了一个接口和类,通过引用导入。这样就可以创建一个对象并访问函数。

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

实现了接口,以便在新数据到达时可以从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++中的简单部分是C#中的接口。它是对C#“可见”的层:接口和类。类内部运行原生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#接口复制位的函数。原因是将真正的内存原生位复制到托管运行时是一个大问题。这是“COM的最佳表现”,并且使用智能指针。在这里找到了这个杰出的解决方案。

ComPtr bufferByteAccess; reinterpret_cast(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,它在“代码世界”之间架起了桥梁。这段代码真的很强大。

调试

调试工作得很好,但需要选择是调试托管代码还是原生代码。这里有一张截图,可以切换。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485