HOME REPORT C++BUILDER2009 から VISUALSTUDIO に移行した話

C++Builder2009 から VisualStudio に移行した話

概要
以前から移行しようと思っていましたが、いい加減限界を感じて VisualStudio に移行した話。
レポート日
2019.8.18

1.はじめに

かなり時代遅れな記事です。C++Builder2009 をずっと使い続けていましたが、もういい加減限界を感じました。

1.ヘルプが WinHelp でインストールするのが難しい

できないことはないらしいですが、セキュリティ的な問題もあるそうでいたちごっこの状態が続いていました。

2.Windows の新しい仕様に一々対応するのが面倒になった

C++Builder の最新版を導入すれば済む話かもしれませんが、古いプロジェクトを新しいプロジェクトに上げるときによく問題が生じます。それにも少し疲れました。

3.ネットに情報が少なくなった

本当に少なくなりました。これはデスクトップからモバイルに主戦場が移ったからというのもあるでしょう。ここまで移行が遅れたのも、ある意味モバイルに主戦場が移ったからだと思います。

milligram image viewer は仕事でも多用していたので、どうしても保守する必要がありました。移行するとして新しいコンパイラを何にするか検討しなくてはなりません。Visual C++ は UI を作るのにコストがかかります。CLI ならそうでもなさそうですが、.NET をどうせ使うのなら C# ということにしました。

2.C# って

C# は現代的な言語だと思います。型が厳密で、C のユルさみたいなものは全く感じません。その分、バグが生じにくい環境、なのでしょう。言語それ自体の仕様としてはとてもいいものだと感じます。

Visual C# は「マーシャル」という概念をシステムでもっています。マーシャルとは、他の言語やプラットフォームと互換性を保つ様式や手法のことです。マーシャリングすることにより、C とのオブジェクトファイルレベルでの互換性を保ったりできるようです。このマーシャルを使いこなさないと、Win32 の環境で作ったアプリやちょっとハードウェア寄りなことをやるのはかなり厳しいと思います。概念としての C# を実装するためのマーシャリングといった感じでしょうか。

しかし、実装にはかなり疑問も感じます。C#.NET で少し凝ったことをやろうと思うと、P/INVOKE を使いまくらなければなりません。また、Win32 の古い DLL を使うとなると、unsafe は必須ではないにしろそのほうが使いやすいと感じます。

また、自分で開放しなきゃいけないものと自分で開放しなくてもいいものを覚える必要があります。今回 milligram image viewer を移行するにあたって躓いたのは、

「マルチイメージを保持する画像のインスタンスがストリームから作られた場合にはストリームを破棄すると最初のイメージ以外にアクセスすると例外が発生する」

です。このストリームの元データがアーカイブファイルの中であった場合では、とか、色々細かく条件が分岐して結構ややこしいことになります。「自分で開放しなくてはいけないものであるが、すぐに開放してはいけなかった」ケース等です。C# のライブラリの中にはそういったものが存在します。

私がよくわかっていないだけかもしれませんが、C# がガーベージコレクションのためにメモリを管理しているのですが、それ以外のメモリにアクセスする場合には基本的にはコピーしてから、ということになりますし、それが安全です。小さなファイルならそれでもいいでしょうが、動画ファイルを編集したりするにはかなりの工夫が必要になると思います。

C++Builder から、C# に移行するためには P/INVOKE とマーシャリング、その二つがまず最初に立ちはだかる大きな壁だと感じます。それ以外の部分では快適か?と聞かれると、意外かもしれませんが .NET ライブラリは VCL よりもほんの少しだけ痒いところに手が届かない印象を受けます。もちろん便利な部分もあるのですが、私が触った範囲では VCL のほうが便利な印象を受けました。コントロールの挙動も少し違ったりします。

3.C++Bulder から VisualC# に移行してみて実際どうだったか?

私が考える最もスムーズに C++Builder から C# 環境に移行する手段は

  1. unsafe を嫌がらない
  2. P/INVOKE を使いまくる
  3. マーシャリングを覚える
  4. VCL を STL に置き換える

です。特に巨大なファイルをマッピングしてポインタを使ってファイルの中をウロウロするようなプログラムは Unsafe を使わないと結構嫌な感じになるんじゃないかと思います。

C# のよい点も多々ありました。

  1. 情報が多い
  2. C# は近代的でかなり「楽」な言語
  3. エディターが高性能
  4. デバッガが良い
  5. 多様なアドオン
  6. 無料

です。3 以降は VisualStudio が、ということになりますが。

しかし C# の問題点も多々あります。特に出力されるファイルが

  1. ソースが丸見え
  2. DLL が別ファイル
  3. 起動がやたら遅い
  4. 何故かカーソルが 2ビットになる

というのがあります。1 は難読化ツールというのがあります。milligram に関して言えば、別段変わったことをしているわけでもなく、ライセンス的ななにかがあるわけでもなく、ソースが見られてしまうのは特に問題はないのですが、汚いソースを見られて気持ちいいものではないと感じます。

2 はこれもまた DLL を同梱化するツールがあります。ところが 1 と 2 を併用するやり方がわかりませんでした。難読化するとできないのかもしれません。かなり試行錯誤してみましたが自分の環境、難読化+多言語&ライブラリファイルの同梱というのはできませんでした。

3 の起動が遅いのもこういったビューワーアプリでは大問題です。起動終了を繰り返しているうちは良いですが、スリープから戻ったらまた起動が遅い、というのがあって、一つだけ常駐化させれば解決しますが、なんともなレガシーな解決策です。

4.これもよくわかりませんが、カーソルファイルでアルファ付きのものが使えませんでした。別ファイルにすればいけるのかもしれませんが更にファイル数が増えることになります。

中間言語で JIT コンパイルで実行ファイルを作って実行、という .NET の仕様はセキュリティ的にも他のいろいろな意味で先進的であるのですが、その分ソースが丸見えで起動が遅い、となってしまうのだなと。SSD + i7-9700K という 2019年では割といいと思われる環境ですが、あまり使いたくないと感じました。

ほかに感じた大きな問題点はリソースリークの追跡です。ハンドルの開放とかその手のアンマネージドなものがリークして使用メモリが増えているのか、ガーベージコレクション的なもののタイミングの話で使用メモリが増えているのか非常に分かりにくいです。

あとはポインタが全く使えないというのもソースを煩雑にする印象があります。参照としてメンバを持っておければと感じるシチュエーションが何度かありました。アプリケーション全体の設計なんでしょうけども。

4.結局 Visual C++ に

C# にプログラムを移行してみましたが、上記のような問題を感じてもう一度 C++ に戻すことにしました。C++ といっても現在の環境では、

  1. WindowsSDK(Win32)
  2. MFC + Win32
  3. CLI(.NET)
  4. CX + WinRT

という選択肢が選べるのですが、はっきり言って訳が分かりませんね。.NET なので避けることにします。2 は以前有料でしたが、今なら無料でもありますが、DLL が色々増えそうです。今現在ならば、4 の C++/CX + WinRT で開発するべきですが、結構制限が多いらしく、Susie の DLL の利用ができるかどうかにかなり不安がありました。

しかし今回移行する大きな理由の一つに DPIAware への対応があります。DPIAware は C++/CX + WinRT でやってくれ的な雰囲気を Microsoft は出しているそうで、なんだかとてもややこしそうです。Win32 をいい加減やめてほしいというマイクロソフトの思惑とセキュリティの面でアクセスとか結構めんどくさくする、みたいなのの板挟みになっている感じですね。

そもそも milligram image viewer はさほど UI が凝っているわけでもなく、C++Builder で製作中ですら、C++Builder で作ることに意味があるのかな?と思っていました。また、Susie の DLL の利用をする以上は基本的には 32bit で作る必要があり、今回は 1 の WindowsSDK で行くことにしました。

ここで元になるソースコードを C++Builder のものを使わずに C# のものを使うことにしました。というのも、参照渡しのほうがいろいろなものが楽だからです。移行は C++ → C# の時よりも圧倒的に楽で、コンポーネントがない部分をメッセージを呼び出すクラスに置き換える程度の作業で済みました。また、C++17 の機能をかなり使いました。C++17 は文字列のエンコード周辺は良くないですが、Microsoft が上手に拡張してくれています。WindowsSDK + C++17 というのはとても便利ですね。WindowsSDK で書いたことによってフォームのサイズ変更の挙動などに無駄がなくなったように感じます。

一つだけうまく行かなかった点が、多言語化部分です。リソースを Netural(Default) で作ってそちらには英語のテキスト、それ以外に日本語リソースを追加したんですが、常に日本語で表示されてしまいました。リソースを Neutral に変更すると今度は常に Neutral に設定した文字列で表示されてしまいます。プロジェクトのデフォルトの言語設定を変更しても挙動には変化がなかったです。仕方がないので使用中の言語を取得して自前で切り替えるようにしています。選択肢として DLL 別添というのもありますが、それをやるのならテキストファイルを読み込む仕様にしたいです。そっちのほうがユーザーが改変できて良さそうだなと感じますが、工数が増えるので今回は見送りにしました。

UWP も制限がゆるくなってきたそうですし、他のアプリは UWP + WinRT 環境に頃合いを見て移行しようと思っています。

以上です。

※)2019.9.6 に C++ での開発の選択肢の部分を少し直しました。いまだによくわかっていないです。WPF というのは XML のレンダー + UI の一種のようです。