[c#] SJISというかCP932とかいう呪い

文字変換

未だに「xxx(※1)はシフトジスでくださいねー」とかいうトチ狂った環境がどのような場所にもある。大抵の社畜が躓くのがあのExcelとのデータやり取りなのだが、何故かあのソフトウェアを皆さん本当に大好きなので困る。中途半端に万能なのが悪いのだが、使用者にも問題(例えばまともにcsv開けない(※2)とか)も多く誰を責めていいものやら。

部下(社畜)を殺しておいて、まるで花火見物で雨に振られたときのように「無駄足だった」か……。面白いのう、お前ら。まあ、せっかくだから死んで行けや

という気分ですよ。阿葉山宗介さんもそりゃマジギレですよ。多くの人間が(主にエクセル対策で)死んでいった。それが文字コード問題。まあ俺から言わせればSJISなんて大したこと無い。EBCDIC(IBMメインフレームとか)の地獄をお前らに味わわせてやりたい。

※1 ここにはExcelとかcsvとかtsvとかお好きなものを脳内で入れてください

※2 データインポートとか誰もやらねえよ!

Windows上でのUTF8 -> CP932変換問題

この令和の時代でも上のような需要があるので文字コード変換からは逃げられないのです。で、説明するのも面倒なので"utf8 sjis 文字化け 波線"とかでググってください。簡単に説明すると、複数の「なんじゃこりゃ」仕様が重なって文字化けするんですね。一部が。世の中のシステムは必ず腐っていくものだけど、なぜかといえば必ず"その場しのぎ"でなんかしちゃうからなんですって。どこかで聞いたんだけど。

変なコードを見た

なんか1文字づつユニコードエスケープ文字になおして比較してたんだけど、これ遅くねえか?と思って調べたら遅かったっていうね。しかし、俺が想定していたコードも最速ではなかった。のだが書いた。

気がついたのだけど、エントリ単体のページはちゃんとコードハイライトが聞いているけど、トップとかカテゴリとかの一覧ページで効いてないのよね。WordPressのJQuery外してる影響っぽいけど、レンダリング速度を優先するのでこれからはコードは"続きを読む"以降に書くことにしました。

続きを読む "[c#] SJISというかCP932とかいう呪い"

Hello DotNet5!

Visual Studio Code縛り

.net5のSDKのインストール、及び単純なコード(エディタで直書き)のビルドに問題は何もなかった。が、VScodeでOmnisharpが古いSDKを見ているようで、ビルドどころか補完すら効かない状態だった。
net5_vscode_failed_load_project.png
VScodeのC#Extensionのreadmeを見たところ、.net5使うにはMSBuildの16.8.0が必要とのこと。ん?MSBuild?仕方がないのでVisual Studio 2019のUpdateを行ったところ、VScodeも.net5のSDKを見に行くようになった。.net5のSDKにincluded MSBuild 16.8.0って書いてあるんだけどなー。"net5.0-windows"などでも検索してみたが、同様な事象で躓いている人間を確認できなかった。やはりCSharperはVisual Studio使いがほとんどなんじゃないじゃろか。

実行時バージョン取得

せっかくなので実行時exeのバージョンを取得したい。PHPだと

phpversion(); //-> 7.2.34
Phalcon\Version::get(); //-> 3.4.5

このように実行時のバージョンが容易く取得できるのだが、.netは昔から何故かめんどくさい。今回は https://github.com/nishy2000/DotNetDetector を参考にして簡易的にバージョンを取得した。.netcore3.1 / 5.0と違う事だけを確認したかったので下記のように書いたが、もっと細かく取得したい人はこのパッケージをNugetでゲットするかリポジトリのSourceを確認してください。

using System;
using System.Reflection;
using System.Runtime.Versioning;

namespace HelloDotNet5
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Console.WriteLine(DotNetVersionOnThisProgram.Get());
        }
    }

    // <summary>
    /// via) NishySoftware.DotNetDetector https://github.com/nishy2000/DotNetDetector
    /// </summary>
    public static class DotNetVersionOnThisProgram
    {
        public static string Get()
        {
            return ((TargetFrameworkAttribute)Assembly.GetEntryAssembly().GetCustomAttribute(typeof(TargetFrameworkAttribute))).FrameworkName;
        }
    }
}
Hello World!
.NETCoreApp,Version=v5.0

追記

そんなわけで現在作成中の画面キャプチャツールも.net5に移行した。プロジェクトファイルを

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <ApplicationIcon>resources\camera_icon.ico</ApplicationIcon>
  </PropertyGroup>
  <ItemGroup>
    <Content Include="log\.gitkeep">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <EmbeddedResource Include="resources\camera_icon.ico" LogicalName="camera_icon.ico" />
  </ItemGroup>
</Project>

これを

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net5.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <ApplicationIcon>resources\camera_icon.ico</ApplicationIcon>
  </PropertyGroup>
  <ItemGroup>
    <Content Include="log\.gitkeep">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <EmbeddedResource Include="resources\camera_icon.ico" LogicalName="camera_icon.ico" />
  </ItemGroup>
</Project>

こう変えてから、launch.jsonのnetcoreapp3.1を

{
   // Use IntelliSense to find out which attributes exist for C# debugging
   // Use hover for the description of the existing attributes
   // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
   "version": "0.2.0",
   "configurations": [
        {
            "name": ".NET Core Launch (console)",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            // If you have changed target frameworks, make sure to update the program path.
            "program": "${workspaceFolder}/bin/Debug/net5.0-windows/Butler.exe",
            "args": [],
            "cwd": "${workspaceFolder}/bin/Debug/net5.0-windows/",
            // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
            "console": "integratedTerminal",
            "stopAtEntry": false,
            "requireExactSource": false
        },
        {
            "name": ".NET Core Attach",
            "type": "coreclr",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}

net5.0-windowsに変更。そしてdotnet cleanをしてからbuildしなおした。

dotnet5_messagebox_show_test

適当に実行して5.0を確認。

[Visual Studio Code][c#] 埋め込みリソース

アイコンは外部ファイル読み込みではなく埋め込みたい

Visual Studio 2019ではなく、Visual Studio Codeで書くという縛りを設けているのだが、早速ハマったことがあり解決したのでログとして残しておく。

宇宙最強のIDEであるVisual Studio様で開発していると、GUIパーツの埋め込みリソース周りはほぼノーコードで実装できてしまう。自動的に.resx, .resourcesなどの生成とビルド時オプションの指定?なのか、それすらわからんというか意識したこともない。今回はexeのアイコン画像の指定(全く苦労しなかった)と、タスクバーアイコンの画像指定(MSのexampleを見つけられなかった && 情報が古いのか.net coreと.net frameworkでの差異なのかなんなのか && 嘘800 で時間使った)について。

vscode_image

.exe(とWindowsFormsタイトルのアイコン)

.exe(とWindowsFormsタイトルのアイコン)のアイコン指定は簡単だ。今回はプロジェクトディレクトリに"resources"というディレクトリを作成し、そこに"camera_icon.ico"というアイコン画像を配置している。埋め込みではなく単純にビルド時に出力したいと言うなら、画像の.gitkeepのように書けば出力される。

プロジェクトファイルに下記を追加する。

  <PropertyGroup>
    <ApplicationIcon>resources\camera_icon.ico</ApplicationIcon>
  </PropertyGroup>

これだけである。

exe_icon

タスクバーアイコン

検索の仕方が悪いのか、そもそもc#使いはVisual Studioを使わない理由が無いからなのか。調べるのに時間がかかった。上と同じ画像ファイルをタスクバーアイコンに設定する。

プロジェクトファイルに下記を追加する。

  <ItemGroup>
    <EmbeddedResource Include="resources\camera_icon.ico" LogicalName="camera_icon.ico" />
  </ItemGroup>

読み込みはこう。

        private void InitializeComponent()
        {
            ...

            // icon
            icon = new NotifyIcon();
            icon.Visible = true;
            icon.Text = Utility.Concat(settings.ApplicationTitle, " ", settings.ApplicationVersion);
            // ここ!!!
            var asm = Assembly.GetEntryAssembly();
            using var stream = asm.GetManifestResourceStream("camera_icon.ico");
            icon.Icon = new Icon(stream);

            ...
        }

System.IO.Streamで返ってくるので、埋め込みまくって何にでも使えるんじゃないじゃろか。

taskbar_icon

おわり