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

幕后:第 2 部分:C++ WinRT 组件 DLL 和 C# Metro 应用程序

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2012 年 3 月 2 日

CPOL

5分钟阅读

viewsIcon

25061

C++ WinRT 组件 DLL 和 C# Metro 应用程序

在本篇文章中,我们已经开发了一个 C++ WinRT 组件 DLL 和 C#.NET 应用程序。

这里重要的点是 C# 应用程序通过 RCW 机制访问 C++ WinRT 组件。同一个应用程序也可以用 JavaScript 开发,并且可以使用我们开发的 C++ DLL。哇,是不是很酷?

为了理解新编程模型的简单性,我们在第一部分创建了一个 C++ WinRT 组件 DLL,这是编写 Windows Runtime 组件所需的所有代码。

请下载代码并解压文件。

#pragma once

using namespace Windows::Foundation;
 
namespace CppWinRTComponentDll
 { 
    public ref class CalculatorSample sealed
     {
     public:
         int Add(int x, int y);
         int Sub(int x, int y);
         int Mul(int x, int y);
 
    };
 }

在这个例子中,您会立即注意到一些不是标准 C++ 的关键字。Visual C++ 定义了一些组件扩展,在 Metro 风格的应用中,它们本质上是底层 COM 调用(用于创建和使用 Windows Runtime 类型)的语法糖。您通常在 public interface 中使用这些扩展,当您的代码通过 ABI 将 Windows Runtime 类型与 JavaScript、C#、Visual Basic(甚至另一个 C++ 模块)进行双向传递时。Visual C++ 在 Windows Runtime 类型和标准 C++ 类型之间提供了各种隐式转换。典型的模式是内部像往常一样使用标准 C++ 类型和库,并在 public interface 中转换为 Windows Runtime 类型。

那么 C++ 组件是如何被 .NET 应用程序调用的呢?当我们构建 CppWinRTComponentDll 项目时,会在输出窗口看到以下内容。注意高亮的 CppWinRTComponentDll.winmd 文本。这意味着编译器正在生成一个 windmd 类型的文件。

1>—— Build started: Project: CppWinRTComponentDll, Configuration: Debug Win32 ——    
1>  CppWinRTComponentDll.vcxproj -> 
C:\Users\Kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll With 
CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.winmd     
1>  LINK : C:\Users\kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll 
With CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.dll not found or 
not built by the last incremental link; performing full link     
1>     Creating library C:\Users\kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll 
With CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.lib and object 
C:\Users\kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll With 
CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.exp     
1>  CppWinRTComponentDll.vcxproj -> C:\Users\kishore\Documents\Visual Studio 11\
Projects\CppWinRTComponentDll With CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.dll     
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

您可以在调试文件夹中注意到 CppWinRTComponentDll.winmd 文件(CppWinRTComponentDll 附带 CSharp App\Debug\CppWinRTComponentDll),如图 1 所示。

image

图 1:.WinMD 文件存在于 Debug 文件夹内的 CppWinRTComponentDll 文件夹中。

这个 WinMD 文件本质上是一个 CLI 元数据文件,可以用 ILDASM 打开,如图 2 所示。CppWinRTComponentDll 是通过 CppWinRTComponentDll.winmd 文件中的 API 元数据公开的。WinMD 文件的格式是 Ecma-335,这与 .NET Framework 使用的格式相同。它只是使用了 ECMA-335 文件格式标准和框架,仅此而已。底层的二进制契约使我们能够以自己选择的开发语言直接访问 CppWinRTComponentDll API。通过静态语言(如 C#)和动态语言(如 JavaScript)都可以理解 CppWinRTComponentDll API 的形状和结构。在 C# 应用程序(CSharpApplication 项目)中可以看到,JavaScript、C#、Visual Basic 和 C++ 都支持 IntelliSense。

image

图 2:使用 ILDASM 打开 CppWinRTComponentDll.winmd 文件。

这个 CppWinRTComponentDll.winmd 文件是由 C++ 编译器创建的,可以看作是一个跨语言的头文件,因为 C# 无法理解 C++ 头文件,JavaScript 也无法理解。所以我们需要一个所有语言都能理解的文件格式,那就是 .winmd 文件格式。尽管我们编写了一个 CalculatorSample 类,但编译器为我们做的是,它还创建了一个 interface __ICalculatorSamplePublicNonVirtuals,如图 3 所示,这是用于与 calculator 类通信的 COM 接口。这将其添加到了公共接口中。

image

图 3:编译器创建的接口 ICalculatorSamplePublicNonVirtuals

CppWinRTComponentDll.winmd 文件的清单如图 4 所示。

image

图 4:CppWinRTComponentDll.WinMD 文件的清单。注意第一项,mscorlib。

如图 5 所示,我们可以在 WinmD 文件中看到 Add 方法的签名。

image

图 5:CppWinRTComponentDll.winmd 文件中存在的 Add 方法签名。
.method public newslot abstract virtual instance int32        
Add(int32 x,         
int32 y) cil managed         
{         
} // end of method __ICalculatorSamplePublicNonVirtuals::Add

在 ILDASM 中,单击 .class interface private abstract auto ansi windowsruntime。GUID 属性。这就像指定接口的 GUID,如图 6 所示。这是组件的 GUID。

image

图 6:接口的 GUID。

WinMD 文件不包含任何 IL。它就像一个头信息,以便其他语言能够理解。这使得 Projections 能够发生。calculator 本身就是一个 ref classCppWinRTComponentDll.CalculatorSample 类实现了 .__ICalculatorSamplePublicNonVirtuals ,并实现了 AddSub Mul 方法,如下面的图 7 所示。

image

图 7:CppWinRTComponentDll.CalculatorSample 类实现了 __ICalculatorSamplePublicNonVirtuals 接口。

请注意,WinRT 中的每个对象都是 ref 计数的。

关于在第一部分创建的 C++ WinRT 组件 DLL 的详细信息(MSDN):C++/CX (Component Extensions)

Visual Studio 11 中的 Visual C++ 有一个创建 Metro 风格应用和组件的新编程模型。新模型的主要特性之一是抽象二进制接口(ABI),它定义了一个用于跨语言通信的接口。在 Windows Developer Preview 中,原生 C++ 可以通过 ABI 与 JavaScript 和托管 .NET 语言 C# 和 Visual Basic 进行通信。这意味着您可以用原生 C++ 创建高性能组件,并直接从其他语言中消耗它们。这也意味着您可以在原生 C++ 中直接使用 Windows Runtime 类型,而无需像使用 .NET Framework 类型时那样进行互操作。

在底层,新的编程模型基于 COM 的更新版本,但使用此新模型的方式比旧式 COM 编程更简单、更自然。当您在原生 C++ 中创建可用的 Windows Runtime 组件或 Metro 风格应用时,您主要像在标准 C++ 中一样使用类和成员。JavaScript 或 .NET 代码使用 new(或 New)实例化您的对象,并且根据客户端语言的机制销毁对象。当原生 C++ 使用 Windows Runtime 对象时,销毁通过引用计数来处理。

下载代码并解压文件。

“通过致力于一个事业、一个计划或一个价值体系来培养乐观主义。您会感到自己在朝着一个有意义的方向发展,这将帮助您克服日常的挫折。”—— Robert Conroy 博士

注意:代码是使用 Windows 8 和 Visual Studio 2011 开发者预览版开发的,实际版本发布时可能会有所更改。

© . All rights reserved.