nuget-icon

.NET FrameworkでDLLファイル(国際化対応リソースを含む)をexeにマージする


前のバージョンまで、「アタッシェケース」ではインストールを行うと、以下のプログラムフォルダーには、本体と並んで、DLLファイルがいくつか並んでいました。

AttacheCase.exe
AtcSetup.exe
Microsoft.WindowsAPICodePack.dll
Microsoft.WindowsAPICodePack.Shell.dll
ja-JP\AttacheCase.resources.dll

このファイル構成は、あくまで開発者側の都合であって、ユーザーにとっては良く分からないでしょう。

実行ファイルを別の場所へ移動させて使いたいとき、このDLLファイルも同時に移動させなくてはいけないのか?と迷ったり、煩わしいと思ったりするかもしれません。

実際、付属DLLファイルによっては、実行ファイルのあるフォルダーに存在しないと、正常に動かないものもあり、ユーザーにとっては、ツールのポータビリティが低く、やや使いづらいのではないかと考えました。

一つの実行ファイルに、すべての付属ファイルをマージする

というわけで、章題。これを目標にしてみました。そこで考えられる方策をいつくかご紹介したいと思います。

ILMerge(ILRepack)

もっとも手軽で定番なのは、「ILMerge」でしょうか。

Microsoft謹製のツールです。リンク先にあるツールをダウンロードしてインストールすると、使えるようになります。いろいろなオプションがあって、それに従って設定すれば、指定の実行ファイルにDLLファイルをマージできるようになります。

コマンドの例としては、以下のような感じです。

ところが、これですと、言語ファイルである、ja-JP\AttacheCase.resources.dllが残ってしまいます。どうやら、国際化対応リソースのDLLは「サテライトアセンブリ」といって、マージのときに除外されるみたいです。

ちなみに「ILMerge」は、Microsoftのプロプライエタリなツールですが、これをオープンソースにして、機能を拡張したものも存在します。「ILRepack」です。

これも、ILMergeと基本的に使い方は同じです。たとえば、以下のようにします。

ただ、これも、肝心の言語ファイルがマージされません。

NuGet

では、より簡単で、すべてのDLLファイルを実行ファイル(exe)にマージできないか調べて見ると、Visual Studio 2012以降では標準で付属しているツールの「NuGet」で、あるパッケージ群をインストールすれば可能になるようです。

まず、NuGetとは何か? マイクロソフト公式のウェブサイトにも説明はありますが、以下のウィキペディアの説明の方が簡潔ですので、そちらを参照なさってください。

NuGet
https://ja.m.wikipedia.org/wiki/NuGet

NuGetは、基本的にVS全体にインストールするというよりも、プロジェクト毎にインストールするようになっています。ですので、以下の画面では、「アタッシェケース」のソリューション(その中に各プロジェクト)が開いている状態で、NuGetパッケージ管理画面を開こうとしています。

 

Fody

次に「参照」から「fody」を検索して、Fodyを見つけたら、NuGetからパッケージを必要とするプロジェクトにチェックを入れ、そこへ「インストール」します。

Fodyとは以下のサイトにも説明がある通り、「Extensible tool for weaving .net assemblies(.NET Frameworkにアセンブリを組み込むための拡張ツール)」です。

Fody
https://github.com/Fody/Fody/

ただ、これだけではまだ不完全です。さらに、次にあるFodyのアドインをインストールする必要があります。

Fody.Costura

再びNuGetで「Fody Costura」を検索してインストールします。

Costuraとは、プロジェクトで使うリソースをアプリケーション本体に埋め込むためのツールです。

Costura is an add-in for Fody
https://github.com/Fody/Costura/

しかし、インストールしただけでは正常に動作しません。その後に、設定ファイルを所定の場所に置かなくてはなりません。ファイル名は以下の通り、決まっています。

FodyWeavers.xml

というファイルを作り、プロジェクトファイルがあるディレクトリに配置しなくてはなりません。

そのXMLファイルの中身ですが、最低限の設定であれば、以下の内容だけでO.K.です。ちなみに、公式GitHubのウェブサイトを見れば、埋め込みを除外するDLLを指定することができたり、様々なオプションが用意されているので、カスタマイズする場合はそちらを参考になさってください。なお、XMLファイルの文字エンコーディングはUTF-8なのでご注意を。

これにより、
Microsoft.WindowsAPICodePack.dll
Microsoft.WindowsAPICodePack.Shell.dll
の二つが「AttacheCase.exe」埋め込まれて、以下のようにファイルが出力されるかと思います。

 

Resource.Embedder

しかし、これでも、まだ国際化対応リソース(言語ファイル)DLL、
ja-JP\AttacheCase.resources.dll が統合されておりません。

そこで、もう一つNuGetパッケージをインストールします。「Resource.Embedder」です。

Resource.Embedder
https://github.com/MarcStan/Resource.Embedder

インストールは、以下の通りです。

これにより、ビルドを行うと、すべてのDLLリソースが「AttacheCase.exe」に埋め込まれて、以下のように単一で出力されます。

 

ただし、.NET Framework 4.0 だと古いバージョンを使う

Fody パッケージ自体は、.NET Frameworkのバージョン依存関係はありませんが、Fodyのプラグインである Costura の最新版の方には、

.NET Framework 4.6
Fody (>= 3.2.6)

といった依存関係があります。

ですので、アタッシェケースは、一応WindowsXP上でも動作するように、.NET Frameworkは、“4.0” でビルドするという縛りを設けているため

Fody ver.2.5.0
Costura.Fody ver.1.6.2

と、あえて古いバージョンのパッケージをそれぞれ使っています。

以上です。

「@nifty光」ロゴ

光コラボレーションの勧誘電話からの契約でミスった話


先だって自宅直通電話に株式会社CLという会社から、「いまご加入の@niftyから乗り換えれば、通信量がお安くなります。」という営業電話がかかってきました。

ただ、僕はパソコン通信時代からNifty Serveを使っていたということもあって、メアドを変えたくないということと、だいぶ前に電力自由化されたことから@niftyでも「@niftyでんき」が始まり、その勧誘もあって、入会していたという経緯があります。ちょっとその段階では@niftyからの乗り換えたくはしたくありませんでした。

しかし、その営業電話では「いま現在ご加入の@niftyを変更することなく、メールアドレスも変わらず、毎月の通信料が安くなります」と勧めてくる。それじゃあ、変えてみようかな、と軽い気持ちで切り替えました。「ただ、後ほど届く資料を必ずご覧になってください」と、「それで契約内容誤解していたなどあれば初期契約解除(クーリングオフ)できます」と、強く念を押されたので「ん?」と思いつつも、その資料が届くのを待ちました。

けっきょく4,5日して届いた資料に細かく目を通して見たら、驚きました。まず、自分が「光コラボレーション(光コラボ)」が始まっているのを知らなかったこと。以下が公式、というか、回線業者(NTT)による光コラボ提供会社の紹介一覧です。かなり多くの企業がやっていることが分かります。

NTT東日本
NTT西日本(※西日本の方が若干詳しく載っています)

光コラボとは、一言で説明してしまえば、電力の自由化ならぬ、光回線の自由化みたいなものです。今までは、以下の図の左にあるとおり、回線事業者(NTT)とインターネット回線の使用を契約し、その上でインターネットプロバイダーをどこにするか、それぞれ決めることになっていました。なので、僕の場合は、「NTT東日本」+「@nify」ということになります。

上の右側の図は、光コラボの図です。僕はてっきり、そのときは左側の状態になっているのかと思っていました。

しかしよく調べてみると、実は何年か前に@niftyから直接、「@nifty光にしてみませんか?」という勧誘があり、実はそれが光コラボということを知らずに契約してしまっていました。

そのため、現状は以下右の図のようになっているということです。

そこへ新たな光コラボ事業者からの営業電話勧誘があり、光コラボのことなんて全然知らなかったこともあり、その状態で、勢いから、契約してしまったというわけです。「毎月たったの950円になります!」と言われれば、安い!と思うわけですよ。これまで毎月4,000円近く払っていたのですから。

しかし、届いた書類を見ると、契約サービス名が「CL接続」とある。この光コラボ事業者の株式会社CLの「サービス」のページを見ると、その他にも「CLひかり」とある。「ひかり」でもない「接続?」そこで「んんんっ?」となる。そしてもう一度、「CL接続」サービスの説明をよく見ると、、、

な、なんだってー!! これじゃあ、光コラボどころかプロバイダーを変更するだけじゃないですか。

とはいえ、たしかに営業担当の人が、「@niftyのサービスはそのままお使いいただけます」って言っていたのはウソじゃない。@niftyを解約せずに、かつプロバイダーをもう一個別のものを加入させようとしたのだから。つまり、意味の無いプロバイダーの追加契約。

しかも、僕はすでに「@nifty光」サービス(光コラボ)へ切り替えてあるので、プロバイダーを解約すると、違約金が既存の@niftyの方で発生します。

いわゆる電力自由化のように、電力供給事業者の契約を破棄しても、自動的に東京電力(既存の電力会社)に切り替わるということもなく、光コラボでは、前のサービスの契約を破棄する前提で新たに契約してね、ということらしい。

おいおい・・・そもそも最初に「@niftyのメアドを変えたくないので」と伝えたはずなんですけども・・・

ざわ、ざわ・・・よくよく株式会社CLのウェブサイトを見てみると、仮にもプロバイダー事業者なのに、SSL接続に対応していないっていうのも微妙に不安を煽ります。

これはヤバい・・・さっそく解約しなくては・・・

実はこの契約では月々の料金が格安になり、最大二ヶ月の利用料金無料特典まで付いている代わりに、契約期間中での解約違約金の高さがエグい。

37ヶ月(約3年)縛りの、
契約月から12ヶ月以内の解約: 22,500円
契約月から24ヶ月以内の解約: 15,000円
契約月から36ヶ月以内の解約: 7,500円

これについては、電話での口頭で説明を受けていたので、三年縛りでも毎月安くなるなら、と納得はしていましたが、契約内容を改めて見たら、内容は僕の想定外になっているし、これは余計にマズいぞとなって焦りました。

とはいえ、契約には、初期契約解除(クーリングオフ)の条項も入っていて、資料到着後8日間以内(本書記載の「ご契約日」から11日以内)に違約金無しの解約ができると書いてあったので、さっそくこの会社のサポート窓口に電話。

サポートにはなかなか繋がらなくて「混んでいますのでもうしばらく経ってからお掛け直しください」とメッセージが流れ、何度か先方から遮断されました。まさか・・・サポートは初めから繋がらなくて、契約解除できないんじゃないか・・・詐欺か・・・そうドキドキしていたとき、何度目かの電話で、なんとかサポートスタッフの方に繋がりました。

意外だったのは、繋がってすぐに「お客さま番号」を聞かれ、「どうして解約されたのか、よろしければ理由を」との質問のみで、あっさり解約することができました。これはかなり良心的でした。

今回はたまたま、まともな事業者だったので、解約できましたが、ネットで調べて見ると、あこぎな事業者もけっこういるそうですから、契約の際には十分気を付けましょう。電話での勧誘による契約には特に注意が必要です。けっこう互いの合意内容に齟齬があったりします。

光コラボレーション自体、わるいものではなくて、きちんと光コラボ事業者を選べば、かなりお得になります。docomoや、au、SoftBankなども光コラボ事業をやっていて、ケータイがどこかのキャリアで持っているのなら、さらにお安くなったりと、メリットも十分ありそうです。

まあ、勧誘を受ける前に、自分で光コラボ事業者を検討し、納得して選び、先に申し込むのがベターだと思いました。なお、「光コラボ」と検索すれば、山ほど紹介ページが出てくると思うので、そちらを参考にしながら自分にピッタリのプランを選べば良いでしょう。

iTunes Connect icon

[Electron][MacOS]Your application still accesses the following location(s):でリジェクト



追記:2017/06/18に大幅修正を加えました。

Electronで絶賛、開発中の「OutlineText」ですが、バージョンアップ版を審査に提出したところ、タイトルのようなメッセージとともにリジェクトが。

正確には、

2. 4 Performance: Hardware Compatibility (macOS)
Guideline 2.4.5(i) – Performance

Your application still accesses the following location(s):

‘/Applications/OutlineText.app/Contents/Resources/app/locales/en.json.tmp’

The majority of developers encountering this issue are opening files in Read/Write mode instead of Read-Only mode, in which case it should be changed to Read-Only.

これを初めてもらったとき、「そうか、たしかに自分で自分のappにアクセスしてしまったっらダメだな」と思って、OutlineText.app内のディレクトリにはロックをかけるような仕組みを作り直して、審査に再提出。

ところが、またリジェクト。理由は、判で押したように上記のメッセージで返ってきました。いろいろ試行錯誤した結果、4回連続でリジェクトを頂戴するという羽目に(審査チームももう少しヒントをくれても良いのに・・・)。

そこまでやって、ふと思い当たったのは、ひょっとすると、Entitlementsの指定が誤っているのではないか?ということで、先の記事中では、Electron でビルドするときは、シェルスクリプトでやっていて、以下のように設定しておりました。

Electornは、単体アプリではなくヘルパーアプリも一緒に動くので、codesignは本体同様にすべてに行ってあげないといけません。でないと、審査以前にアプリをアップロードするときに、アップローダーに怒られます。

この辺りは、「Electron アプリを Mac App Store に登録する手順」が参考になるでしょう。

ここで、問題になっていたのは、parent.plist 9行目のEntitlementsに、com.apple.security.files.user-selected.read-write が指定されていること。

このせいでいくらい対策を講じても、アクセスは可能になっていたというわけかと納得。そこで、以下のようにcom.apple.security.files.user-selected.read-onlyだけの記述にして審査へ再提出したら、ようやく審査に通りました。

ところが、いったんは審査を通ったものの、今度は保存ダイアログボックスが出ないというバグが発生・・・(これは審査チームも見逃したようです)。

考えてもみれば、そりゃそうですよね。read-onlyなのですから、保存ダイアログが出ないのは当たり前です。

で、結局は以下のように、指定を元に戻して再提出しました。具体的には、Entitlementsの指定で、read-onlyを、read-writeに書き換えています。

これでまた一から振り出しに戻り、先のテンプレ文とリジェクトをいただくことに。。。

そこで業を煮やした僕は、審査チームに「アピール」を送信してみることにしました。

Writes in the location are restricted and be open for read-only already. Please tell me the detailed occurrence procedure.

画像も添付しました。

read-only

ちゃんと「読み取り専用」として開いているぞ、と。

すると、二日後に以下のようなメッセージが届きました。

Hello,

Thank you for your inquiry. To clarify, the app is opening files in Read/Write mode instead of Read-Only mode, in which case it should be changed to Read-Only.
The file being accessed is:
‘/Applications/OutlineText.app/Contents/Resources/app/locales/en.json.tmp’

これを読んで、ふと、思い当たる節がありました。ひょっとして、ファイルの読み書きのところで、意図せずread-writeで読み込んでいる箇所があるのではないか?と。

実際、ありました。

保存するとき(ファイルに書き込むとき)、前に保存したディレクトリが存在しているかどうかチェックをして、なければデフォルトは「書類」フォルダを指定するというコードにしていました。参考にしたのは、「Check synchronously if file/directory exists in Node.js – Stack Overflow」です。

ひょっとすると、fs.lstatSyncが、read-writeでアクセスしに行っているのではないか?と思い(Node.jsの公式ページでは確認できなかったのですが)、Stack Overflowのページをもう一度確認してみると、回答が大幅に書き換えられていて、以下が推奨となっていました。

そこで、この部分を上記で書き直して、再度Appleに提出。程なくして、「Ready for sale」の返答があり、ようやくバージョンアップ版がApp Storeに並ぶことになりました。

やれやれ・・・一件落着です。

ちなみに、Appleの審査チームのアピールですが、質問形式で送ると、即座にテンプレで「サポートか、フォーラムに投げてね」的な回答が返ってきますが、「再現の手順」を教えてくれ、といった具体的な質問に対しては、ヒントになるくらいの回答が得られました。アピールの仕方にも、少し工夫が必要ですね。

 

Electron-icon

Electronでメニューへ動的にチェックを入れる



ElectronでMacOSアプリ作っています。

当サイトで「Open source & Free software」などと、標榜しておきながら、MacOSの方で有料アプリとして作って公開しています。(→気になる方はコチラからどうぞ)。

言い訳がましいですが、Appleのディベロッパーアカウントは1万円/年ほどかかっており、フリーで公開中のWindowsアプリのコードサイニング証明書更新など6万円/年と、すでに出銭の方が多いのではないかという状況でして。どうか忖度、願います。

そんなことはさておき、表題の件。

意外とサンプルが見つからなかったんですよね。

アプリ起動時のメニュー生成は、サンプルもいくつかみつかり、比較的簡単です。

JSON形式でテンプレートを作っておいて、それをアプリケーションメニューとしてセットするだけです。

ただ、これですと、セットした後にメニュー内容を変更するにはどうすれば良いのしょうか? たとえば、以下のような場合です。

sample-menu

チェックボックスの変更です。たとえば、上記の例でいえば、エンコーディングの種類の変更を行いたい(その選択したメニューにチェックを入れ直したい)場合です。

これはもう構築したメニュー全体から、変更したい該当のメニューを探し出すしかありません。そこで、前述のソースコードの7行目に注目してほしいのですが、メニューアイテムの属性値に「id」を追加しています。これを頼りに検索する関数をつくります。

これにより、変数encodingMenuには、「エンコーディング」以下のサブメニューオブジェクトが入ります。

これも関数にまとめてしまいましょう。

ここで注意したいのが、6行目のループで使われているsubmenu.itemsです。ここ、submenuだけにしがちなので、ご注意ください。

まとめるとこうなります。

本来ならよくあるように、’id’だけでズバッと該当のメニューを指定して変更できるのがベターなのですが、現状ではその方法がないので、メニュー内を探索して特定するしかなさそうですね。

 

「アタッシェケース#3」を正式版としました。


β版リリース時にもブログ記事を書きましたが、バグ報告もなくなり、自身で使っていても、目立った不具合がなくなってきたため、正式版としました。それでも細かいバグはまだまだありそうですので、もし何かあれば報告をいただけるとうれしいです。

アタッシェケース#3アイコンhttps://hibara.org/software/attachecase/

前述の記事でも書きましたが、Ver.2からの変更点のおさらい。

  • ファイルフォーマットの変更(Ver.3独自)
  • パスワードの扱いについての改良(RFC2898によるキー派生)
  • 暗号化、復号の処理速度の向上
  • Windows 10(タッチ操作など)に対応
  • パスワード付きZIPファイルの作成機能(おまけ)

ver.2は、2004年の開発開始からほとんど修正されることのなかったファイルフォーマットに手を入れました。冗長な部分を削除し、やや弱かったパスワード部分の扱いを改良、メモリで扱う部分を大きくし、また高速化(並列処理)に適したフォーマットにしました。

ですので、Ver.3で暗号化されたファイルは、Ver.2では復号できませんので、あらかじめご注意ください。ただし、Ver.2ファイルはVer.3では開けます。つまり上位互換です。

パスワード付きZIPファイルへの対応はおまけです(笑)。知人からの要望を受けて、入れてみました。邪魔で不評なら将来的に削除、好評なら復号処理も入れようかと思います。

技術的な変更点は、

  • .NET Frameworkでの開発
  • コードサイニング証明書の付加

今までC++Builderで開発を行ってきましたが、毎年のバージョンアップ費用がもはや個人ユースとして耐えられなくなってきたのと、無料で使える、Microsoftの「Microsoft Visual Studio Express 2015 for Windows Desktop」にした方が、より多くの人にとって、オープンソースからのプルリクエストや、フォークがしやすいのではないかと思い、乗り換えてみました。

また、暗号化ツールという性質上、セキュリティ面での使用を躊躇してしまうのを少しでも軽減しようと、コードサイニング証明書を付加してみました。法人ではなく僕個人のもので、けっこうなお値段でしたが、少しでも安心して使っていただけるようにと自腹で負担しました(泣)。

より多くの人に使っていただけるのが、開発者としては望外の喜びです。

s