[C#] MSDN/.NETのFileStreamコンストラクタの説明の和訳に誤り

MSDNには.NETのクラスの日本語マニュアルがあるけど、それぞれのページの冒頭に「この記事は機械翻訳されたものです。 記事の文章にポインターを重ねると、原文のテキストが表示されます。」という記述がある。これから推察するに、訳文の正当性チェックはさほど細かく行われていないのかもしれない。

先日関数の引数を調べていて、和訳された記述が原文とは違った意味になっている箇所があった。最初日本語の説明を読んでいたのだけど、おかしいなと思って原文を見直したところ気付いたのだけど、こうしてブログに書いておくと誰かの役に立つかもしれないので覚え書き。

FileStream コンストラクター (IntPtr, FileAccess, Boolean, Int32) (System.IO)
http://msdn.microsoft.com/ja-jp/library/w4z40ebc(v=vs.110).aspx

bufferSize
Type: System.Int32
A positive Int32 value greater than 0 indicating the buffer size. For bufferSize values between one and eight, the actual buffer size is set to eight bytes.

bufferSize
型 : System.Int32
バッファー サイズを示す 0 より大きな正の Int32 値。 bufferSize 値には 1 から 8 を設定します。実際のバッファー サイズは 8 バイトに設定されます。 1から8の間の値をbufferSizeに指定すると、実際のバッファサイズは8バイトに設定されます。(つまり、適用されるbufferSizeの最小値は8となる)

[C#] 画像を矩形で切り取る

Graphicsオブジェクトを使うと、画像の切り取りも比較的簡単に行うことができる。

切り取り後の画像サイズのビットマップを作成し、矩形領域を指定して元画像をDrawImageするだけ。

[C#] INIファイルを読み書きする

Windowsにはアプリの設定を保存する方法がいくつかある。古い順に挙げるとINIファイル、レジストリ、XMLファイルなど。中でもINIファイルは、取り扱いが楽なのでいまだに使われている現場もある。エディタで開いて自由に設定を変更できるし、アンインストール時にレジストリにゴミを残す心配も無い。

C#でINIファイルを読み書きするには、WindowsのDLLをインポートすることで、Windows APIとして提供されているINIファイルのアクセス関数を使うのが手っ取り早い。

参考までに自作クラスを紹介しておく。

[C#] 画像ファイルからExif情報を削除するには

前回のエントリの内容を試行錯誤している間に見つけた方法。ちょっと裏技っぽいけど。

「Exif情報付き画像ファイルから作成したBitmapオブジェクトを複製したものを画像ファイルに保存すると、保存された画像ファイルにはExif情報が付加されない」。

保存した画像ファイルにはExif情報は付加されていなかった。想像だけど、元画像ファイルの情報は複製したBitmapオブジェクトに引き継がれないので、元画像ファイルから保存先ファイルにExif情報が転記されないのだと思う。だけど、こういったBitmapクラスの挙動はMSDNなどドキュメントに記載されていないので、将来.NETがバージョンアップしたときには振る舞いが変わっている可能性があるかもしれない。このテクニックの活用には注意が必要だ。

[C#] 画像からExif情報を削除するRemovePropertyItemメソッドの挙動がおかしい件

Bitmapクラス (Imageクラスから派生) のメソッドを眺めていたら、プロパティ項目を削除するメソッドを発見。

Image.RemovePropertyItem メソッド (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/system.drawing.image.removepropertyitem(v=vs.110).aspx

Exif情報などメタデータはプロパティ項目として画像に格納されているので、画像ファイルを読み込んでこのメソッドでプロパティ項目を削除して保存しなおせば、Exif情報が削除された画像ファイルが作成できるはず。そう思って試してみたのだけどうまくいかない。画像ファイルを読み込んだBitmapインスタンスからはプロパティ項目を削除できるのだが、保存しなおした画像ファイルには削除したはずのプロパティ項目が復活しているのだ。おかしい。

テストコード

以下のコードで挙動を調べた。

結果と個人的な推察

インスタンス上で変更したプロパティ情報は、保存したファイルにも反映される。しかし、削除したプロパティ情報は保存したファイルでは復活してしまう。これは.NETのバグだろうか。いや、文書には書かれていないけど、恐らくは仕様だろう。僕の予想は以下の通り。

画像データに加えてメタ情報が格納されることで画像ファイルは以前に増して肥大化している。極端な例だけど、わずか5×5ピクセルの画像に10GBのメタデータが付加されることだってあり得る。もしImageクラスに画像ファイルの内容を全て保持するようにすると、オブジェクトが肥大化してメモリを圧迫するのは明らか。そこでImageクラスの設計者は、クラスの機能に必要なデータだけを保持することにした。その弊害として、オブジェクトを別ファイルに書き出しすと、元ファイルにあったメタ情報が継承されないという問題が起こる。これを回避するために、ファイルを書き出す際には元ファイルからメタ情報を直接転記するようにしたのだろう。

僕の予想が当たっているかどうかはわからないけど、もし仕様ならばきちんと文書に記して欲しい。挙動がはっきりわからなければ使えない。

[C#] スプラッシュスクリーンを表示する

Windowsアプリにスプラッシュスクリーンを表示したい場合がある。その場限りの使用を想定した自前ユーティリティには必要ないけど、商品としてリリースされる予定の受託アプリには必ずと言っていいほどスプラッシュスクリーンの表示が求められる。

以下のページにわかりやすい具体例がある。

@IT:.NET TIPS Windowsアプリケーションでスプラッシュ・スクリーンを表示するには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/223splashscrn/splashscrn.html

スプラッシュスクリーンを表示するコードを以下に抜粋。留意点は ①スプラッシュスクリーンはモードレスフォームとして表示する ②スプラッシュスクリーン表示中のバックグラウンド処理ではDoEvents()を回す ③スプラッシュスクリーンを閉じた後はメインフォームにフォーカスを渡す、の3点。

[C#] フォルダをコピーする

あるディレクトリを別のディレクトリにサブディレクトリを含めてコピーする。

[C#] フォームに常に入力フォーカスを当てる

WindowsマシンをKIOSK端末のように使う想定で、アプリが常に入力フォーカスを持つようにしたいというニーズあり。すなわち、バックグラウンドで動いているアプリがメッセージを表示してもフォーカスを移すことなく、メインのアプリが常に前面かつ入力フォーカスを持つようにしたい。

まず思いついたのは、アプリのメインフォームにTopMost(常に最前面に表示)の属性をセットすること。試してみると、確かにフォームは常に最前面に表示されるけど、キーボードの入力フォーカスは他のアプリに移ってしまうことがあった。入力フォーカスをアプリに取り戻すためには、マウスでフォームをクリックしてやる必要がある。これでは要件が満足されない。

それじゃと思いついたのは、キーボードをグローバルフックすること。ネットを検索してみたら同じような事例が見つかる。だけどWin32 APIを呼んでやらないといけないのでちょっと面倒かな。もっと手軽にできる方法は無いだろうか。

C# フォームが非アクティブな状態でもキー判定を行いたい – Yahoo!知恵袋
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1080106570

ぬるり。: グローバルフック・ザ・キーボード
http://hongliang.seesaa.net/article/7539988.html

そこで思いついたのは以下の方法。タイマーを使って周期的に自分をアクティブ化することで、常にこのフォームがキーボードフォーカスを得る。インターバルを短くし過ぎるとタイマー処理のオーバーヘッドが大きくなるので注意が必要かも。あまりマナーの良い方法じゃないので自慢できたものじゃないが、手軽に実装したければこういう方法もありということで。

[C#] C++からC#のDLLを呼ぶ方法

以前のエントリで「C#からC++のDLLを呼ぶ方法」を書いた。今回はその逆で「C++からC#のDLL関数を呼ぶ方法」を考える。

これが必要になるのは次のようなシチュエーション。C++で書かれたアプリがあり、今回そのアプリに機能を追加したい。もちろんC++で地道にコーディングすれば機能は追加できるけど工数は多くなる。C#と.NETを使えば工数が少なくなるのは明らかなので、今更C++でコーディングするのはだるい。サクサクっとC#でコーディングして、それをC++から呼べると楽だよね?

方法としては、C++からC#のDLLを直接呼ぶことはできないので、C#で作成したCOMをC++から呼ぶことになる。以下にテストコードを示す。

テストDLL (C#) のソース

DLLを作成するために、Visual C#で「クラスライブラリ」としてプロジェクトを作成する。

プロジェクトの[プロパティ]-[アプリケーション]-[アセンブリ情報]設定で、[アセンブリをCOM参照可能にする]をチェックしておく。

VS2010-properties

そして、COMをビルドしてRegasm.exeを使ってシステムに登録する。

Regasm.exe (アセンブリ登録ツール)
http://msdn.microsoft.com/ja-jp/library/tzat5yw6(v=vs.110).aspx

これでC#(COM)側の準備は完了。

テストアプリ (C++) のソース

C++からC#で書かれたCOMの関数を呼び出す。

参考サイト

マネージドDLLとの接続、ActiveX(COM)による接続、アンマネージドDLLとの接続
http://satoshi3.sakura.ne.jp/memo/connect_dll.htm

C++からC#のdllを参照する際、引数内に構造体があった場合の処理 – C・C++ – 教えて!goo
http://oshiete.goo.ne.jp/qa/5493528.html?from=recommend

[C#] C#からC++のDLLを呼ぶ方法

最近は新規Windowsアプリ開発はC#でやるようになった。だけど、「既存のC/C++ライブラリ使い回す代わりに工数減らして」と発注元から要求されたり、サードパーティから購入したC言語DLLの商用ライブラリをリンクしないといけなかったりと、いまだにC/C++との連携は避けられない。

というわけで、C#からC/C++のDLL関数を呼び出す手順を覚え書きとして記しておく。

サンプルコード

以下のような簡単なテスト関数をC++で書いてDLLをビルドした。このDLLの関数をC#のテストアプリから呼び出してみる。

参考サイト

チュートリアル: ダイナミック リンク ライブラリの作成と使用 (C++)
http://msdn.microsoft.com/ja-jp/library/ms235636.aspx

pInvokeStackImbalance MDA
http://msdn.microsoft.com/ja-jp/library/0htdy0k3(v=vs.110).aspx