C#は電気羊の夢を見るか?(引っ越し中)

dtiブログが閉鎖とのことでhttp://tanocs.blog.fc2.com/へ引っ越します。

CsharpSQLiteの問題点

C#で実装し直された完全マネージッドなSQLite
http://code.google.com/p/csharp-sqlite/

このCsharpSQLiteは特定の文字列がクエリに含まれていると実行できないバグがある

問題はSqlite3クラスのクエリチェックメソッド『sqlite3GetToken』内にて発生していた
原因はString[]からByteにキャストして、ヌル文字を判定している箇所にて、
string[]に2バイト文字が入った場合、前半1バイト分が情報落ちする。
そのため、下1バイトが'00'の文字でヌル文字と判断されるため、クエリが通らなくなる。

尚、その条件に当てはまるのは以下の16文字
∀、─、一、稀、紀、儀、言、最、蔀、需、退、刀、謀、掘、耀、椀

以上の文字を含むクエリは以下の例外で終了してしまうはずです。
Community.CsharpSqlite.SQLiteClient.SqliteSyntaxException (0x80004005): unrecognized token '対象文字


修正はわりと単純で
Community.CsharpSqliteプロジェクト内の
complete.csとtokenize.csを修正すれば良い

以下は「sqlite_3_7_7_1_71」を元にした場合の修正方法
(尚、12月19日コミット分でも同様の方法で修正できます)

■complete.cs内
◇44行〜

static bool IdChar( u8 C )
{
return ( sqlite3CtypeMap[(char)C] & 0x46 ) != 0;
}

≡変更≡

static bool IdChar(char C)
{
return (sqlite3CtypeMap[C] & 0x46) != 0;
}



◇244行〜

if ( IdChar( (u8)zSql[zIdx] ) )
{
/* Keywords and unquoted identifiers */
int nId;
for ( nId = 1; ( zIdx + nId ) < zSql.Length && IdChar( (u8)zSql[zIdx + nId] ); nId++ )

≡変更≡

if (IdChar(zSql[zIdx]))
{
/* Keywords and unquoted identifiers */
int nId;
for (nId = 1; (zIdx + nId) < zSql.Length && IdChar(zSql[zIdx + nId]); nId++)


■tokenize.cs
◇129行
byte c = 0;
≡変更≡
char c = '¥0'; //¥を半角して下さい


◇201行
c = 0;
≡変更≡
c = '¥0'; //¥を半角して下さい

◇"(byte)z" を "z" に置換



最後に、情けない話ですが、
どなたか、本家のコミュニティに、この事を伝えられる方がいたら伝えてください。
英語とか、読んで雰囲気を感じるのが精一杯なんですorz


追記:2012/12/22
と思ったら既に本家のコミュニティで4月には、わかっていた問題だったようで、
issueとして対策が載っておりMileStone3.7.11として登録済みでした。

尚、それを参考に修正方法を、キャストしない方式に修正しました。

http://code.google.com/p/csharp-sqlite/issues/detail?id=151
このエントリーをはてなブックマークに追加
LINEで送る

ComboBoxへDictionaryを関連付ける

ComboBoxへDictionaryを関連付けたいだけなのだが、
情報が散らばっていて、分かりにくかったので、自分なりに、こうしたよというメモ。



ミソは以下の2つ
・BindingSourceでバインドする
・イベント中ではKeyValuePairへキャストする

追加はこんな感じ


選択はこんな感じ
comboBox1.SelectedValue = "b";

または、こんな感じ
comboBox1.SelectedIndex = 1;

バインドを強制的に外す



もっとスマートな実装方法がある場合は、コメントで指摘していただけると嬉しいです。


2012/12/17 修正
・クリア方法が無駄に小難しく書かれていたのを修正
・ドロップダウンの長さが残ってしまう問題を修正
・クリア後、例外が出てしまう問題を修正
・選択方法を追記
このエントリーをはてなブックマークに追加
LINEで送る

C#で、ネイティブなEXEを作成する

通常であればC#で開発したアプリケーションは.Net Frameworkが
インストールされた端末か、Monoが有る環境でしか実行できない。

しかし、Monoを使用してmkbundleというコマンドにてネイティブ化を行うことで
Monoや.Net Frameworkのインストールがされていない端末でも、
インストール作業なしで実行を行うことが可能になります。


この手法、海外のサイトを調べてみるとcygwinを使用した方法が主流ですが、
根っからの窓っ子の自分にはどうもとっつきにくい。
調べていくと、cygwinを使わずとも出来ることが解ったので、cygwinは抜きの手順です。


尚、出来上がるexeの実績については、SharpDXを使い1000本ほど配布を行いましたが、
WinXP、Vista、7にて32、64bitを問わず、実行できなかったという回答をもらっていないことから、
割と多くの端末で動作しているものと思われます。



記事を起こした時点での動作確認は以下のバージョンにて行なっています
・[Mono] 2.10.9
・[gcc for Windows] 4.7.2
・[GNU utilities for Win32] Last Update:2011-04-05


以下に長々と書いていますが、スムーズに行けば
準備3ステップ、実行3ステップの単純なものです。

◆準備
Monoをインストール
gccコンパイラをインストール
GNU utilities for Win32を配置

◆実行
mkbundleを実行
⊇侏莨紊った[temp.c]を編集
コンパイルを行う


■準備編
Monoインストーラをダウンロードする[mono-2.10.9-gtksharp-2.12.11-win32-0.exe]
http://www.mono-project.com/Main_Page

Mono for Windows, Gtk#, and XSPをダウンロードして、インストールしてください。
この時、インストールしたフォルダはコマンド等で頻繁に使用しますので、覚えておいてください。

★これ以下では、例として[C:Mono]にインストールを行ったものとして記事を書きますので、
別の場所に保存した方は適宜読み替えてください。



Win32の『32bit版』のgccコンパイラをインストールする[gcc-4.7.2-32.exe]
http://www.equation.com/servlet/equation.cmd?fa=fortran

!!64bit版のOSであっても、必ず32bit版をインストールしてください!!

☆ユーザー名が日本語の方はフォルダ名が化けているので修正してください。
 この時、日本語が含まれていないほうが望ましいと思われます。



GNU utilities for Win32を配置する[UnxUtils.zip]
http://sourceforge.net/projects/unxutils/
[UnxUtils.zip]を解凍し中に入っている[sh.exe]を[c:monobin]に配置する

☆後述しますが、このファイルは今回の目的にはかなりリッチなモノです。
また、実行時ウィンドウを小さくするバグを持っていて、最適とは言いがたいです。
詳細は[[脱線]]を御覧ください。



ず撞動して準備完了
!!環境変数を反映させるため手動での再起動が必要です!!


[[脱線開始]]
ここで必要なのは[sh.exe]という名前で[as -o temp.o temp.s]を実行してくれるアセンブリです。

.Netアセンブリのexeでも問題なく動作しますので、良く解らない物を使いたくないという人は、
適当な[HelloWorld.exe]を[sh.exe]にリネームして配置してしまうのも手です。
この場合mkbundle終了後cmdより[as -o temp.o temp.s]を手動で実行する必要があります。

ベストなのは、HelloWorldではなく[as -o temp.o temp.s]をキックするアセンブリであるのは
言うまでもありません。

さらに、mkbundleはオープンソースになっているため、
自作にて[sh.exe]を使わないようにカスタムする手もあります(後述)
[[脱線終了]]




■実行編
mkbundleを実行してgccアセンブラソースとmonoオブジェクトを取得する
【1.スタートメニューから「Mono-2.10.9 Command Prompt」を実行】


【2.ネイティブ化したい実行ファイルのあるフォルダに移動する】


【3.mkbundleを実行する】
・DLLなし
 mkbundle -c -o temp.c --deps --keeptemp hoge.exe

・DLLあり
 mkbundle -c -o temp.c --deps --keeptemp hoge.exe foo.dll bar.dll

・SharpDXを使う場合の具体例
mkbundle -c -o temp.c --deps --keeptemp Sample.exe SharpDX.Direct3D9.dll SharpDX.dll


!!ウィンドウが小さくなった後も引き続き[as -o temp.o temp.s]が実行されるので、
ウィンドウの×で終了しないでください!!

☆GNU utilities for Win32を使用するとウィンドウが小さくなってしまい、
 mkbundleのログが見えなくなってしまいます。

☆[as -o temp.o temp.s]は一緒に入れ込むdll次第では長時間となる場合があります

☆ログメッセージの
warning: pointer targets in passing argument 2 of 'mono_register_co
nfig_for_assembly' differ in signedness [-Wpointer-sign]
については後述。


【4.[exit]コマンドで終了】
ウィンドウが小さくなっていて見づらいですが、
[as -o temp.o temp.s]の実行が終了して入力が可能になるのを待って入力してください。


【上手くいかない時は】
☆SharpDX等インターネットからダウンロードしたdllなどのアセンブリを使用する場合、ブロックの解除が必要

☆署名有りDLLはダメなことがあるので、署名なしのものを利用してください。
 ここで通ってしまうこともありますが、後々問題を引き起こすので、署名なしのものを使ってください。

☆mkbundle実行時、exeの作成時と違うバージョンのdllを同梱しようとするとFileNotFoundになるので注意
 ソリューションをバッチビルドでリビルトしてやれば直る



⊇侏莨紊った[temp.c]を編集
#ifdef _WIN32
#include
#endif

//【以下2行を追加】
#include<direct.h> //<>を半角にしてください
#undef _WIN32

/////////////////////////////////////////////////

int main (int argc, char* argv[])
{

//【以下5行を追加】
char Path[4];
if(0 != GetModuleFileName( NULL, Path, 4)) {
Path[3] = '¥0'; //¥を半角にしてください
chdir(Path);
}


"#undef _WIN32"を書かないとコンパイル時にエラーが出て先に進めない
他は日本語を含むパスから実行するときにmono-2.0.dllが見つかるようになる魔法の呪文



コンパイルを行う
gcc -g -o AssemblyName -Wall temp.c -mms-bitfields -mwindows -IC:/Mono/include/mono-2.0 -mms-bitfields -mwindows -LC:/Mono/lib -lmono-2.0 -lws2_32 -lpsapi -lole32 -lwinmm -loleaut32 -ladvapi32 -lversion temp.o

!!以下の引数についてMONOのインストールディレクトリに適宜を記述を変更すること!!
-IC:/Mono/include/mono-2.0
-LC:/Mono/lib


☆「アクセスが拒否されました」とかメッセージが出る場合
cygwinがすでにインストールとかされてて、インストールしたgccより優先されてしまっているので、
環境変数の順番変えてインストールしたwin32のgccが実行されるようにしてくりゃれ。


☆cannot find -lmono-2.0とかってメッセージが出てる場合
このメッセージが出力されるのは64bit版gccをインストールしているから
Mono-2.0は32bitアセンブリのため、読み込むことが出来ずエラーメッセージが出力される。

解決するにはインストール時に登録されたgccの環境変数を手動で消して、
インストールしたフォルダを消して32bit版を再インストールしてください。

[蛇足]64bit版で実行しても速度に大きな改善はないので、面倒の少ない32bit版で行うのが良いと思う


☆最適化オプションについて
ある程度、最適化オプションを自由に設定できるが、思ったほど効果が上がらなかった。
なにか良いオプションを知っている方がいたら、ご一報ください。



exeが出力されて完成
出来上がったexeと[Mono-2.0.dll]を同じフォルダにいれれば、.Netのない環境でも実行できる。

配布時、exeのみとする方法もありますが
『mkbundle実行時に--staticフラグ付けて静的リンクしたら、お前のプログラムもLGPLだかんね』
http://www.mono-project.com/Mono:Runtime

とのことなので、おとなしく[Mono-2.0.dll]を外に出しておくのが無難だと思います。
「LGPL?上等!逆アセンブルなんて怖くねーぜッ!」って方はご自由に。



★★★★★実行がうまくできない時は★★★★★
=SharpDXでエラーが出る時は=
・最新版のDX入れてね☆(ゝω・)
http://www.microsoft.com/ja-jp/download/details.aspx?id=35


=実行しても、うんともすんとも言わないとき=
・同梱したdllのバージョンが、アセンブリ生成時と違ってたりする事があるのでリビルトを試す

・署名がついてるdllが混ざっていないか確認する

経験則で理解できてはいないけどmkbundle実行時、アセンブリの記述順で良くなったりダメになったりする事がある。
コンパイルは通ってexeは出来るけど、実行時うんともすんとも言わないパターンなので容赦ならない。


=署名関係について=
署名付きのdllしか提供されていない場合Mono付属の[sn.exe]で署名の上書きが出来るらしいが、権利的に怪しい。
出来る事ならソースコードをダウンロードして、自分で署名なしのバイナリを作るのが望ましい。

オープンソースじゃないのなら、作者に嘆願するか諦めるか個人の範囲で楽しみましょう。


=mkbundle実行時のメッセージについて=
temp.c: In function 'install_dll_config_files':
temp.c:81:2: warning: pointer targets in passing argument 2 of 'mono_register_co
nfig_for_assembly' differ in signedness [-Wpointer-sign]
In file included from temp.c:3:0:
C:/Mono/include/mono-2.0/mono/metadata/assembly.h:101:15: note: expected 'const
char *' but argument is of type 'const unsigned char *'

mkbundle実行時このメッセージが出力されていても、
致命的では無いようで大丈夫な時は大丈夫。
出ない時もある、よく解からん(´・ω・`)

内容は署名が違うとか言ってるっぽい。書き換えてやれば黙るのかは未確認。



◆mkbundleを自作する
・mkbundleのソースコード
https://github.com/mono/mono/tree/master/mcs/tools/mkbundle

自作したmkbundleを通して出来上がったexeを実行して
this application has requested the runtime to terminate it in an usual way
Please contact the application's support team for more information.
とかってエラーが出たら
MkBundleが実行時、Monoの環境ではなくMS.Net環境で実行されてる。


このエラーはMS謹製のmscorlib.dllを参照したためmono-2.0.dllの実行時に落ちてると思われる。
mkbundle時のログを見れば、MS製のmscorlib.dllを参照しているはず。

Mono用のコマンドプロンプトから"Mono"キーワードをアセンブリ名の前につけて
"Mono Mkbundle.exe[引数略]"とかってして実行してくりゃれ。


未確認な手法ですが、mscorlib.dll等の関連するファイルの署名をsn.exeで上書きすると
mscorlib.dllがMS版のままmkbundleが出来るかもしれない。

しかし、これは許諾以外の使用方法で、権利的に非常に怪しいと思うので、
個人の趣味の範囲でどうぞ。


=出来なかったこと=
mkbundleを単体で動作できるようにしたかったが、どうにも上手くいかなかった。
何か上手い事GUI化出来た方がいたらご一報ください。



◆おまけ
この手法でネイティブ化出来るのはMonoで実装されている機能だけなので、
全ての.Netアセンブリがネイティブ化出来るわけではない。
それを調べるためにMomaというフリーウェアがあるが、コレも割とめんどくさい。

そこで、下記の手法をつかってVS上からあぶり出すことが可能。
バージョンが違うので、dllは自力で入れ替える必要があるが、割と便利だったのでご紹介。
http://jpobst.blogspot.jp/2009/06/mono-in-visual-studio-2010.html


この方法で恐らくIronPythonから出力した.Netアセンブリもネイティブに動かせるんじゃないかと思う、という蛇足。蛇だけに。



◆最後に
この手法は、足がかりに過ぎず、ただ出来ているという状態を超えていません。
よりよい手法がありましたら、一つコメントをいただけると助かります。


この手法が、どなたかの助けとなれば幸いです。
このエントリーをはてなブックマークに追加
LINEで送る

.NetのRandomクラスから出力される値のムラについて

さんざんゲームを作り、システムを作ってきたはずなのに、
こんな基本的な落とし穴にはまってしまったのでメモ。


Randomクラスなのに使い方次第では完全なRandomにならない

Seedを揃えればそうなるのは仕様だけれど、
意図せずにこんな事があるとは、恐ろしい・・・


まず、Randomをインスタンスする際コンストラクタ引数なしの場合
SeedがEnvironment.TickCountを使用する設定になっている。

よって、連続して複数のインスタンスをほぼ同時に行うと、 同じ結果しか吐き出さなくなる。
というのはここらへんを見ると解ると思う


しかしながら、上記の対応方法でも問題がある。
Seedの値がいくらか違っても、どういうわけか結果に顕著なムラがある。

元々ムラがあるのは内部的に採用しているアルゴリズム上、仕方ないのだが、
それ以上に結果のムラを強く感じる。

検証ソース


結果


このレベルのムラはゲームでは致命的にはならないが、
GAなどでは結果に大きく影響するため、意識的に避けたい。

そういうわけで、複数のインスタンスを作成するより、
ひとつのインスタンスを使いまわす方が結果が優秀であるため、
スタティックでグローバルなクラスを作って、 そこから取得するのが良いのではないかと思う。


以下適当ソース


取得方法


結果サンプル


なんか、ジェネリックとかで、他にもっとうまい方法で出来るような気がするんだけど、
とりあえずこんな感じで。

求ム、最適解。


2012/11/22 追記
RandomをRondomと何度も何度も連呼しているという、
ソーシャルなウィンドーが全開の、まっこと恥ずかしい誤記を指摘していただいた、
通りすがりのご親切な方、誠に誠にありがとうございました。
このエントリーをはてなブックマークに追加
LINEで送る

Enumerable.Repeatでハマった

Enumerable.Repeatの挙動が想像していたのと違うのでメモ


こんな感じのクラスがあったとする
    public class test

{
public int index;

public test(int n)
{
index = n;
}
}
で、それをEnumerable.Repeatを使って、デフォルトコンストラクタを呼び出す。
    test[] array = Enumerable.Repeat(new test(5), 10).ToArray();
すると、結果はarrayのindexはすべて5となる。
ここまでは良い。

そして、それに値をこんな感じでセットする
    for (int i = 0; i < array.Length; i++)

{
array[i].index = i;
}
すると、結果はarrayのindexは、すべて 9 になってしまう。


何故こんな事が起こるかというと、
Enumerable.Repeatは、指定された回数初期化処理を行うのではなくて、
指定された個数のコピーを作るに過ぎないと言うことっぽい。

これ、別のバグとワンセットになって潜んでいた性で、かなり苦労させられた。
Repeatの名に騙された・・・
このエントリーをはてなブックマークに追加
LINEで送る

InvalidOperationExceptionが出るときの引数を犠牲にしない対処法

InvalidOperationExceptionは他のスレッドから、 コントロールの操作を行おうとすると発生する。 「有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'textBox1' がアクセスされました。」等と怒られるはず。 細かいお話は他のサイト様に任せるとして、とりあえずこの例外を切り抜ける方法。 何が起こっているか知りたい人は InvokeRequiredやMethodInvokerあたりを調べると幸せになれると思う。
このエントリーをはてなブックマークに追加
LINEで送る

C#でXMLを扱う時のメモ

XMLを扱っている上で困った、アレコレをまとめてみた。


・クラスをシリアライズしたXMLファイルを読み込む時、
XmlDocumentのLoadでOutOfMemoryExceptionが発生する対処方法


以下のように記述すると、XMLがある一定のサイズを超えると、
doc.LoadでOutOfMemoryExceptionが発生するようになる。


とりあえず、エラーを止めるには記述を以下のように変更すれば良い。


しかし、これだけでは根本的な解決にはならない。
一般的な対応方法は、SQLiteで、おとなしくDBを使うのが結果的に楽で早い。

ところで、肥大化したXMLファイルにjpg等の画像を埋め込んでいないだろうか?
この場合は対処方法がある。


・XML内に画像を埋め込んだ時にサイズが巨大になる対処方法
問題は、jpgやpngで取り込んだはずのデータでも、
すべからく32bitBMP形式で保存されるため、サイズが巨大化する。

これは以下のように、バイナリ化する際にImageクラスをそのまま、バイナリ化するのが原因。

これを解消するには、保存する際にjpgのバイナリにしてやることで回避可能。
もちろん画質はjpgになるが、この対応で読み込み時間が劇的に改善される。

さらにもう一歩踏み込むと、これはメモリ上にはビットマップで持ったままになる為、
プログラムの動作改善にはあまり効果がない。

そこで、使う寸前までJPGのバイナリでメモリ上に保持しておき、使う時に
Image = new Bitmap(new MemoryStream(PictureByteArray))
とした方がメモリ効率がぐっと良くなる。

また、読み込み時のメモリ確保、Bitmapの構築コストが無くなるので、
読み込み時間が更に短くなるはず。


・大きなファイルは直接上書きしない
あと、基礎的な所で、これだけ巨大なXMLを保存するときは直接上書きしてはならない。
以下の実装で書き出し中に万一メモリ不足でプログラムがハングアップすると、
過去データがすべて消える憂き目に合う。



気持ち面倒ではあるが、ワンクッション置くと、万一のとき、被害の度合いがぐっと減る。


以上、XMLアレコレでした。
基本的に、XMLでこのようなメモリをバカ食いする実装は、
本来は望ましくないのではないかと思う。

これらの手法は、ある程度データが増えた場合の一時的な対応なので、
なんらかのDBに移行するために、時間を稼ぐ延命措置ぐらいに思って欲しい。


もしくはXMLをランダムアクセスする、豪快なクラスを作るのも面白いかもしれない。
先頭アドレス、サイズ、キーを保存したファイルを用意すれば、不可能ではないのではないかと思う。
このエントリーをはてなブックマークに追加
LINEで送る

ネットからダウンロードしたアセンブリを読み込む

どうにも思うようにmkbundleが動作してくれないので、いよいよとパッチ作業を始めた。その中で以下のエラーが出て先に進めなくなったのでメモ。

ネットワーク上の場所からアセンブリを読み込もうとしました。これにより、以前のバージョンの .NET Framework で、アセンブリがサンドボックス化された可能性があります。このリリースの .NET Framework では、CAS ポリシーが既定で有効になっていないため、この読み込みは危険な場合があります。この読み込みがアセンブリのサンドボックス化を目的としない場合は、loadFromRemoteSources スイッチを有効にしてください。詳細については、http://go.microsoft.com/fwlink/?LinkId=155569 を参照してください。

要約すると、
『読み込んじゃいけないっぽいアセンブリを読みこもうとしてますぜ、旦那。
どうしてもって言うなら、フラグ変えると幸せになれるかもな。
続きはWebで。』


じゃぁ、続きをと思って見てみると、以下のメッセージが目に入った。
「Visual Studio プロジェクトのエラー一覧に表示されたエラー メッセージ、またはビルド エラーによってこのトピックにたどり着いた場合は、「方法: Visual Studio で Web からダウンロードしたアセンブリを使用する」を参照してください。

要約すると
『お前も、かの場所から来たのか。
ならば、お前の進むべき道は・・・
続きはWebで。』


というわけで続きを開いてみると
方法: Visual Studio で Web からダウンロードしたアセンブリを使用する

あぁ、なるほど。
このエントリーをはてなブックマークに追加
LINEで送る

DirectShowLib-2005をWin7で使えるようにする

DirectShowLib-2005をWindows7の64bitで使おうとしたところ
『接続に必要な中間フィルターの組み合わせが見つかりませんでした。』
とかってエラーがでて動作しない。


Windows7ではDirectShowフィルターは
強制的にMicrosoft製の物が優先になるとか何とか(うろ覚え)

まぁ、そのあたりの絡みなのかなぁと思いつつ、
どうせ使わないのでDirectShowフィルターを無効にしてやることで、
とりあえずこの問題をクリアした。


修正はたった1行で
ソース『Capture.cs』内の SetupGraph メソッド中にある、
以下の一行をコメントアウトすればよい。

m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0);
このエントリーをはてなブックマークに追加
LINEで送る

これは便利だ・・・

超基本なんですが、今までずーっとこれで苦労していた。

タブ遷移

こいつを自動的にささっと指定する方法はないかと、
何度も探しては挫折していたのですが、
ようやく見つかった。


メニューバー[表示(V)]→タブオーダー(V)としてから、
遷移させたい順にオブジェクトをクリック
そこからメニューバー[表示(V)]→タブオーダー(V)で確定


今まではそれほど画面数がなかったので、
我慢して自力でやってましたが、いつからこの機能あったんだろう・・・

確か、前の会社でメジャーバージョンアップ時にタブオーダーの変更で、
2人日くらいスケジュールがとったような記憶が・・・・・・(汗
このエントリーをはてなブックマークに追加
LINEで送る

知らんかった・・・

bool型って初期値があって、宣言すれば勝手にfalseになるそうな。
コンストラクタで一生懸命初期化してたよ・・・
このエントリーをはてなブックマークに追加
LINEで送る

VC#2010EEで対象のフレームワークが変更できない時の対処方法

現在XNA4.0化を進めていたのですが、いくつかハマったので情報として残しておく。


参照アセンブリ "Microsoft.Xna.Framework.Content.Pipeline,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553" は、
現在のターゲット フレームワーク ".NETFramework,Version=v4.0,Profile=Client" 内にない
"Microsoft.Build.Utilities.v4.0, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" に依存するため、解決できませんでした。
ターゲット フレームワーク内にないアセンブリへの参照を削除するか、
プロジェクトを再ターゲットしてください。

上記エラーメッセージが表示された時の対処方法として
XNA4.0ではデフォルトがおそらく
[.NET Framework 4 Client Profile]なので
これを[.NET Framework 4]としたい。

しかし、VC#2010 Expressだと
『プロジェクトプロパティ→アプリケーションタブ→対象のフレームワーク』から変更ができない。

そこでコンパイルターゲットをExpress Editionで変更するのと同じ方法で、
エラーが出ているプロジェクトファイル(*.csproj)を適当なテキストエディタで開き
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
となっているのを
<TargetFrameworkProfile></TargetFrameworkProfile>
と変更すれば良い。

蛇足として、この方法では『無印→Client』の逆方向への変換はできなかった。


XNA4.0化を対応していると、全体的に煩わしさを取り除くことに注力しているなぁという印象。
その経緯には携帯端末への対応のため、どうしても処理を単純化せざるを得なかった背景もあるように思う。

しかし、この単純化が原因でDirectXにほど近い機能のいくつかが削除されてしまった。
最も痛手だったのはFillMode.Pointの廃止。
これを利用して頂点シェーダからGPGPUを実装していただけに、完全に足元を失ってしまった。
どうにか実現できないかと、あれこれやってみたが、どうにもダメっぽい。

DirectXからFillModeの設定変更を無理やりラップしてみて、
ダメそうならSlimDXへの移行を検討する予定。
このエントリーをはてなブックマークに追加
LINEで送る

苦手意識

苦手意識というのがある。
こいつは食わず嫌いのように、やってみれば大したことないのに、
何故か出来ないような気がして手が出ない心理的に非常に厄介な状態。
自分にとってそんな感じだった物にdelegateがある。

なんとなくjavascriptの、関数を変数のように扱うイメージはあったものの、なぁんとなく手が出せずにいた。
理由はよく解らない物を使ってバグを引き起こすわけにはいかない為、普段使い慣れていないものを嫌っていたのだと思う。

ところが先日、どうにもスパゲティになっていたソースを修正する機会があり、苦手意識を克服することができた。


件のソースは、オブジェクト分割は疎か、関数への分割も殆ど行われておらず、
一つのイベントだけで3千行以上書いてある有様で、
一つのソースファイルに1万行以上のコードが記されている超大作であった。

こいつをどうにかして、ソースの全体を見渡せる状態を作りたかったために、処理を整理していったのだが
ちょっとの判定の差が影響して、似たような二重ループが量産されているのが目についた。

その二重ループの大半が描画処理であったため、とりあえず関数化して別ソースに避けていったのだが、それでもまだ同じようなソースコードが大量に存在している状態であった。

こいつをどうにかしてまとめたいという欲求から、デリゲートのお世話になってみることにした。


ところがデリゲートを使ってみるとその大量にあった二重ループのソースは約1/10程度まで減り、かなりすっきりと全容を見渡せるようになった。

使ってみればイメージ通りの挙動をしてくれるし、今まで全く理解できなかったラムダ式もサクサク使えるようになった。

逆にラムダ式が読めない人には、何のことかさっぱり読めないソースコードになったような気がしないでもない・・・


しかしながら、これは非常に便利だと思った。
便利でコーディングはかなり楽になるけど、使い過ぎると可読性が落ちて非常に危険なんじゃないだろうか・・


ラムダ式にたいする一般的な見識というのを見かけたことがないので、多用に対する注意や可読性に対する見解はどうなってるんじゃろなぁ・・

とりあえず、デリゲートが理解できたので、これで並列処理も書いていけるようになりそう。



蛇足:こいつぁは便利だー!って書きまくって思ったんだけど、
デリゲートってオーバーロード出来ないんじゃろか・・
感覚的に書いたらエラー出て、ちょっと調べた感じじゃなさそうだったので。

そこまで仮想化すると、元がなんなのかわからなくなってしまうような気がしないでもない・・
このエントリーをはてなブックマークに追加
LINEで送る

配列のお話

普段何気なく使っている多次元配列。
過去の自分が作ったソースを見ていると、
ある時期を境に表記が変わっていることに気がついた。

int[][] a; //旧
int[,] a; //新

ある時期というのは、ブランクが1年ほどあるので、
そこが境界なのだが・・・はて、この差はなんだ?
と思いつつも、大して違いはなかろうと、ろくすっぽ調べることなく放置してました。


んで最近、配列の初期化をスタイリッシュに行いたいと思い立ち、以下のソースに出会った。


//int[100]{1,1,1,1,1.....}と同じ
int[] intArray = Enumerable.Repeat(1, 100).ToArray();

//string[10]{"a","a","a"....}と同じ
string[] strArray = Enumerable.Repeat("a", 10).ToArray();


うん、スタイリッシュ。

速さについては知らないが、さほどコールされない初期化処理なら問題にはならんでしょう。
それよりも、初期化処理にfor文を書かずに済む分、非常に見栄えがよろしい。

ところが以下のような多次元配列の初期化が通らない。


int[,] array = Enumerable.Repeat(Enumerable.Repeat(1, 100).ToArray(), 100).ToArray();

なんでもint[,]にint[*][*]を変換できないのだとか。

     |
 \  __  /
 _ (m) _ピコーン
    |ミ|
  /  `´  \
   ('A`)
   ノヽノヽ
     くく   もしや、別物。。。


んでよくよく調べてみると、最初に書いた表記の差は、ジャグ配列と多次元配列という、
全く別ものであることが分かった。


int[][] a; がジャグ配列
int[,] a; が多次元配列


int[][]は四角い配列にする必要がないとかで、直感的に”低速そうだなぁ”と思ったのだが、
よく良く調べてみるとどうも違う。

int[][]は内部的には一次元配列を切り替えて処理するため、
単純な二次元配列よりも高速なのだという。


ほぅ・・・


じゃぁ、二次元配列の強みは?というと、
アンセーフコード化したときにポインタアクセスするのに便利。
さらに、アンセーフコードでポインタアクセスすると高速。
・・・って、おい。

マネージドコードじゃ、いいところ無しかぁ・・


ではジャグ配列の実力とやらを検証してみると
内部的に一次元配列と言いながらも、一次元配列より15%程遅い。

そして、四角い配列はアンマーネジコードで線形アクセスすると早い。
なら最初から一次元配列にしとけばいいんじゃぁ・・・

今までなんとなく二次元配列を使用してましたが、
速度が必要になる画像処理やゲームの世界では、極力一次元配列で実装したほうが良さそう。
このエントリーをはてなブックマークに追加
LINEで送る

のっぴきいかねぇ

世の中にはやってはならんことというのが幾つかある。
その理由や度合いは様々だが、いたしかたない事もある。

今回は標準モジュールの設計がプア過ぎて、
親ウィンドウ閉じちゃうようなひょっとこなダイアログを
さらにコンストラクタで呼び出すという、ひょっとこ面の頭にヤカン載っけて沸かしてしまうような状態のプログラムを
納期との兼ね合いでどうしても動作させるようにする方法のご紹介。

ObjectDisposedExceptionを吐いているので、それを無視すれば良い。

メッセージはきっとこんな感じで出ているでしょう
「破棄されたオブジェクトにアクセスできません。
オブジェクト名 'Form1' です。」

Program.csをこんな感じに変更

try {
Application.Run(new Form1());
} catch (ObjectDisposedException ode){
}

き、きもちわるい・・・・


まちがっても
catch (Exception e)
などと記載しないように、きっとこんなのプログラマが書いたらSEは死んでしまう。


とりあえず・・・とりあえず、これでエラーを吐かずに動く。
現場では動くプログラムこそ正義。

悲しいけど、これ仕事なのよね。
このエントリーをはてなブックマークに追加
LINEで送る

小ネタ

■スタイリッシュ配列指定
 ※あくまでスタイリッシュであって、速度のことは知らない

a.First(); //a[0]
a.Last(); //a[a.Count - 1]

考察:
可読性は結構上がる。あとなんとなくカッコイイ。
しかしながら、メソッドであるため、戻り値がメモリにわざわざ置き直されるんじゃなかろうか?

そうすると、配列一つあたりのメモリ使用量が大きい場合、結構速度へ影響があるような気がする。
例えばa.First().ToString()とか言う感じで参照後のメソッドを呼び出すような場合、
顕著に現れる気がする。
もちろん、気がするだけで実証はしてない。


.Last()は速度への影響が少ないところにはぼちぼち使ってみたい。
.Firstは文字数的にも見た目的にも速度的にも微妙。
自身が長年 a[0] の表記に慣れ親しんでいるので、あまり使わない気がする。


■sortedリストのエラーメッセージ
しょぼいミスで『少なくとも 1 つのオブジェクトで icomparable を実装しなければなりません。』とか言うエラーが出たときの対処法。

SortedList.Max() はできないので SortedList.Last() とすること。
結果はよっぽど同じになるはず。


■迷った時は
SortedListかSortedDictionaryで迷った場合、
ランダムアクセスとキー指定の頻度が多ければSortedDictionary。
比較的単純なアクセスが多く速度がほしい時はSortedListが優秀。


■応急処置
現場とかでどうしてもソースをいじるのに
Visual C# 2008 Express Editionを使用する場合、
相手方が64Bitだったりすると、CPUの選択ができずに詰む。

これの対処のためにテキストエディタで
ソリューション(*.sln)とプロジェクトファイル(*.proj)を開き
[Any CPU][AnyCPU]を[x86]にすると対応できる上、
何故か構成マネージャが有効になる。
このエントリーをはてなブックマークに追加
LINEで送る

別スレッドからフォームコントロールを呼ぶときの注意

label1.textに値を代入しようとしたら”CrossThreadMessagingException”なる例外がっ

たかだかラベルにテキスト送信するだけでなんで例外が出るのかと思いきや、
別スレッドからのフォームコントロールプロパティへのアクセスは.Net2.0からの仕様変更で
そうなったそうで。

よくよく使用箇所を見てみるとたしかにフォームオブジェクト外からのイベント呼び出しようで、別スレッドっぽい。

そこでぐぐーる大先生で検索してみると、スレッドセーフだとかコントロール スレッドだとか、
妙に小難しい単語が並んでいて、サンプル見てもデリゲートとか見慣れない方法が連なっていて、
初心者には厳しいんじゃないかと思う・・


んで、簡単な対処方法を以下にご紹介

this.Invoke( //このthisはform1なので、別オブジェクトからの場合は注意が必要
(MethodInvoker)delegate() {
label1.Text = "hoge";
}
);

これでかなり簡単に、かつソースの見た目もほぼそのままコーディング出来る。
これすらも面倒だと言う人は、例外そのものを発行しなくなるオプションがあるそうなので、
そっちを当たってみるといいかも。
このエントリーをはてなブックマークに追加
LINEで送る

anchorとサイズの挙動

解決してみればなんということはないハマリだが、
これが意外と調べてもなかなかと答えが見つからなかったのでメモ。


アンカーを使ってコントールのサイズを自動的に決定する場合、
アンカーによって変更されたサイズをサイズプロパティからは取得できない。
(デザイナの初期設定値を平然と返す)

そこで、SizeChangedイベントからサイズを取得し、
そいつをわざわざ入れてやる必要がある。


なんで、見た目変わってるのにサイズプロパティを更新しないのだろうか・・・不思議。


private void pictureBox1_SizeChanged(object sender, EventArgs e)
{
Control control = (Control)sender;

pictureBox1.Width = control.Size.Width;
pictureBox1.Height = control.Size.Height;
}
このエントリーをはてなブックマークに追加
LINEで送る

コンパイルしてくれなんて頼んでいない

ASP.NETではまったのでメモ
誤って目的外のファイルが混入していると
そのファイルもまとめてコンパイルされるためエラーを吐くようになる。

サーバーとローカルでファイル構成が変わっているのに気がつけない環境や、本番環境などでデバッグが表示ができないときにハマりやすい。


『クライアントは 'text/html' の応答のコンテンツ タイプを見つけましたが、'text/xml' が必要です。要求は以下のエラーにより失敗しました。』
の詳細がコンパイルエラーとなっている時はこれ。
このエントリーをはてなブックマークに追加
LINEで送る

なんとかバー

スクロールバーで0%〜100%を切り替えようとしていた後輩がいた。


・・・・なんか違う。

これじゃない。

もっとこう、いいコントロールがあった気がする。

ほら、あのスクロールバーの細いヤツ・・


名前なんだっけ・・・


答)TrackBar
このエントリーをはてなブックマークに追加
LINEで送る

ひとつ上のプログラム

階層のひとつ上を指定するとき、いっつも"../"とかやってた、時には定数を作ったりもしてたけど、かっちょいいソースを発見したのでメモ

DirectoryInfo currentDirectory = new FileInfo(Assembly.GetEntryAssembly().Location).Directory;
string path = currentDirectory.FullName + @"¥" + fileName;
if (File.Exists(path)) File.WriteAllBytes(currentDirectory.Parent.Parent.FullName + @"¥" + fileName, File.ReadAllBytes(path));

もういっそのこと@"¥"もなんとかならんかなぁ・・・


=10/31追記=
とおもったら有ったpath.combine(Path1, Path2);

Path.DirectorySeparatorCharも使える
このエントリーをはてなブックマークに追加
LINEで送る

自身のファイル名を取得する際の罠

今回はハマるまではいかなかったものの、
調べるのに意外と時間がかかったのでメモ

Environment.GetCommandLineArgs()[0]にて取得すると
デバッグ中にはvshost.exeが帰ってくるので不便。

Application.ExecutablePathを使うほうが.netらしいのではないかと思う。


=追記=
と思ったら更にはまった

Application.ExecutablePathで帰ってくる拡張はなんと大文字・・
これではDirectory.GetFilesで取得した自身とは比べられないので
Assembly.GetEntryAssembly().Locationを使う。

ってか、おんなじ事をするメソッドなのに、何でこうも差が出るかね・・
このエントリーをはてなブックマークに追加
LINEで送る

コンストラクタのオーバーロード

シーンに分岐があるかどうかや、そのシーンでシーンの末端を担う等の場合、コンストラクタにフラグを追加したくなるのだが、毎回引数を渡すはめんどくさい。

そこで、コンストラクタをオーバーロードしようとするのだが、意外と手こずったのでメモ

//もともとのコンストラクタ
//シーンクラスを継承とかしてた場合 :base()とか必要に応じて書いてくりゃれ
public GameSceneTest(Game game, bool isLastScene) : base(game) {
//なんか処理とか
}

//省略形のコンストラクタ
public GameSceneTest(Game game) : this(game, false) {
//オーバーロードする場合、此処に書く処理はthis()コンストラクタの実行後に実行される
}
このエントリーをはてなブックマークに追加
LINEで送る

メモ

最近、自作のゲームが恐ろしく重たくなってきた。
一回のコンパイルで10分とかかかるので、
うっかりコンパイルしてしまうとそのまま10分持って行かれる・・

そんなわけで、人生で初めてコンパイルをキャンセルする必要が出てきた

そういうわけでCtrl+Breakでコンパイルをキャンセルできる。
Breakキーも人生で初めて使ったよ・・・
このエントリーをはてなブックマークに追加
LINEで送る

XPとVistaでカレントディレクトリの挙動

VISTAは固定されるがXPはFileDialogでコロコロ変わるので、
ファイルのパス指定は相対的に'hoge.txt'とかやらないず、
特種ディレクトリパス等を取得して、完全パスで行うこと。

ただし、インストール型のプログラムを作成時、
自EXEと同フォルダとしてProgramFilesフォルダに
読み書きするプログラムは7で挙動がおかしくなる原因となるので、
極力避けること。
このエントリーをはてなブックマークに追加
LINEで送る

 | HOME |  NEXT »

PAGE TOP ▲

Appendix

■春条

■春条

生息地は愛知
車と甘い物が好きな31歳
特技は無限昼寝

MONOからSharpDXを使う
変態的な手法で、
.NET Frameworkを使わずに
ゲーム作りやってます。

Search

Calender

« | 2017-11 | »
S M T W T F S
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 - -

Twitter

Recent Entries

DTIブログポータルへ
このブログを通報
Report Abuse

利用規約