Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
17
Help us understand the problem. What are the problem?

VSCode(Visual Studio Code)によるWindowsアプリ開発(WPF C# C/C++)

Visual Studioが重い!と思ってる私のような日曜プログラマー向け。

2021年2月現在、Visual Studio Code(以下VSCode)Build Tools for Visual Studio 2019(以下BuildTools)の組み合わせのみで、大抵のWindowsアプリ開発は出来る気がしている。デバッグも可。
本家Visual Studioなんて使わ…何でも無いです。1

試したこと

WPF(.NET 5)

一番開発しやすいと感じた。あとReadyToRunが適用出来る。
もうWindowsUpdateで.NET 5ランタイム同梱してくれんかなあ。(「Windows の更新時に他の Microsoft 製品の更新プログラムを受け取る」をオンにしておけば入ってくるらしいが、どれだけの人がオンにしていることか…。)
WinFormsは今更な感じがするし、UWPは魅力的ではあるけど(ストア限定という点で)自由が無いし、ということでWPF。

WPF(.NET Framework 4.7)

4.7な理由は、Creators Update(2017年春)以降のWindows 10には標準でランタイムが入ってるから。
多くの人に使ってもらえる。

ネイティブ(C/C++)

個人的には、マネージドでは出来ないことをネイティブなDLLにしてマネージドから呼び出す用。
…と思ってたけど、C++/WinRTのおかげでこちらも無視出来なくなってきた。場合によってはメインに返り咲く?

ダウンロード

VSCodeもBuildToolsもhttps://visualstudio.microsoft.com/ja/downloads/からGET出来る。
BuildToolsは分かりにくいが、ページの下の方の「> Visual Studio 2019 のツール」を展開したら、これまた下の方にある。

インストール

BuildTools

「個別のコンポーネント」タブにして、下記のものをチョイスして入れた。

【.NET】
  • .NET 5.0 ランタイム
  • .NET Core 3.1 ランタイム (LTS)
  • .NET Framework 4.7 Targeting Pack
  • .NET SDK

※Targeting Packは、使う予定のバージョンのものを入れる。
※SDKは「.NET SDK」だけで良い。多分。

【SDK、ライブラリ、およびフレームワーク】
  • Windows 10 SDK (10.0.19041.0)
  • Windows ユニバーサル CRT
【コード ツール】
  • NuGet のターゲットおよびビルド タスク
  • テキスト テンプレート変換
【コンパイラ、ビルド ツール、およびランタイム】
  • C++ 2019 再頒布可能パッケージの更新プログラム
  • MSVC v142 - VS 2019 C++ x64/x86 ビルド ツール (v14.28)
【開発作業】
  • C++ Build Tools コア機能
  • C++ コア機能

VSCode

「追加タスクの選択」で、「エクスプローラーの~追加する」となっている2か所にチェックを入れておくと便利。
vscode01.png

VSCodeの初期設定

最低限必要な拡張機能

  • Japanese Language Pack for Visual Studio Code(UIの日本語化)
  • C#(拡張機能の名前)
  • C++(拡張機能の名前)
  • NuGet Package Manager(NuGetを使う場合)

vscode02.png
左にある積み木みたいなアイコンが拡張機能。こんな感じで検索して入れる。

設定

VSCodeのデフォルトのエンコーディングはBOM無しUTF-8だが、VSのコンパイラはBOM無しUTF-8で書いたコードに日本語を入れた場合に盛大に文字化けするので、cppやcsharpのファイルは標準でBOM有りUTF-8になるようにしておいた方が良い。(Shift JISでも良いんだろうけど)
「ファイル」→「ユーザー設定」→「設定」で設定画面を開き、右上の書類にくるりと矢印が付いたようなアイコンをクリックすると、VSCodeのユーザー設定ファイル(%AppData%Roaming\Code\User\settings.json)を直接編集できる。
vscode08.png
ここで記述を追加し、下記のようにする。

settings.json
{
    "(すでに設定があれば、その直下に下記を追記)": "",
    "[cpp]": {
        "files.encoding": "utf8bom",
    },
    "[csharp]": {
        "files.encoding": "utf8bom",
    },
    "[plaintext]": {
        "files.encoding": "shiftjis",
    },
}

"[plaintext]"の項はオマケ。

その他、配色テーマ・フォントファミリ・フォントサイズ・デフォルトの折り返し設定等お好みで。

VSCodeの言語共通の下準備

VSCodeは基本、フォルダ単位の管理になるので、適当な作業用フォルダを作っておき、VSCodeで開く。
「ターミナル」→「新しいターミナル」で、右下にターミナル(PowerShell)のペインを出しておく。

WPF(.NET 5)の開発

スケルトン生成

ターミナルにてdotnet new wpfを実行すると、カレントフォルダに、空のウインドウを表示するプロジェクトのファイル群が自動生成される。
(ちなみにwpfの部分はconsoleとかwinformsにも出来る。)

デバッグ

「実行」→「構成の追加」→「.NET Core」で、デバッグ絡みのファイルが自動生成される。カレントフォルダに「.vscode」フォルダが、さらにその中に「launch.json」(デバッグ設定)と「tasks.json」(ビルド等設定)が出来ている。
.NET 5の場合、すでに必要な設定は記述してあるので、いじらなくてもそのままデバッグ出来る状態ではあるが、launch.json内の"OS-COMMENT1"等から始まる行は不要なので削除可。
「F5」キーを押すか、「実行」→「デバッグの開始」で、未保存のファイルが保存されたのち、ビルド→デバッグが実行される。

リリースビルド時にデバッグ情報が入らないようにする

プロジェクトファイル(.csproj)の<PropertyGroup>タグ内に、下記の要素を追加。
<DebugType Condition="'$(Configuration)' == 'Release'">none</DebugType>

発行

ターミナルにて下記コマンドを実行。
dotnet publish -c:Release -r:win10-x86 -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained:false

それぞれのスイッチの意味は

  • -c:Release … リリースビルド
  • -r:win10-x86 … ターゲットをWindows 10 32bitにする(64bitアプリを作る場合は-r:win10-x64にする)
  • -p:PublishReadyToRun=true … 事前コンパイル方式にする、つまり初回から起動が速くなる
  • -p:PublishSingleFile=true … 出力ファイルを1つのexeファイルにまとめる
  • --self-contained:false … ランタイムを含めない

なお、--self-contained:trueにしてさらに-p:IncludeNativeLibrariesForSelfExtract=trueも加えると、ランタイム込みの単一exeが爆誕するが、サイズはえらいことになる。

発行コマンドをタスクに登録

「tasks.json」に下記のような感じで追記。

tasks.json
{
    "version": "2.0.0",
    "tasks": [
        { "(中略、下記追加)": "" },
        {
            "label": "publish(x86)",
            "command": "dotnet",
            "type": "process",
            "args": [
                "publish",
                "-c:Release",
                "-r:win10-x86",
                "-p:PublishReadyToRun=true",
                "-p:PublishSingleFile=true",
                "--self-contained:false",
            ],
            "problemMatcher": "$msCompile"
        },
        {"(追加ここまで)": ""}
    ]
}

「ターミナル」→「タスクの実行」で、上記"label"に設定した「publish(x86)」を選ぶと登録したタスクが実行される。

WPF(.NET Framework 4.7)の開発

大まかな流れは前項の.NET 5と同じだが、4.7で動くようにいろいろいじる必要がある。

スケルトン作成

ターミナルにて dotnet new wpf を実行したのち、プロジェクトファイルを修正。

  • <Project Sdk="Microsoft.NET.Sdk"><Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">に変更
  • <TargetFramework>net5.0-windows</TargetFramework><TargetFramework>net47</TargetFramework>に変更

net47の部分は「TFM」というらしく、一覧表がMS公式のページに載っている。もちろんBuildToolsのインストール時に、該当バージョンのTargeting Packをインストールしておく必要がある。

また、割と新しめの名前空間(System.Net.Httpとか)を使おうとすると「存在しません」とか言われて怒られるので、プロジェクトファイルの<PropertyGroup>タグと同じ階層に下記を追加する。

  <ItemGroup>
    <Reference Include="System.Net.Http"/>
  </ItemGroup>

上記を全部適用して、ついでにリリースビルド時にデバッグ情報が入らないようにする場合、プロジェクトファイルは下記のようになる。

.csproj
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net47</TargetFramework>
    <UseWPF>true</UseWPF>
    <DebugType Condition="'$(Configuration)' == 'Release'">none</DebugType>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System.Net.Http"/>
  </ItemGroup>

</Project>

デバッグ

「実行」→「構成の追加」→「.NET Core」で、「launch.json」は作られるが、「tasks.json」が作られないので、「ターミナル」→「タスクの構成」と進み「テンプレートから tasks.json を生成」「.NET Core」を選択していき、「tasks.json」を生成させる。
「launch.json」がそのままでは動かないので、下記を修正。

  • "type"の値を、"coreclr"から"clr"に変更(2か所あると思う)
  • "program"の値を、"${workspaceFolder}/bin/Debug/net47/(プロジェクト名).exe"に変更

プロジェクト名(.csprojの拡張子の前の部分)が「net47test」の場合、「launch.json」は下記のようになる。

launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Launch (console)",
            "type": "clr",
            "request": "launch",
            "preLaunchTask": "build",
            "program": "${workspaceFolder}/bin/Debug/net47/net47test.exe",
            "args": [],
            "cwd": "${workspaceFolder}",
            "console": "internalConsole",
            "stopAtEntry": false
        },
        {
            "name": ".NET Core Attach",
            "type": "clr",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}

発行

各種最適化オプションが効かないので、発行コマンドはシンプルになる。
dotnet publish -c:Release -r:win10-x86

ネイティブ(C/C++)の開発

スケルトン作成

スケルトンを自動で作ってくれるコマンドは無さそうなので自力で作成する。
プロジェクトファイル(.vcxproj)は下記のような感じ。

cpptest.vcxproj
<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <ProjectConfiguration Include="Debug|Win32">
            <Configuration>Debug</Configuration>
            <Platform>Win32</Platform>
        </ProjectConfiguration>
        <ProjectConfiguration Include="Release|Win32">
            <Configuration>Release</Configuration>
            <Platform>Win32</Platform>
        </ProjectConfiguration>
        <ProjectConfiguration Include="Debug|x64">
            <Configuration>Debug</Configuration>
            <Platform>x64</Platform>
        </ProjectConfiguration>
        <ProjectConfiguration Include="Release|x64">
            <Configuration>Release</Configuration>
            <Platform>x64</Platform>
        </ProjectConfiguration>
    </ItemGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.default.props"/>
    <PropertyGroup>
        <ConfigurationType>Application</ConfigurationType>
        <PlatformToolset>v142</PlatformToolset>
        <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
        <CharacterSet>Unicode</CharacterSet>
        <IntermediateOutputPath>obj\$(Configuration)\$(Platform)\</IntermediateOutputPath>
        <OutDir>bin\$(Configuration)\$(Platform)\</OutDir>
    </PropertyGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/>
    <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
        <ClCompile>
            <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
        </ClCompile>
        <Link>
            <GenerateDebugInformation>false</GenerateDebugInformation>
        </Link>
    </ItemDefinitionGroup>
    <ItemGroup>
        <ClCompile Include="*.cpp"/>
    </ItemGroup>
    <ItemGroup>
        <ClInclude Include="*.h"/>
    </ItemGroup>
    <ItemGroup>
        <ResourceCompile Include="*.rc"/>
    </ItemGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets"/>
</Project>
  • 序盤の<ItemGroup>の部分はVSで使う設定らしいが、これを入れておかないとビルド時に怒られる。
  • 3か所ある<Import>タグはほぼおまじない。かつそれぞれその位置にある必要があるっぽい。
  • <ConfigurationType>Applicationになっているが、これはEXE作成用。DLLを作る場合はDynamicLibrary、静的ライブラリーを作る場合はStaticLibraryにする。
  • <CharacterSet>は、マルチバイトの場合はMultiByteにする。
  • <RuntimeLibrary>は、ランタイムを別にしたい場合はMultiThreadedDLLにする。
  • <ClCompile ~<ClInclude ~の対象は、ワイルドカードが使える。

プロジェクトファイルはもうこれ全体がおまじないだと思って、必要な部分だけ変更するような感じでも差し支え無いと思う。
あとは適当に*.cppとか*.hとか書けばビルド通るはず。

なお、プロジェクトファイルのファイル名を「cpptest.vcxproj」にすると、プロジェクト名は自動的に「cpptest」となり、ビルドして生成される実行ファイルもデフォルトで「cpptest.exe」となる。(もちろんどちらもスクリプト内で変更可能…のはず。)

デバッグ

「実行」→「構成の追加」→「C++(Windows)」→「既定の構成」で「launch.json」が、「ターミナル」→「タスクの構成」→「テンプレートから tasks.json を生成」→「MSBuild」で「tasks.json」が生成される。

「tasks.json」は、"command"の値を"C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/MSBuild/Current/Bin/MSBuild.exe"のようにMSBuild.exeのフルパスで指定する。なおパスの区切りはバックスラッシュ(半角¥)じゃなくて通常のスラッシュでOK。

tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/MSBuild/Current/Bin/MSBuild.exe",
            "args": [
                "/property:GenerateFullPaths=true",
                "/t:build",
                "/consoleloggerparameters:NoSummary"
            ],
            "group": "build",
            "presentation": {
                "reveal": "silent"
            },
            "problemMatcher": "$msCompile"
        }
    ]
}

「launch.json」は"preLaunchTask": "build",を追加するのと、"program"の値を${workspaceFolder}/bin/Debug/Win32/(プロジェクト名).exeのような感じで、デバッグ実行ファイルのパスで指定。
また、"console"の値はコンソールアプリの場合はexternalTerminalのままで良い(デバッグ時に別途コマンドプロンプトが立ち上がるので便利)が、GUIアプリの場合は邪魔なのでinternalConsoleに変更しておく。
プロジェクト名が「cpptest」の場合、「launch.json」は下記のようになる。

launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(Windows) 起動",
            "type": "cppvsdbg",
            "request": "launch",
            "preLaunchTask": "build",
            "program": "${workspaceFolder}/bin/Debug/Win32/cpptest.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "console": "internalConsole"
        }
    ]
}

ビルド

ビルドは「MSBuild.exe」で行う。
ターミナルにて下記コマンドを実行。
& "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe" /p:Configuration=Release /p:Platform=Win32
(ターミナルがPowerShellなので、フルパスのコマンドを実行するには頭に「&」が要る。という理解で合ってる?)

もちろんタスクに登録も可。
というか、先述のデバッグも当然実行前にデバッグビルドしているわけで、「tasks.json」にリリースビルド用の記述を追加すればOK。
一応下記に、リリース用とリビルド用の設定を追加した「tasks.json」を載せておく。

tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/MSBuild/Current/Bin/MSBuild.exe",
            "args": [
                "/property:GenerateFullPaths=true",
                "/t:build",
                "/consoleloggerparameters:NoSummary"
            ],
            "group": "build",
            "presentation": {
                "reveal": "silent"
            },
            "problemMatcher": "$msCompile"
        },
        {
            "label": "release",
            "type": "shell",
            "command": "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/MSBuild/Current/Bin/MSBuild.exe",
            "args": [
                "/property:GenerateFullPaths=true",
                "/t:build",
                "/consoleloggerparameters:NoSummary",
                "/p:Configuration=Release",
                "/p:Platform=Win32"
            ],
            "group": "build",
            "presentation": {
                "reveal": "always"
            },
            "problemMatcher": "$msCompile"
        },
        {
            "label": "rebuild",
            "type": "shell",
            "command": "C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools/MSBuild/Current/Bin/MSBuild.exe",
            "args": [
                "/property:GenerateFullPaths=true",
                "/t:rebuild",
                "/consoleloggerparameters:NoSummary"
            ],
            "group": "build",
            "presentation": {
                "reveal": "always"
            },
            "problemMatcher": "$msCompile"
        }
    ]
}

これで、VSCodeのメニュー「ターミナル」→「ビルド タスクの実行」で、「release」を選択すればリリースビルドが、「rebuild」を選択すれば(デバッグの)リビルドが実行される。

生成物は、(今回のvcxprojの場合)プロジェクトフォルダの「bin\[DebugまたはRelease]\[Win32またはx64]」の中に出来る。

注意点

  • リソーススクリプト(*.rc)は文字コードが「UTF-16 LE」である必要があるのだが、デフォルトではUTF-8なプレーンテキスト扱いになってしまっているので、変更しておく。
    対象の*.rcファイルを開いておいたうえで下部ステータスバーの右の方に「UTF-8」とか書いてある部分をクリックし、「エンコード付きで保存」→「UTF-16 LE」でOK。
    もしくは拡張子rcのファイルをデフォルトでUTF16 LEになるように設定してしまう。別記事を参照されたし。
  • Resource.hを使う場合、Resource.hの1行目にいきなりコードを書くとBOMの関係で動かなくなるので、1行目は空行かコメント行にしておく。

  1. ※歯切れが悪い理由は、BuildToolsのライセンスを見るに「Visual Studio Community、Visual Studio Professional、Visual Studio Enterprise と共に使用する」とあるから。共に使用する、の解釈…何でも無いです。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
17
Help us understand the problem. What are the problem?