dotnet安装

.NET6默认会安装一个SDK和几个runtime

  • .NET SDK
  • .NET Runtime
  • ASP.NET Core Runtime
  • .NET Windows Desktop Runtime

可以通过dotnet命令行的--list-sdks以及--list-runtimes列举。

dotnet命令行

设置环境变量DOTNET_CLI_TELEMETRY_OPTOUT为1,避免信息采集。参考.NET SDK and .NET CLI telemetry

dotnet workload

通过dotnet workload search可以搜索到可用的workload。比如maui或者wasm-tools相关的。

dotnet new

dotnet new用于创建工程。直接执行会列出几个工程模板让你选择。

dotnet new web --search则会列出NuGet.org上的可用工程模板。

比如创建一个winforms模板的app:

dotnet new winforms -n winforms-app1

疑问:生成的工程文件中,哪些是需要纳入版本控制的? 回到:在csproj文件,比如<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.635-beta">

dotnet build

winforms-app1目录下执行dotnet build可以构建此工程。

相关命令:

  • dotnet clean,清理工程

dotnet run

winforms-app1目录下执行dotnet run可以运行此工程生成的可执行文件。

dotnet add

通过dotnet add可以从NuGet.org安装发布的软件包。比如:

dotnet add package Microsoft.Windows.CsWinRT

为了能够编译CsWinRT,需要在项目中开启

  <PropertyGroup>
    <CsWinRTEnabled >false</CsWinRTEnabled>
  </PropertyGroup>

否则会出现错误 Version 1.2.2 or greater produces “Path ‘7.0’ is not a file or directory” error #822

添加一个prelease的包需要指定--prerelease选项,如下所示:

dotnet add package --prerelease cswin32

其他相关命令:

  • dotnet list package列出工程中的的NuGet包
  • dotnet remove package删除一个NuGet包
  • dotnet pack可以用于制作nuget包
  • dotnet nuget隐藏着一些其他nuget相关命令

Using the Win32 Api in a C# program with C#/Win32

C#9引入了叫做Code Generators的东东,可以编译的时候动态生成代码。(听着有点像C++的模板,不过适用面看起来广多了)。

传统的.NET需要通过PInvoke来调用第三方代码。但是PInvoke需要描述文件。有专门的网站http://pinvoke.net/提供这些描述文件。

Code Generator给了PInvoke之外的另一种可能,CsWin32就是基于这种可能的产物。

来实践以下CsWin32

dotnet new console -o win32-app1
cd win32-app1
dotnet add package Microsoft.Windows.CsWin32 --prerelease

注意,必须使用0.1.422-beta版的package Microsoft.Windows.CsWin32,当前最新的0.1.635-beta会报错error CS0234: The type or namespace name 'Windows' does not exist in the namespace 'Microsoft'

创建一个名为NativeMethods.txt的文件,内容如下:

FindFirstFile
FindNextFile
FindClose

相应的代码如下:

using System;
using System.Linq;
using Microsoft.Windows.Sdk;
var handle = PInvoke.FindFirstFile("*.*", out var findData);
if (handle.IsInvalid)
    return;

上述代码使用了C#9的Top Level Statements的功能。

文中还展示了文件回调的例子。具体看https://github.com/bsonnino/UseWin32

C#/Win32 P/Invoke Source Generator

部分功能需要用到C#9。目前.NET6提供的是C#10,需要在项目中设置:

<LangVersion>9</LangVersion>

既有的Win32 PInvoke项目:https://github.com/dotnet/pinvoke

注意不能将AllowUnsafeBlocks 设为false。

NativeMethods.txt文件中列出所需要的Win32用编口,每行的内容可以是

  • 导出的方法的名字,可能带有A、W后缀
  • 一个命名空间,导出其中所有名字
  • 模块名后跟.*,比如kernel32.*
  • 结构、枚举、常量、接口等的名字
  • //开头的行注释,会被忽略掉

上述导出的内容,会在Windows.Win32.PInvoke下可见。

有一些选项来控制生成的代码。这些选项可以在NativeMethods.json中指定,例如:

{
  "$schema": "https://aka.ms/CsWin32.schema.json",
  "emitSingleFile": false
}

许多生成的类型中带有partial修饰符,允许向类型中添加额外的代码。

可以更新Microsoft.Windows.SDK.Win32MetadataNuGet包来获得更新的元数据。

也可以在工程文件中设置MicrosoftWindowsSdkWin32MetadataBasePath,指向Windows.Win32.winmd所在的目录。

小结

cswin32基于win32metadata,后者是通过扫描Win32的用编口头文件生成出来的。生成采用的工具是ClangSharp。 win32metadata也被xlang使用来生成rust的互操作描述文件。

项目地址:

NuGet包

其他参考

(完)