日記に近いメモです。
前置き
メンテナンスしている、とあるWinFormsアプリは.NET Frameworkで動作しているのですが、開発者としては.NET 5に備え.NET Core 3.1に移行したいところです。
しかし、手元のWinFormsアプリはVisual Studio 2017 Expressで開発しているので、そう簡単に.NET Core(の新しいcsproj形式)に移行できません。
WinFormsデザイナーが使用できないと、UIに手を入れるのが非常に面倒になります。
そこで「移行」するのではなく、Visual Studio 2017(.NET Framework)で開発可能なまま.NET Coreでもビルドできる状態を目指していきます。
(使用していないソースコードを削除する以外は、ソースコードは変えません。)
Visual Studio 2019が使えればこんな面倒なことはしません。
対象のソースコード
下記のようなディレクトリ構成だとします。細かいファイルは省略してます。
なお、このアプリはx86でしか動作しませんが、開発環境はx64です。
SolutionFolder/
├───MyApps.sln
├───MyFormsApp/
│ ├───MyForms.csproj
│ ├───Form1.cs
│ ├───...
│ └───Program.cs
└───MyLib/
└───MyLib.csproj
準備
基本的にはWindows フォーム デスクトップ アプリを .NET Core に移植する方法を参考にします。
.NET Portability Analyzer
.NET Portability Analyzer で事前に検証すべきですが、最近はWindows 互換機能パックにより互換性が高めなので、明らかに[.NET Coreで使用できない機能](.NET Core で使用できない .NET Framework テクノロジ)(WCFとか)を使用していないのであれば、自己責任でやらなくてもいいかもしれません。
.NET Core SDK
アプリはx86でしか動作しませんが、開発環境に合わせて.NET Core 3.1 SDK x64をインストールします。
dotnet
コマンドが動作すること確認しておきます。
PS > dotnet --list-sdks
3.1.100 [C:\Program Files\dotnet\sdk]
PS > dotnet --list-runtimes
Microsoft.AspNetCore.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
csprojに含まれないソースコードを削除する
.NET Coreではワイルドカードでソースコードを指定するため、使用していないソースコード(ゴミ)が残っている場合は削除しておきます。
新しいcsprojを作成する
docs.microsoft.comの例に倣い、MyFormsAppCore
というディレクトリを作成して、その中に.NET Core用のプロジェクトを作ります。
MyFormsAppの中に作ると、dotnet
コマンドで毎回プロジェクトファイルを指定しないと行けないので面倒になります。
SolutionFolder/
├───MyApps.sln
├───MyFormsApp/
│ ├───MyForms.csproj
│ ├───Form1.cs
│ ├───...
│ └───Program.cs
├───MyLib/
│ └───MyLib.csproj
└───MyFormsAppCore/ <--- New folder for core project
dotnet/try-convertというツールもありますが、今回は手動で行います。
PS > cd SolutionFolder/MyFormsAppCore
PS SolutionFolder\MyFormsAppCore> New-Item -Type File MyFormsAppCore.csproj
dotnet new winforms
コマンドで作成してもいいんですが、
どうせ*.cs
ファイルを消して.csproj
ファイルを作成する必要があるので直接作ります。
csprojの編集
下記を貼り付けます。
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AssemblyName>MyCoreApp</AssemblyName>
<RootNamespace>WindowsFormsApp1</RootNamespace>
<Deterministic>false</Deterministic>
<LangVersion>7.3</LangVersion>
<PlatformTarget>x86</PlatformTarget>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\MyFormsApp\**\*.cs" Exclude="..\MyFormsApp\obj\**\*.cs" />
<EmbeddedResource Include="..\MyFormsApp\**\*.resx" />
</ItemGroup>
</Project>
-
AssemblyName
/RootNamespace
は実際のプロジェクトに合わせて(古いcsprojファイルを参照して)変えます。 -
LangVersion
は Visual Studio 2017で使用可能な7.3までにします。 -
AssemblyVersion.cs
で、[assembly: AssemblyVersion("1.0.*")]
のようなワイルドカードを使用していたので、エラー CS8357が発生します。今回はソースコードは変えない前提なので、<Deterministic>false</Deterministic>
を追加します。 - Visual Studio 2017でビルドしていると、
obj
ディレクトリ内に自動生成された*.cs
ファイルが作成されるので、Exclude
属性で除外しています。 - 前述の通り、x86でしか動作しないので
PlatformTarget
にx86
を指定しています。 - x86でしか動作しないWinFormsアプリなので、コマンドラインでの指定を省略できるように
RuntimeIdentifier
にwin-x86
を指定しています。x64でも動作させるなら、指定は外しておくべきでしょう。
追加の編集
デフォルトで、ある程度使える設定はされていますが、何も設定をしなくていいわけではありません。
下記の設定(タグ)を、旧csprojからコピペが必要でした。
パスも調整する必要があります。
ApplicationIcon
ApplicationManifest
NuGet参照
使用するライブラリの精査が面倒なら、 Windows 互換機能パックへの参照を追加します。
PS SolutionFolder\MyFormsAppCore> dotnet add package Microsoft.Windows.Compatibility
手元のプロジェクトだとMEFを使用していたので、
PS SolutionFolder\MyFormsAppCore> dotnet add package System.Composition
だけで済みました。
プロジェクト参照
使用するライブラリへの参照を追加します。
元のMyFormsApp.csproj
の中から、..\MyLib\MyLib.csproj
を指定しているItemGroup
タグをコピーして、MyFormsAppCore.csproj
に貼り付けます。
...
<ItemGroup>
<ProjectReference Include="..\MyLib\MyLib.csproj">
<Project>{8E29561D-E424-4AAB-A4FA-E966EF653A0F}</Project>
<Name>MyLib</Name>
</ItemGroup>
...
ライブラリ自体は.NET Frameworkのままですが、結果的に手元のプロジェクトは何もせずにビルドできました。
正しくは事前に.NET Coreプロジェクト化したcsprojを用意して、dotnet add reference
で追加する必要があるでしょう。
ビルド
上手く行っていれば、問題なくビルドできるはずです。
# Debugビルド
PS SolutionFolder\MyFormsAppCore> dotnet build
# Releaseビルド
PS SolutionFolder\MyFormsAppCore> dotnet build -c Reelase
実行
PS SolutionFolder\MyFormsAppCore> dotnet run
発行
発行する方法はいくつかありますが、batファイルを用意することにします。
dotnet publish -c Release --output publish
実行後、SolutionFolder\MyFormsAppCore\publish\MyCoreApp.exe
が作成されているので、それを実行します。
PublishTrimmed
やPublishSingleFile
を使用したければ、dotnet publishコマンドのリファレンスに従って、オプションは調整しましょう。