C#で開発を行う際に守るべき18のルール

StackOverFlowで紹介されていたC#で開発を行う際に守るべき18のルールが紹介されていました。
内容が興味深かったので紹介します。
元ネタは、http://stackoverflow.com/questions/2787035/coding-guidelines-best-practicesです。

日本語に訳していますが、意味いまいちな場合は原文を当たった方が分かりやすいかも…


1.FxCopを使用して、ソースの静的チェックを行う

FxCopとは、Framework Copの略で(Cop=警察です)、Microsoftから提供されているツールです。
コンパイル後のバイナリ(マネージドコードアセンブリ)に対して、ガイドラインに準拠しているかをチェックする事ができます。



2.StyleCopを使用してコードのスタイルをチェックする

StyleCopは、ソースコードのスタイルをチェックする事ができます。
コーディング規約のチェックに便利です。
http://archive.msdn.microsoft.com/sourceanalysis



3.値の型(value type)がEnumと異なる意味である事を示すために、IDEの設定で色を変更せよ。

VisualStudioのメニューバーの、ツール->オプション->環境->フォントおよび色をみると、ユーザタイプ(列挙型)と、 ユーザタイプ(値の型)が同じ色になっているので、一方を違う色に変更して置きます。
これによって、列挙型と、Value Typeの区別が付きやすくなります。



4.例外はコード内のバグを示す傾向があるため、IDEで全ての例外をbreakさせるようにせよ。

VisualStudioのメニューバーの、デバッグ->例外で、Common Language Runtime Exceptionsの”スローされるとき”にチェックを入れます。
これで、デバッグ中にCLRの例外が発生すると、常にプログラムの実行が中断されます。



5.プロジェクトの設定で、”アンセーフコードを許可しない”の設定をセよ

VisualStudioのメニューバーより、プロジェクト->xxxのプロパティを選択後、ビルドタブで指定できます。



6.プロジェクトの設定で、”警告をエラーとして扱う”の設定をセよ

VisualStudioのメニューバーより、プロジェクト->xxxのプロパティを選択後、ビルドタブで指定できます。



7.プロジェクトの設定で、演算のオーバーフローおよびアンダーフローのチェックを入れよ

VisualStudioのメニューバーより、プロジェクト->xxxのプロパティを選択後、ビルドタブに有る”詳細設定”ボタンより指定できます。



8.単一で明確に定義された目的のために変数を使用せよ。

1つの変数を複数の目的で使用すると、後でコードをメンテするときにバグが入りやすくなってしまいます。



9.マジックナンバーを使用するな。

マジックナンバーというのは、コード中に書かれた具体的な数字です。

数字をコード中に直接書くのではなくconstを使用して、定数を定義します。
http://msdn.microsoft.com/ja-jp/library/ms173119%28v=vs.80%29.aspx



10.1つのメソッドは短くなるようにせよ。単一の明確に定義された目的を持たせるべき。

複数の処理が混在している複雑なメソッドは、バグが入りやすくなりますし、仕様が変わったとき場合にもメンテを行う範囲が大きくなってしまう場合が多いため保守性の面でも問題があります。


11.メソッドは小さすぎるということは無い(1メソッドが20行を超えると、大きいと思え)

10.と同じような意味かと思います。
1つの処理はなるべくシンプルにしておき、モジュール間の結合が小さくなる事を心がけます。


12.メソッドのパラメータとして、不正な値をはじくようにチェックせよ

不正な値は、入ってきたタイミングで防ぐ事でプログラムの品質を向上する事ができます。
メソッドのパラメータは処理の最初でチェックを行い、NGの場合は例外を返す等の処理を行います。


13.オブジェクトを不変(immutable)にできないか考慮せよ

immutableについては、下記のサイトが詳しいです。
immutable



14.”#pragma warning disable”を使用して、警告の出力を抑制させてはならない。

警告はプログラムのバグを示唆してくれる場合が多いため、覆い隠すのではなく警告が出ないような表記に書き換えます。



15.ダメなコードは書き直せ

保守性を考えて、読みづらかったり、入力チェックが甘いようなロジックは書き直してしまいます。
…ただ、一方で、”動いているコードは直すな”という格言もあるので、ケースバイケースで考えてください。



16.例外をcatchして、その後の処理を正常処理する場合は、なぜそうするのか理由をコード上に明記せよ

例外を無視する場合、コーディングしている時はそうすべき明確な理由があったかもしれませんが、後から保守する時にはその意図が分からなくなっている危険が有ります。
もし、あえて無視する必要があるなら”コード中”に理由を明記しておきます。



17.文字列連活に関するパフォーマンス低下に気をつけよ。

C#に限らずjavaでも有名な話ですが”+”演算子による文字列結合を大量に行うと、パフォーマンスが低下します。このような場合はStringBuilderの使用を検討してください。

18.gotoは使用するな


goto批判については、Wikipediaを参照してください。
http://ja.wikipedia.org/wiki/Goto%E6%96%87

ただ、C#の場合は、Javaと違ってラベル付きcontinue/breakの構文が無いので、gotoを書いた方がすっきりする場合もあるかも…という気もします。


4774145025
C#ルールブック ~読みやすく効率的なコードの原則

[C#]演算子オーバーロードを使用して、オブジェクトの条件分岐をシンプルに記述する

あるクラスのオブジェクトの状態をチェックしたい場合、比較式をクラスのメソッドとして実装して確認する事が有ります。

class Score {
    public int value;
    public Score( int i ) {
        value = i;
    }
 
    public bool isValid() {
        // 値が0~100のときのみ有効とみなす
        if ( value >= 0 && value <= 100 ) {
            return true;
        } false {
            return false;
        }
    }
}
 
static void Main() {
    var s = new Score(-1);
    if( s.isValid() ) {
        Console.Write( "It worked!" );
    }
}





上記のプログラムですが、演算子オーバーロードを使用すると、チェック処理をシンプルに記述できます。
これには、if内で記述したオブジェクトに対する暗黙の型変換の機能を利用します。

サンプル:

class Score {
    public int value;
    public Score( int i ) {
        value = i;
    }
 
    public static implicit operator bool( Foo f ) {
        // 値が0~100のときのみ有効とみなす
        if ( value >= 0 && value <= 100 ) {
            return true;
        } false {
            return false;
        }
    }
}
 
static void Main() {
    var s = new Score(-1);
    if( s ) {
        Console.Write( "It worked!" );
    }
}



“implicit operator bool”で、bool型への型変換を定義しています。
これによって条件式が”if ( s )”だけのシンプルな記述になりました。

演算子オーバーロードは、乱用するとかえってコードの可読性が低くなってしまう危険もありますが、状況によっては上記のサンプルのようにコードをすっきりさせる事もできます。

Amazonマーケットプレースで、保留中商品への発送依頼が来た時の返答方法

Amazonマーケットプレースで商品を販売している場合、購入者側で決済が完了していないと”保留中”のステータスになります。
決済が完了すれば発送可能になるのですが、保留中の注文は送付先住所が出品者側では分からないため、発送したくても発送する事ができません。

また、Amazonの規約上も保留中の商品を出荷することは出来ません。

保留中の注文とはなんですか?
 
保留中の注文には、購入者の支払い方法の承認が完了していない注文や、コンビニ決済で支払いが
完了していない注文が含まれます。保留中の注文を出荷することはできません。
 
購入者から直接連絡があった場合でも、出荷しないよう注意してください。
 
保留中の注文には「出荷通知」ボタンや「注文キャンセル」ボタンが表示されません。
また、保留中の注文は、注文レポートや未出荷注文レポートには表示されません。


よくある質問:注文の管理より

というわけで保留中の商品を発送する事はできないのですが、購入者によっては、自分の注文の決済が完了していない事を把握できておらず、早く商品を発送するよう依頼や督促のメールが来てしまうことがあります。


この場合は、Amazonカスタマーサービスへ誘導するのがベターです。
以下、返信メールの雛形です。

お問合せ頂いた商品ですが、現在Amazonのシステム上お支払いの決済処理が完了していないため、
当方にて商品の発送を行う事ができない状態です。
 
 
お手数をおかけして真に申し訳御座いませんが、以下の方法で購入者様より直接
Amazonカスタマーサービスへお問い合わせいただけますよう、お願い致します。
 
1. Amazon.co.jpサイト右上の「ヘルプ」をクリック
 
2. 各ヘルプページの右側に表示されている「お問い合わせはこちら」ボックス内の
 「カスタマーサービスに連絡」というボタンをクリック
 
3. Eメールまたは電話でのお問い合わせを選択し、カスタマーサービスに問い合わせ
 
 
また、カスタマーサービスへのお問い合わせについて詳しくは以下のヘルプページで
ご説明しています。
http://www.amazon.co.jp/contact-us/
 
 
もしくは、以下のお電話番号にご連絡いただくよう御願い申し上げます。
-----------------
011-330-3000
0120-999-373
-----------------



クレーム応対文書文例集

[C#]Stringとstringの違いは?

C#で文字列を格納する変数を定義する場合、Stringとstringの2つが有ります。(先頭が大文字か小文字かが違っています)

以下の例では、どちらもエラーなくコンパイル&実行可能ですがこの2つは何が違っているのでしょうか?

String var1;
string var2;



C#の言語仕様上、stringはSystem.Stringのエイリアス(別名)という位置づけなので、仕様的には両者は全く同じです。
ですので、どっちを使っても問題無く動作するのですが、一般的には以下のガイドラインに沿ってコーディング規約が作られる事が多いです。

1.文字列の変数を定義する場合
先頭小文字のstringを使用します。

string name;




2.クラスのスタティックメソッドをコールする場合
クラスである事を明示するために、先頭大文字のStringを使用します。

string message = String.Concat( "hello", "world" );



C#ルールブック 読みやすく効率的なコードの原則

[C#]誕生日より年齢を求める最も簡単な方法

C#で誕生日から年齢を求めるシンプルな方法です。


日付計算はDateTimeクラスに任せるのが一番簡単です。
DateTimeだと、うるう年周りの処理もやってくれるので安心です。
また、誕生日を過ぎているかどうかで1歳変わるので、その分の判定を最後の行で行っています。

int age;                 // 年齢
 
DateTime birthDay = ...; // 誕生日を取得
DateTime today    = DateTime.Today;
 
age = today.Year - birthDay.Year;
age -= birthDay > today.AddYears(-age) ? 1 : 0; // 誕生日が来てない場合は1歳引く
 
Console.WriteLine( "あなたの年齢は" + age + "歳です" );



知識の暦
Visual C#.NET逆引き大全

[C#]enumが持つ全ての値をforeachで取得する

以下のコードで、enumの列挙が持つ全ての選択肢をループで取得する事が可能です。

public enum ErrLevel {
        Debug,
        Info,
        Warnig,
        Error,
}
 
foreach ( ErrLevel level in Enum.GetValues( typeof(ErrLevel) ) ) {
	...;
}



Enum.GetValuesの戻り値は配列(Arrayオブジェクト)で、指定した列挙体内の定数値たちを,配列として取得します。

[C#]foreach文でループカウンタを取得する方法

C#でforeachを使用してループを行うと、シンプルな表記で集合内のデータを処理する事ができるので便利ですが、何番目の値を処理しているかのループカウンタが無いのが不便です。

このような場合は、以下のようにSelect()メソッドを使用すると処理中データのindexを取得できます。

static void Main(string[] args) {
    string nameArray = new string[] { "alice", "bob", "charlie", "dave" };
 
    foreach ( var nameObj in nameArray.Select( (value, index) => new { value, index } ) ) {
 
        // nameObjのメンバであるindexよりループカウンタを取得可能
        Console.WriteLine( "{0}人目: 名前{0}", nameObj.index, nameObj.value );
    }
}



ここで出てくるSelect()メソッドですが、これはEnumerableクラスのメンバなので、
例で使用している配列以外にListやDictionaryにも応用可能です。

Select()には、ラムダ式を引数として渡してあげます。
ラムダ式では2つのパラメータをもらっていますが、これはmsdnのオンラインマニュアルで確認すると、以下のように1つ目が処理中の値で2つ目が0から始まるカウンタである事が分かります。

selector の最初の引数は、処理する要素を表します。 selector の 2 つ目の
引数は、ソース シーケンス内のその要素の 0 から始まるインデックスを表します。 
 
これは、たとえば、要素が既知の順序である場合に、特定のインデックスにある要素
に対してなんらかの処理を行うときに役立つことがあります。 
 
また、1 つ以上の要素のインデックスを取得する場合にも役立つことがあります。


http://msdn.microsoft.com/ja-jp/library/bb534869.aspx より


シンプルかつとても便利な表記法ですが、注意点としては、Select()は、LINQの導入とともに追加された機能なので.NetFrameworkの3.5以上である必要があります。また、1要素処理するたびにnewしているので、集合内のデータ件数が膨大な場合は(シンプルなforeachに比べると)処理に時間が掛かる危険があります。

C#プログラムの効率的な書き方

[VS2010]exeのバージョン表示で,リビジョンNoを自動インクリメントさせる

VisualStudio2010で作成したアプリには、バージョン番号を付与する事ができます。
アプリにバージョン番号を付与しておく事で、ユーザは自分が使用しているアプリが最新なのかを簡単に把握する事ができます。

このバージョン番号は、VisualStudio2010のデフォルトでは開発者が明示的に指定する事になりますが、場合によっては自動でインクリメントしてくれた方が便利な場合があります。

そこで、本記事では、バージョン番号を自動インクリメントさせる方法を説明します。
また、リビジョン番号を自動更新させるとuser.configの取り扱いで問題が出てくるため、この対処法も合わせて説明します。


exeのバージョンNoを自動インクリメントさせる


バージョン番号は4つの数字で構成されており、以下の構成をとります。

メジャーバージョン.マイナーバージョン.ビルド番号.リビジョン



このうち、自動更新が可能なのは、ビルド番号と、リビジョンのみです。
ビルド、リビジョン番号を自動更新させるには、以下の設定を行います。

VisualStudioのメニューより、プロジェクト->exeのプロパティを選択します。


アプリケーションタブの、アセンブリ情報ボタンをクリックします。


アセンブリバージョンの欄の3,4つ目を、”*”(アスタリスク)に変更します。
※下の画像では4つ目だけを”*”にしていますが、3つ目も”*”にしてください!!


これで、コンパイルを行うたびにリビジョン番号が更新されるようになります。


バージョンNoの付番ルール


この設定を行って何回かビルドしてみると、バージョン番号の増え方がちょっと変わっている事に気づきます。自動でバージョンNoをインクリメントすると、数字が1づつ増えるというわけではなく、一気に数字が増えていきます。
どんな規則で増えて行くか、気になったので調べてみると、http://msdn.microsoft.com/en-us/library/c405shex.aspxに説明がありました。

If you specify major and minor, you can specify an asterisk (*)for build.
This causes build to be equal to the number of days since January 1, 2000, local time, 
and revision to be equal to the number of seconds since midnight of the current day,
local time, divided by 2.
 
If you specify major, minor, and build, you can specify an asterisk for revision. 
This causes revision to be equal to the number of seconds since midnight of the current day, 
local time, divided by 2.



要は、以下のようなルールで決まるという事になります。

メジャーバージョン:手動指定のみ可
マイナーバージョン:手動指定のみ可
ビルド番号        :2000/1/1からの経過日数
リビジョン        :その日の00:00:00からの経過秒数を2で割った数
 
※時刻はlocal timeなので、GMTではなくJST基準です。



上記の事から分かる問題点としては、[assembly: AssemblyVersion( “1.0.0.*” )]という様に、ビルド番号を明示した上でリビジョンだけ可変にしてしまうと、日が変わったときにバージョン番号が戻ってしまいます。これでは、どのexeが最新バージョンか分からなくなってしまうので要注意です。



バージョンNoは自動インクリメントすべきか?


自動インクリメントを利用すると、バージョン番号の設定し忘れが無くなって基本的には便利なのですが、以下のようなデメリットもあるので、状況によっては使い分けが必要です。
(詳細は、http://msdn.microsoft.com/ja-jp/library/ms998223.aspxを見ると詳しいです。)

1.内部アセンブリビルド番号と、システムビルド番号にずれが発生してしまう。

2.ビルド番号、リビジョン番号が1づつ増えるわけではないので、ユーザが今利用しているexeと最新版との違い(最新版がどの程度バージョンアップされたものなのか)を把握しづらい。

3.ライブラリの作成時は、毎回バージョンが替わってしまうので、ライブラリを使用するクライアント側でアセンブリを厳密に名前指定している場合、クライアント側もリビルドする必要が出てくる。


単純なexeを作る場合は余り問題なさそうですが、DLL開発の時とかは検討が必要っぽいです。


バージョン間でuser.config情報を引き継がせる

他のハマりどころとしては、リビジョンNoを自動インクリメントさせていて、かつ、user.configを使用している場合、一旦保存したuser.configの情報が正しく取れなくなってきます。これは、user.configを保存するフォルダ名にバージョン名が含まれている為で、リビジョンが更新されるとuser.configの保存先フォルダが変わってしまうからです。


特に開発中はコンパイルを行うたびにリビジョンが替わってしまうので、実質的にuser.configに覚えさせた内容が意味を成さなくなってしまいます。

これを避けるには、バージョンが替わっても、旧リビジョン(バージョン)で保存したuser.configの内容を引き継がせるようにします。
方法は、以下のコードを組み込み、アプリケーションの起動時に走るようにしておきます。

//------------------------------------------
// アップグレードが必要か確認する
//------------------------------------------
if ( !Properties.Settings.Default.IsUpgrade ) {
	// 前バージョンの情報取得する
	Properties.Settings.Default.Upgrade();
 
	// アップグレードを行った事をセットする
	Properties.Settings.Default.IsUpgrade = true;
	Properties.Settings.Default.Save();
 
	Debug.Print( "設定ファイルのアップグレードが行われました" );
}



また、以下のようにIsUpgradeという項目をboolとしてuser.configに追加しておきます。
これは、二回目以降の起動で既にuser.configがアップグレード済みの時に、再度アップグレード処理が走るのを防ぐためです。



これによって、バージョンが替わったときでも、旧バージョンの設定を引き継いでくれます。
(app.configのフォルダは、新旧両方とも残ります)


プログラムからexeのバージョンを取得するには

上記の方法で設定したバージョン番号ですが、下記のコードでプログラムから取得できます。

System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();




“ファイルまたはアセンブリ ‘CrystalDecisions.CrystalReports.Engine … が読み込めません”エラーが出たときは


Windowsでプログラムを実行しているときに、CrystalDecisions.CrystalReports.Engineが無いという、以下のようなエラーダイアログが表示される場合があります。


Just-In-Time (JIT) デバッグを呼び出すための詳細については、
ダイアログ ボックスではなく、このメッセージの最後を参照してください。
 
************** 例外テキスト **************
System.IO.FileNotFoundException: ファイルまたはアセンブリ 'CrystalDecisions.CrystalReports.Engine, 
Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304'、またはその依存関係の 
1 つが読み込めませんでした。
指定されたファイルが見つかりません。ファイル名 'CrystalDecisions.CrystalReports.Engine, 
Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304' です。
   場所 ...
 
警告: アセンブリ バインドのログ記録がオフにされています。
アセンブリ バインドのエラー ログを有効にするには、レジストリ値 [HKLM\Software\Microsoft\Fusion!
EnableLog] (DWORD) を 1 に設定してください。
 
注意: アセンブリ バインドのエラー ログに関連するパフォーマンス ペナルティがあります。
この機能をオフにするには、レジストリ値 [HKLM\Software\Microsoft\Fusion!EnableLog] を削除します。





このエラーは何かというと、プログラムが内部で使用しているCrystalReportsのライブラリが使用しているパソコンにインストールされていない事を意味しています。
CrystalReportsというのは、プログラムから印刷を簡単に行うためのライブラリです。


このCrystalReportsの実行用ライブラリですが、無償でダウンロード可能です。

ダウンロードを行うためには、下記のサイトにアクセスします。
http://wiki.sdn.sap.com/wiki/pages/viewpage.action?pageId=56787567



次に、プログラム実行時に表示されたエラーメッセージより、どのバージョンのライブラリを取得すべきかを確認します。
前述の例だとメッセージ内に、”Version=13.0.2000.0″と表記されていますので、”CRVS2010″をダウンロードすればよいという事が分かります。


右の方にあるDownload Linkをクリックすれば、ダウンロードを行う事が可能です。

[C#]タスクトレイアイコンの画像を動的に変更する

Windowsでプログラムを作成する際、通常は画面(Form)を持つプログラムを作成する事が多いですが、簡単な監視や通知プログラムの場合タスクトレイに常駐させるプログラムを作成する事が有ります。

タスクトレイアプリを作成した場合、バルーンヘルプやアイコンをクリックしたときのメニューの他に、トレイのアイコンで状態を通知したい事が有ります。例えば、タスクマネージャはCPU負荷を表示してくれますし、一般的なメール監視アプリでは新着メール着信は、メールチェック中にアイコンイメージを変更する事が多いです。


そこで、今回はC#でタスクトレイアプリを作成時に、アイコンの画像を編集する方法を説明します。

サンプルでは現在のアイコン画像を取得した上で加工を行っていますが、本サンプルを応用すれば、複数の画像をあらかじめ用意してアニメーションさせるような事も可能です。


アイコン画像の編集方法

C#(VisualStudio)でタスクトレイのアイコンを表示させるには、NotifyIconコントロールを使用します。
今回は、以下のような感じで設定しました。
NotifyIconの仕様に付いてはこちらの記事を参照してください。


次に、アイコン画像を変更処理のメソッドを作成します。

下記のサンプルプログラムでは、既存のアイコン画像データをbmp形式で取得し、アイコン左上にドットを表示した上で再登録しています。TaskTrayIcon.Iconを直接編集したいところなのですが、Iconオブジェクトは編集できない仕様なのでやむなく一旦Bitmapオブジェクトに変換しています。

また、関数の最後でDestroyIcon()をコールしていますが、これについては後述します。

// アイコンリソースの破棄API
[System.Runtime.InteropServices.DllImport( "user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
 
//*********************************************************************
/// <summary> タスクトレイアイコンの画像を変更する
///            (アイコン左上にドットを表示)
/// </summary>
/// <param name="mode"> 0:赤色, 1:黒色</param>
//*********************************************************************
private void changeTrayIcon( int mode ) {
	Icon   curIcon = TaskTrayIcon.Icon;
	Bitmap curBmp  = TaskTrayIcon.Icon.ToBitmap();
 
	//-----------------------
	// ドットの色を決定する
	//-----------------------
	Color notifyColor = mode == 0 ? Color.Red : Color.Black;
 
	//-----------------------------------------------
	// アイコン左上にドットを表示させる(3x3ピクセル)
	//-----------------------------------------------
	for ( int x = 0; x < 3; x++ ) { 
		for ( int y = 0; y < 3; y++ ) { 
			curBmp.SetPixel( x, y, notifyColor );
		}
	}
 
	//-----------------------
	// アイコンを変更する
	//-----------------------
	Icon newIcon = Icon.FromHandle( curBmp.GetHicon() );
	TaskTrayIcon.Icon = newIcon;
 
	//------------------------------------
	// 変更前アイコンのリソースを破棄する
	//------------------------------------
	DestroyIcon( curIcon.Handle );
}







次に上記関数の呼び出し元を作成します。
今回はお試しなので、タイマーで周期的に点滅させるようにします。


イベントハンドラの処理は,以下のような感じです。

// 周期的にアイコン画像を変更する
int tmpVal = 0;
private void timer1_Tick( object sender, EventArgs e ) {
	tmpVal = tmpVal == 0 ? 1 : 0;
 
	changeTrayIcon( tmpVal );
 
}



これで、以下のようにアイコン画像を実行時に変更させる事が可能となりました。
ちょっと分かり辛いですが、アイコン右上のドットの色が変わってます。

↑ ↓


Iconオブジェクトのリソース開放漏れに注意

説明したchangeTrayIcon()関数ですが、最後にDestroyIcon()をコールしています。

これはMSDNの関数仕様にも明記されていて、コールしないとリソースの開放漏れが発生します。

このメソッドを使用する場合は、Win32 API の DestroyIcon メソッドを使用して
結果のアイコンを廃棄して、確実にリソースが解放されるようにする必要があります。


msdnのオンラインマニュアル より


もし、DestroyIcon()をコールしなかった場合、暫くは動作するのですが徐々にリソースがリークしていくので、長時間起動させておくと以下の例外が発生してしまいます。




System.Runtime.InteropServices.ExternalException はハンドルされませんでした。
  Message=GDI+ で汎用エラーが発生しました。
  Source=System.Drawing
  ErrorCode=-2147467259
  StackTrace:
       場所 System.Drawing.Bitmap.GetHicon()
  InnerException:




画像の更新頻度が低い場合は、開発/デバッグ中に発生させづらいバグなので特に注意が必要です。

Windowsダンプの極意 エラーが発生したら、まずダンプ解析

[C#]mmとtwipの相互変換を行う関数

CrystalReportsで帳票の開発などを行っていると、印字位置(Top,Left)をtwip単位で指定する必要があります。

プログラムによっては印字位置をユーザに指定させたい場合がありますが、その場合に画面上では通常mm単位で指定する事が多いのでmmとtwipの単位系で相互変換を行う必要があります。

単位の変換は、以下の関数で行う事ができます。

//*********************************************************************
/// <summary> mmの値をtwipに変換する
/// </summary>
/// <param name="mmValue">長さ(mm)</param>
/// <returns>             長さ(twip)</returns>
//*********************************************************************
private static int mmToTwip( int mmValue ) {
    return (int)(mmValue * 56.6929);
}
 
//*********************************************************************
/// <summary> twipの値をmmに変換する
56.6929で割る
/// </summary>
/// <param name="mmValue">長さ(twip)</param>
/// <returns>             長さ(mm)</returns>
//*********************************************************************
private static int twipToMm( int twipValue ) {
    return (int)(twipValue / 56.6929);
}



単位変換ですが1440twip = 1inchで、1inch = 25.4mmなので、それぞれ56.6929で掛けたり、割ったりすればOKです(1440/25.4=56.6929…なので)。

AmazonMWSで注文された商品のコンディション・コメントを取得する方法

本記事では、Amazonのマーケットプレース大口出品者が利用できるMarketplace WebService API(AmazonMWS)で、注文された商品のコンディション・コメントを取得する方法を説明します。
注文に対する納品書の発行システムを作成する際には、コンディションやコメントの取得が必要となります。


注文データの取得方法

AmazonMWSで注文された商品は、ListOrdersと、ListOrderItemsのAPIを使用して取得します。

ListOrders APIは注文の一覧を取得します。住所や合計金額は分かりますが、どの商品が購入されたかの内訳は本APIでは取得できません。商品明細は、ListOrderItems APIをコールする事で取得可能です。

ListOrderItemsでは、商品明細(SellerSKU,ASIN,Title等)を取得する事が可能となっています。ですが、残念ながら商品のコンディション・コメントまでは取得できません。

注文された商品のコンディション・コメントが欲しい場合は、予めダウンロードされた「出品詳細レポート」から出品者SKU(SellerSKU)をキーに、上記の情報を取得します。出品詳細レポートをMWSのAPIで取得する場合、RequestReport,GetReportのAPIを使用します。


RequestReport API

RequestReportは「出品詳細レポート」に限らず、大量の情報一覧をTSV形式のレポートとして取得可能なAPIです。RequestReportリクエストのAPIの呼び出し制限は30req/1時間となっています。

RequestReport APIでは、どの種類のレポートが欲しいかをReportTypeで指定します。ReportTypeとして指定可能なのは以下の5つです。

_GET_FLAT_FILE_OPEN_LISTINGS_DATA_
_GET_MERCHANT_LISTINGS_DATA_
_GET_MERCHANT_LISTINGS_DATA_LITE_
_GET_MERCHANT_LISTINGS_DATA_LITER_
_GET_MERCHANT_CANCELLED_LISTINGS_DATA_





各レポートの情報はTSV形式で取得できます。取得できる情報の概要とTSVの列一覧は以下の通りです。

_GET_FLAT_FILE_OPEN_LISTINGS_DATA_

商品の価格と数量の一覧

sku
asin
price
quantity





_GET_MERCHANT_LISTINGS_DATA_

最大50,000件までの詳細な出品中の商品レポート。

商品名
出品ID
出品者SKU
価格
数量
出品日
商品IDタイプ
コメント
コンディション
国外へ配送可
商品ID
在庫数
フルフィルメント・チャンネル





_GET_MERCHANT_LISTINGS_DATA_LITE_

在庫を持つ出品データの一覧(=出品数が1以上の商品一覧)。
50,000件以上出品している場合に使用可能。

出品者SKU
数量
価格
商品ID




_GET_MERCHANT_LISTINGS_DATA_LITER_

出品中商品のSKUと数量だけの一覧。
LITERの文字通り_GET_MERCHANT_LISTINGS_DATA_LITE_よりさらに軽い情報のみが取得できる。
50,000件以上出品している場合に使用可能

出品者SKU
数量




_GET_MERCHANT_CANCELLED_LISTINGS_DATA_

注文のキャンセルが行われた商品一覧。

商品名
出品者SKU
価格
数量
商品IDタイプ
コメント
コンディション
国外へ配送可
商品ID



上記の一覧から分かるように、商品のコンディション・コメントを取得する場合は、ReportTypeに_GET_MERCHANT_LISTINGS_DATA_を指定します。

データはリアルタイムではなくバッチで作成されるので、リクエストのレスポンスで上記の情報を取得する事はできません。
レスポンスでは、以下の2点をチェックします。
ReportProcessingStatusが_SUBMITTED_になっているか?
受け付けられた要求のReportRequestIdの値(後で使います)



レポートが作成されたかを確認する

RequestReport APIで依頼したレポートが、Amazon側で準備できたかをGetReportRequestList APIを使用して確認します。
パラメータとしてReportRequestIdを指定しますが、これはRequestReport APIのレスポンスとしてサーバからもらった値をそのままセットします。

レスポンスとして、ReportRequestInfoが返されるので、この値が_DONE_であれば、サーバ側でレポートの作成が完了した事になります。



作成されたレポートのレポートIDを取得する

レポートが作成された事が分かったので、早速ダウンロードしたいのですが、その前に作成されたレポートのIDを取得する必要があります。
これは、GetReportList APIをコールする事で取得可能です。
ReportRequestIdを渡してあげると、ReportIdを取得できます。


レポートIDを指定して、作成されたレポートをダウンロードする

実際のレポートは、GetReport APIで取得します。
パラメータとしてReportIdを指定します。(ReportRequestIdではないので注意)

結果として、TSV区切りのテキストが取得できます。

APIの呼び出し制限は60req/1時間です。


まとめ

というわけで、注文された商品のコメントを取得するためには複数のAPIをコールする必要があります。
呼び出すべきAPIの順序と、各APIの主だったリクエストキー、レスポンス情報をまとめると以下の流れになります。

もちろん、実際には他にも必要なリクエストKeyや応答項目が有りますし、APIによっては検索キーとして下記以外の項目を使用することも可能ですが、ここでは流れを分かりやすくするため省略しています。
詳細はAPI仕様書を参照してください。

ListOrders [注文一覧の取得]
    リクエストKey: 日付範囲etc
    レスポンスVal: AmazonOrderId
 
ListOrderItems [注文明細の取得]
    リクエストKey: AmazonOrderId
    レスポンスVal: SellerSKU
 
RequestReport [出品一覧詳細レポートの作成を依頼]
    リクエストKey: SellerSKU
    レスポンスVal: ReportRequestId
 
GetReportRequestList [レポート作成が完了したか]
    リクエストKey: ReportRequestId
    レスポンスVal: ReportRequestInfo
 
GetReportList [作成されたレポートのIDは何か]
    リクエストKey: ReportRequestId
    レスポンスVal: ReportId
 
GetReport [作成されたレポートの取得]
    リクエストKey: ReportId
    レスポンスVal: コメント、コンディションetcの情報



びっくりする事に、たかだかコメント/コンディション情報を取るだけの為に6つもAPIをコールする必要がありました。
せめて、SellerSKU指定で1品分の出品明細が取得できるシンプルなAPIが有れば便利なのに…と思うところです。


Amazonマーケットプレイス徹底活用

WordPressのタグクラウドで、文字の大きさを全て同じにする方法

WordPressではウィジェットを使用することで、タグクラウドを表示する事ができます。

標準では、タグの重要度に応じて文字の大きさが変更されるようになっていますが、設定を変更する事で、大きさの範囲を変えたり、全て同じ大きさにすることが可能です。


タグクラウドの文字サイズ変更方法

タグクラウドの設定は、WordPressのインストール先のwp-includesフォルダ内にあるcategory-template.phpファイルで定義されています。


wp_tag_cloud()関数内の$defaultsでsmallest,largestが指定されてます。
このsmallest,largestがタグクラウド内のフォントサイズです。


以下のように両方を同じ値に変更すれば、タグクラウド内の文字の大きさを全て同じにする事ができます。

変更前

function wp_tag_cloud( $args = '' ) {
    $defaults = array(
        'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 0,
        'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
        'topic_count_text_callback' => 'default_topic_count_text',
        'topic_count_scale_callback' => 'default_topic_count_scale', 'filter' => 1,
    );
 
    ...


  ↓

変更後

function wp_tag_cloud( $args = '' ) {
    $defaults = array(
        'smallest' => 8, 'largest' => 8, 'unit' => 'pt', 'number' => 0,
        'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
        'topic_count_text_callback' => 'default_topic_count_text',
        'topic_count_scale_callback' => 'default_topic_count_scale', 'filter' => 1,
    );




また、以下のように変更すれば文字サイズは変更されるけども、変更の幅を小さくする事ができます。

'smallest' => 8, 'largest' => 12




483994105X
WordPress 3.x デザイン&カスタマイズ スタイルブック


4883377830
WordPressデザインブック3.x対応

[Amazonマケプレ]FBAで販売不可品のNG理由を確認する方法

Amazonマーケットプレースで商品を出品時で、在庫をFBA管理している場合、商品の状態によってはAmazonの判断で販売不可とされてしまう場合があります。

販売不可と判断された商品が存在するかは、メニューの在庫→FBA在庫管理からアクセスできるFBA在庫一覧ページ確認できます。
(販売不可/発送不可の列タイトルをクリックし、並び替えを行うと探しやすいです)

以下のように販売不可/発送不可に値が入っている場合は、販売対象外にされています。



この販売不可品ですが、なぜ販売不可になったかの理由は以下の手順で確認できます。

販売不可品に対する理由の確認方法

メニューより、レポート→フルフィルメントを選択します。


Amazonフルフィルメントレポートのページより、返送推奨レポートをクリックします。


一覧のコンディション欄に、販売不可の理由が表示されています。



販売不可の理由ですが、ほとんどの場合は”商品情報がありません”と表示されます。
商品情報がありませんというはどんな状況なのかという話になりますが、これはAmazonに問い合わせたところ、以下の返答を頂きました。

販売可能な在庫が存在しない状況ということです。
この商品は、XXXXのコンディションで出品しておりますが、注文番号: XXX-XXXXXXX-XXXXXXX にて注文が入り
返品となった際に、『XXXXXXXXXXXXXXXXX』という理由にて返品となっております。
 
購入者の返品理由に基づいて返送後に再販可能商品か、不可能商品かを判断いたします。
購入者の返品理由により現在『販売不可』在庫として在庫が計上されておりますので、手元に返送を行うか、
破棄を行うかしていただきますようお願いいたします。


つまり、コンディション違い等の理由に伴う、お客様からのクレームによって返品が行われ、結果として再販不可な状態となっているものです。
返品理由が、”注文した商品を間違えた”等の場合は自動的に再販可能となりますが、コメント欄に”書き込みなし”と記載したのにも関わらず書き込みが有った等が理由だった場合はAmazon側ではどうがんばっても再販できないので、販売不可のステータスになります。


購入者から提示された返品理由の確認方法ですが、こちらもAmazonに確認方法を問合せてみたところ下記の回答でしたので、都度ケース管理のページより問合せを行う必要があります。

現状は下記のような返品時のコメントそのものは出品者様側の機能ではご確認いただく事ができない部分のため、
詳細は当サイトにお問い合わせをいただけないとわからない状況でございます。
 
[中略]
 
出品者様側の利用可能な機能ですと、レポートタブの「フルフィルメント」にございます『返品レポート』にて
大まかな理由が確認できるのみとなっております。




販売不可となった商品は、そのままでは保管料だけが掛かり続けてしまうので、返送か破棄の手続きをする必要があります。
次は、返品・破棄を行う方法を説明します。

販売不可品の返品・破棄を行う方法


手続きを行うには先ほどのページにあった、「返送(または所有権の破棄)依頼を開始」をクリックします。



依頼内容のページで、返品・破棄を選択します。
返品の場合は、返品先を指定します。




破棄を選択した場合は、以下の画面に遷移し”内容を確定”をクリックする事で破棄を行う事ができます。



破棄に伴う費用は以前は無料でしたが、現在は有料で下記の金額が掛かります。

返送または所有権の放棄  小型・標準サイズ    大型サイズ
返送           50円           100円
所有権の放棄       10円           20円




ムダをなくして利益を生み出す在庫管理
Amazonマーケットプレイス徹底活用

[WP]コメント入力欄の”Spam Protection by WP-SpamFree”を非表示にする方法

WordPressで、WP-SpamFreeプラグインを使用すると、コメント入力欄の下に”Spam Protection by WP-SpamFree”というメッセージが表示されます。
これを非表示にするには、以下の設定を変更すればOKです。


WordPressの管理画面に入り、プラグイン->WP-SpamFree を選択します。



「Help promote WP-SpamFree?」のチェックを外し、”Update Options”のボタンをクリックします。



チェックボックスの説明どおり、これを外す事で”Spam Protection by WP-SpamFree”のリンクが削除され、非表示になります。

This places a small link under the comments and contact form, 
letting others know what's blocking spam on your blog.
 
コメントと問い合わせフォームの下に小さいリンクを表示し、
このブログがスパムをブロックしている事を読者に知らせます。




爆笑テストの珍解答500連発!!
ジワジワ来る○○

GetASFStreamで,録音時にMediaPlayerが表示されるのを回避する

GetASFStreamを使用すると、ストリーミング放送されている音声・動画をファイルに保存できます。
とても便利なソフトですが、デフォルトの設定内容だと録画予約を行うと、録画中にWindows Media Playerの画面が表示されてしまいちょっと不便です。

こんな場合は、以下の設定を行っておくとMediaPlayerが表示されるのを回避することができます。



メニューより、共通設定→DL詳細設定を選択します。



共通設定タブの”MyPlayerを使用する”のチェックを外します。



これで、録画予約時もMedia Playerが表示されなくなります。
ダウンロード大百科 世界中のファイルを根こそぎGet!

[VS2010]データセット作成時、xscファイルで「DataSetUISetting要素が宣言されていません」警告が表示される



VisualStudioのデータセット作成でxsdファイルを作成した際に、自動生成されるxscファイルで以下の警告が表示される場合があります。

'urn:schemas-microsoft-com:xml-msdatasource:DataSetUISetting' 要素が宣言されていません。



この警告は、開発者側の問題ではなく、VisualStudioが自動生成するxscファイルに不備があるのが原因なので、無視しても構いません。


関連情報:
ado.net – Warning in XML Editor on Typed DataSet “.XSC” File – Stack Overflow
Problem Creating Dataset
Problem with VS DataSet designer

XMLスキーマ書法

[PHP]mb_str_split: 指定した文字数で,文字列を分割する(全角文字対応版)

指定された文字列を指定した文字数単位で分割し、配列として返す関数を作成しました。

ここでいう「文字数」はbyte数ではないので注意してください。
例えば”あいうえお”は、10ではなく5とカウントします。

function mb_str_split( $inStr, $length ) {
    $outArray = array();
 
    // パラメータチェック
    if ( $length < 1 ) {
        return FALSE;
    }
 
    for ( $offset = 0; $offset < mb_strlen( $inStr, 'SJIS' ); $offset += $length ) {
        $outArray[] = mb_substr( $inStr, $offset, $length );
    }
 
    return $outArray;
}



ちなみに全角文字チェックは行っていますが、禁則処理には対応していません。
この為、行頭に「。」、「々」、「っ」などが出てくる可能性が有ります。

[C#]指定した幅(byte数)で文字列を分割する(全角文字対応版)

指定された文字列を指定したbyte数単位で分割し、結果を配列として返す関数です。
byte数は、SJISとして解釈した場合での計算となります。

本関数は、phpで言うところのマルチバイト対応版str_split()関数のようなものです。

//*********************************************************************
/// <summary>文字列を指定した文字数単位で分割する(全角文字考慮)
/// </summary>
/// <param name="inStr">  分割前文字列</param>
/// <param name="length"> 1行の長さ</param>
/// <returns>             分割後文字列の配列</returns>
//*********************************************************************
private string[] mbStrSplit( string inStr, int length ) {
    List<string> outArray = new List<string>(); // 分割結果の保存領域
    string       outStr   = "";                 // 現在処理中の分割後文字列
    Encoding     enc      = Encoding.GetEncoding("Shift_JIS");
 
 
    // パラメータチェック
    if ( inStr == null || length < 1 ) {
        return outArray.ToArray();
    }
 
    //--------------------------------------
    // 全ての文字を処理するまで繰り返し
    //--------------------------------------
    for ( int offset = 0; offset < inStr.Length ; offset++ ) {
        //----------------------------------------------------------
        // 今回処理する文字と、その文字を含めた分割後文字列長を取得
        //----------------------------------------------------------
        string curStr         = inStr[offset].ToString();
        int    curTotalLength = enc.GetByteCount( outStr ) + enc.GetByteCount( curStr );
 
        //-------------------------------------
        // この文字が、分割点になるかチェック
        //-------------------------------------
        if ( curTotalLength == length ) {
            // 処理中の文字を含めると、ちょうどピッタリ
            outArray.Add( outStr + curStr );
            outStr = "";
        } else if ( curTotalLength > length ) {
            // 処理中の文字を含めると、あふれる
            outArray.Add( outStr );
            outStr = curStr;
        } else {
            // 処理中の文字を含めてもまだ余裕あり
            outStr += curStr;
        }
    }
 
    // 最後の行の文を追加する
    if ( !outStr.Equals( "" ) ) {
        outArray.Add( outStr );
    }
 
    // 分割後データを配列に変換して返す
    return outArray.ToArray();
}




ちなみに全角文字チェックは行っていますが、禁則処理には対応していません。
この為、行頭に「。」、「々」、「っ」などが出てくる可能性が有ります。

[C#]未停止のbackgroundWorkerオブジェクトを調べる方法

以前に、未停止のbackgroundWorkerが存在する場合に、プログラムを終了させようとしても終了しない状況が発生する事について説明しました。
 参考:プログラム中でApplication.Exit();を実行しても、プログラムが終了しない



今回は、もしこの状態に陥った時、どのbackgroundWorkerオブジェクトが動き続けているかを調べる方法について説明します。
ちなみに今回説明している内容はVisualStudio2010 Professionalエディションで確認しています。Expressだとひょっとしたらメニューが無いかもしれません…


Ctrl + Alt +Breakキーを押し、プログラムの実行を一時中断させます。


VisualStudioのツールバーを右クリックし、”デバッグの場所”を選択します。


表示されたバーのスレッドより、”ワーカースレッド”と記載されたものを選択します。
これで、問題を起こしているスレッドにアクセスできます。


その後、メソッドの呼び出し履歴を見ると、このスレッドの呼び出し元(backgroundWorkerの呼び元クラス名)が分かります。





二章で、マルチスレッドアプリケーションの設計に関わる知識について紹介されています。

4839930422
C# .NETアプリケーション開発 徹底攻略 C# 3.0/.NET Framework 3.5対応