C#|突然Twitterに投稿出来なくなった

 日頃から愛用しているコマンド入力型のアプリケーションランチャーから呼び出せる様にC#で書いたTwitterのステータス投稿プログラムが、

ハンドルされていない例外: System.Net.WebException: リモート サーバーがエラーを返しました: (417) Expectation Failed

とか吐いて使えなくなった。

 今までは期待どうりステータスを投稿出来ていたのに…。困りました。

using System;

using System.Collections.Specialized;

using System.Net;

using System.Text;

class Program {

static void Main(string[] args) {

WebClient client = new WebClient();

client.Encoding = Encoding.UTF8;

client.Credentials = new NetworkCredential(args[0], args[1]);

NameValueCollection nvc = new NameValueCollection();

nvc.Add("status", args[2]);

byte[] res = client.UploadValues("http://twitter.com/statuses/update.xml", nvc);

string resStr = Encoding.UTF8.GetString(res);

client.Dispose();

Console.WriteLine(resStr);

}

}

C#|TwitterのAPIを叩くライブラリを作ってみた2

 ここまで出来ましたよ~って感じの進捗報告のつもりでUP

TwitterClient.zip

 少しは使えるようになって来たと思います。Webから色々引っ張ってくるときの作法とか良く知らないので、動いてはいるけど正しいかは自信が無いです。

 まだテストしてないところとか、ちゃんと動かない部分とかコメント付けてるので、利用前に必ず確認、修正して下さいね。

 こんな汚いコード読めねぇよ!って人の為にヒント

using System;
using System.Collections.Generic;
using System.Linq;
using Anis.Twitter.Api;
class Program {
  static void Main(string[] args) {
    Methods twitterClient = new Methods("ユーザーID", "パスワード");
    var timeLine = from status in twitterClient.GetFriendsTimeline()
                    orderby status.Id
                    select status;
    foreach(var status in timeLine) {
      Console.WriteLine("{0}\t{1}\t{2}\n\t{3}",
        status.User.Screen_name,
        status.Created_at,
        status.Id,
        status.Text);
    }</p>
  }</p>
}</p>

こんなに簡単にタイムライン取ってこれるんですよ。

C#|TwitterのAPIを叩くライブラリを作ってみた

 Twitter始めました。Twitterの先輩がいましたら是非是非followして下さい。

http://twitter.com/anis774

TwitterはWebAPIを公開しているとのことで、それを利用したクライアントも多数あります。その中でもJavaで実装されたPeraPeraPrvが気に入ったので導入しました。

でもやっぱり、サンデーヘボグラマなら自分で作ってみたくなりますよね。さらに楽して作りたいとも思う筈です。面倒なことはしたくないですよね。

そこでライブラリを探したところ、

http://devblog.yedda.com/index.php/twitter-c-library/

こんなのを見付けました。なんだ英語じゃないですか。英語怖いよ、英語怖い。でも恐る恐るDLしてソースを読んでみると、読めるじゃないですか。英語は読めないけどC#は読めるって当たり前の話でした。短いソースコードだったのでさらっと読んで…捨てました。オプションの引数の指定とか全く出来ないんですもん。サンプルとしては参考になるのでしょうけど、そのまま実用にはなりませんね。実はサンプルなのかも知れませんが…、英語読めないから分かりません。

やはり自分で書くしかないと…。書きました。ここを参考にしました。

http://watcher.moe-nifty.com/memo/docs/twitterAPI13.txt

ここの『ステータス関連のAPI』の実装が出来たので、実際に動くサンプルのビューアと、コマンド形式のランチャから呼び出して使える投稿プログラムを書いて見ました。

疲れたのでひとまず公開します。何の反響も無ければこれで終わりにします。反響があれば少しだけやる気が出るかも。むしろ誰かが完成させて公開してくれると嬉しいかも。そう言う意味で、恥ずかしいけどソース付きです。

煮るなり焼くなり好きにして下さい。

TwitterClient.zip

VB.NET|任意のタイミングでキーボードの状態を取得

 フレームごとに計算をするゲームのプログラムなんかだと、イベント発生時以外にキーボードの状態を取得したいと思うでしょう。

 そこで通常ならDirectInputを使うのでしょうが、あえて使わないで解決してみようと書いたコードがこれ。今回はVB2005です。

Imports System.Windows.Forms

Module KeysState

    Dim keysState As New Dictionary(Of Keys, List(Of Boolean))

    ''' <summary>
    ''' 毎フレーム呼び出す
    ''' </summary>
    Public Sub UpDate()
        For Each key As Keys In keysState.Keys
            keysState(key).RemoveAt(1)
            keysState(key).Add(keysState(key)(0))
        Next
    End Sub

    ''' <summary>
    ''' キーが押し始められたかを取得
    ''' </summary>
    ''' <param name="key">押し始められたかどうかを取得するキー</param>
    ''' <returns>押し始められていたらTrue、押し始められていなければFalse</returns>
    Public Function IsPush(ByVal key As Keys) As Boolean
        Return keysState.ContainsKey(key) AndAlso Not keysState(key)(1) AndAlso keysState(key)(2)
    End Function

    ''' <summary>
    ''' キーが押されているか取得
    ''' </summary>
    ''' <param name="key">押されているかどうかを取得するキー</param>
    ''' <returns>押されていたらTrue、押されていなければFalse</returns>
    Public Function IsPress(ByVal key As Keys) As Boolean
        Return keysState(key)(0)
    End Function

    ''' <summary>
    ''' キーが離されたかを取得
    ''' </summary>
    ''' <param name="key">離されたかどうかを取得するキー</param>
    ''' <returns>離されたらTrue、離されていなければFalse</returns>
    Public Function IsUp(ByVal key As Keys) As Boolean
        Return keysState.ContainsKey(key) AndAlso keysState(key)(1) AndAlso Not keysState(key)(2)
    End Function

    ''' <summary>
    ''' 対象のコントロールのKeyDownイベントハンドラに追加する
    ''' </summary>
    Public Sub KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
        If keysState.ContainsKey(e.KeyCode) Then
            keysState(e.KeyCode)(0) = True
        Else
            keysState.Add(e.KeyCode, New List(Of Boolean)(New Boolean() {True, False, False}))
        End If
    End Sub

    ''' <summary>
    ''' 対象のコントロールのKeyUpイベントハンドラに追加する
    ''' </summary>
    Public Sub KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs)
        If keysState.ContainsKey(e.KeyCode) Then
            keysState(e.KeyCode)(0) = False
        Else
            keysState.Add(e.KeyCode, New List(Of Boolean)(New Boolean() {False, False, False}))
        End If
    End Sub
End Module

C#|テキストボックスのサイズを内容に合わせて変更

 ググるとSystem.Drawing.Graphics.MeasureString()を用いた方法がHITしますが、これでは誤差が出るので悩んでいる人を掲示板のログ等で見かけます。

 僕も同じことをやろうとして調べてみたのですが、

System.Windows.Forms.TextRenderer.MeasureText()メソッドを用いると誤差なく描画サイズの取得が出来ました。

C#|Brainf*ckの処理系を書いてみた。

 唐突ですが、ちょっとやってみたくなったんです。

 まずはインタプリタ

using System;

using System.Collections.Generic;

using System.IO;

using System.Text;

class Program {

    static void Main(string[] args) {

        if(args.Length == 0) {

            Console.WriteLine("ソースファイルを指定して下さい。");

            return;

        }

        int memorySize = 256/**************************************************
                              *BrainFuckコードの実行に割り当てるメモリーサイズ。*
                              *実行するコードに対して充分な大きさが必要。       *
                              **************************************************/

        //ヘルプの表示

        if(args[0].ToLower().Contains("help") || args[0].ToLower().Contains("?")) {

            Console.WriteLine(

@"bfi [ドライブ:][パス]ファイル名[メモリサイズ]

メモリサイズ    プログラム実行の為に確保するメモリのサイズです。充分なサイズを指定して下さい。
                大き過ぎても落ちるかも…。規定値は256。");

            Console.ReadLine();

            return;

        }

        //ソースファイルの読み込み*/

        string src;

        string srcFile = Environment.CurrentDirectory + "\\" + args[0];

        if(File.Exists(args[0])) {

            srcFile = args[0];

        } else if(!File.Exists(srcFile)) {

            Console.WriteLine("ソースファイルがありません。");

            return;

        }

        using(System.IO.StreamReader sr = new System.IO.StreamReader(srcFile, Encoding.GetEncoding("Shift-Jis"))) {

            src = sr.ReadToEnd();

            sr.Close();

        }

        //コマンドラインオプションパーサ

        if(args.Length > 1) {

            if(!int.TryParse(args[1], out memorySize)) {

                Console.WriteLine("メモリサイズの指定が正しくありません。");

                return;

            }

        }

        brainFuck(src, memorySize);

#if DEBUG

        while(true) {

            Console.ReadLine();

        }

#endif

    }

    unsafe static void brainFuck(string src, int memorySize) {

        /*メモリーの確保と初期化*/

        byte* point = stackalloc byte[memorySize];

        byte* tmp = point;

        for(int i = 0; i < memorySize; i++) {

            *(tmp + i) = 0;

        }

        //実行

        for(int i = 0; i < src.Length; i++) {

            switch(src[i]) {

            case '>':

                point++;

                break;

            case '<':

                point--;

                break;

            case '+':

                (*point)++;

                break;

            case '-':

                (*point)--;

                break;

            case '.':

                Console.Write*1;

                break;

            case ',':

                *point = (byte)(Console.Read());

                break;

            case '[':

                if(*point == 0) {

                    i = kakko(src, i);

                }

                break;

            case ']':

                if(*point != 0) {

                    i = kakko(src, i);

                }

                break;

            }

        }

    }

    static int kakko(string src, int index) {

        int nest = 0;

        bool flag = src[index] == '[';

        for(int i = index; flag ? i < src.Length : i >= 0; i = i + (flag ? 1 : -1)) {

            if(src[i] == '[') nest++;

            else if(src[i] == ']') nest--;

            if(nest == 0return i;

        }

        return -1;

    }

}

 unsafeでポインタ使ってみました。C#だとわかるんですよね、何故か。なのにCでポインタ使って書くと動かないのは何故なんでしょう…。

 素直に配列使ってもそんなに速度変わらなかったりして、試して無いけど。List<byte>とか使えばメモリの指定が要らなくなってより安心して使えるかも知れないですね。

 次にコンパイラ

using System;

using System.CodeDom.Compiler;

using System.IO;

using System.Text;

using Microsoft.CSharp;

namespace Brainfuckコンパイラ {

    class Program {

        static void Main(string[] args) {

            if(args.Length == 0) {

                Console.WriteLine("ソースファイルを指定して下さい。");

                return;

            }

            int memorySize = 256/**************************************************
                                  *BrainFuckコードの実行に割り当てるメモリーサイズ。*
                                  *実行するコードに対して充分な大きさが必要。       *
                                  **************************************************/

            //ヘルプの表示

            if(args[0].ToLower().Contains("help") || args[0].ToLower().Contains("?")) {

                Console.WriteLine(

    @"bfi [ドライブ:][パス]ファイル名 [メモリサイズ]

メモリサイズ    プログラム実行の為に確保するメモリのサイズです。充分なサイズを指定して下さい。
                大き過ぎても落ちるかも…。規定値は256。");

                Console.ReadLine();

                return;

            }

            //ソースファイルの読み込み*/

            string src;

            string srcFile = Environment.CurrentDirectory + "\\" + args[0];

            if(File.Exists(args[0])) {

                srcFile = args[0];

            } else if(!File.Exists(srcFile)) {

                Console.WriteLine("ソースファイルがありません。");

                return;

            }

            using(System.IO.StreamReader sr = new System.IO.StreamReader(srcFile, Encoding.GetEncoding("Shift-Jis"))) {

                src = sr.ReadToEnd();

                sr.Close();

            }

            //コマンドラインオプションパーサ

            if(args.Length > 1) {

                if(!int.TryParse(args[1], out memorySize)) {

                    Console.WriteLine("メモリサイズの指定が正しくありません。");

                    return;

                }

            }

            brainFuck(src, memorySize,srcFile);

#if DEBUG

            while(true) {

                Console.ReadLine();

            }

#endif

        }

        static void brainFuck(string src, int memorySize,string srcFile) {

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("using System;");

            sb.AppendLine("class C{");

            sb.AppendLine(  "unsafe static void Main(){");

            sb.AppendLine(      "int memorySize = " + memorySize.ToString() + ";");

            sb.AppendLine(      "byte* point = stackalloc byte[memorySize];");

            sb.AppendLine(      "byte* tmp = point;");

            sb.AppendLine(      "for(int i = 0; i < memorySize; i++)*(tmp + i) = 0;");

            for(int i = 0; i < src.Length; i++) {

                switch(src[i]) {

                case '>':

                    sb.Append("point++;");

                    break;

                case '<':

                    sb.Append("point--;");

                    break;

                case '+':

                    sb.Append("(*point)++;");

                    break;

                case '-':

                    sb.Append("(*point)--;");

                    break;

                case '.':

                    sb.Append("Console.Write*2;");

                    break;

                case ',':

                    sb.Append("*point = (byte)(Console.Read());");

                    break;

                case '[':

                    sb.Append("while(*point != 0){");

                    break;

                case ']':

                    sb.Append("}");

                    break;

                }

            } 

            sb.Append("}}");

            CompilerParameters param = new CompilerParameters();

            param.OutputAssembly = Path.GetFileNameWithoutExtension(srcFile) + ".exe";

            param.GenerateExecutable = true;

            param.CompilerOptions += " /unsafe";

            CompilerResults rs = new CSharpCodeProvider().CompileAssemblyFromSource(param, sb.ToString());

            foreach(string str in rs.Output) {

                Console.WriteLine(str);

            }

        }

    }

}

 コンパイラだなんて言ってカッコつけてますけど、中身はBrainf*ck→C#のトランスレータです。これをC#としてコンパイルさせてるだけです。

 やっぱインタプリタとは速度が段違いです。

 次はWhitespaceの処理系に挑戦してみようかと思っているのですが、僕にもわかるような言語仕様の説明が見付かりません。本家サイトは英語だし…。英語読めたらなぁ。努力はしませんけどね。

 うわぁ、読みにくいですね。

 ソースコードをHTMLに整形するツールを使ってみたのですが、ブログのスタイルシートが干渉して行間が…。

 やっぱ今まで通りソースファイルをそのままアップした方がよさそうですね。

*1char)(*point

*2:char)(*point

C#|二重起動を禁止して、コマンドライン引数を取得

 ”C# 二重起動 禁止”等で検索するとMutexを使った方法を紹介したページがヒットしますが、これでは後から起動されようとしたインスタンスのコマンドライン引数を取得出来ません。

 自分で、既に起動済みのインスタンスにコマンドラインを渡して、受け側で処理する様に実装しなければいけません。これでは面倒です。VB.NET 2005では簡単に二重起動を禁止して、引数も取得出来ました。

 同じクラスライブラリなのだから、VBに出来てC#に出来ない筈は無いと考え、調べてみました。下準備をすればVBと同じ方法で二重起動を禁止し、引数も取得出来ることがわかりました。以下にその方法を紹介します。

まず、”Microsoft.VisualBasic”をプロジェクトの参照に追加します。

そして、次の様にクラスを書きます。

using System.IO;
using Microsoft.VisualBasic.ApplicationServices;
class myApplication:WindowsFormsApplicationBase{
  public myApplication()
    : base() {
    this.EnableVisualStyles = true;
    this.IsSingleInstance = true;
    this.MainForm = new Form1();//スタートアップフォームを設定
    this.StartupNextInstance += new StartupNextInstanceEventHandler(myApplication_StartupNextInstance);
  }
   void myApplication_StartupNextInstance(object sender, StartupNextInstanceEventArgs e) {
    //ここに二重起動されたときの処理を書く
    //e.CommandLineでコマンドライン引数を取得出来る
  }
}

myApplication_StartupNextInstanceメソッドの中には、VB.NETの方法の時と同じ様にコーディング出来ます。詳しくは検索すればわかりやすいページがあるでしょう。

次に、プログラムのエントリポイントを書き換えます。

using System;
static class Program {
  [STAThread]
  static void Main(string[] args) {
    //Application.EnableVisualStyles();
    //Application.SetCompatibleTextRenderingDefault(false);
    //Application.Run(new Form1());
    myApplication winAppBase = new myApplication();
    winAppBase.Run(args);
  }
}

 こんなに簡単な方法があるのに、検索しても紹介されているのを見たことがありません。この方法に何か問題があるのかも知れませんね。

 知っている方がいましたらコメント下さい。

C#|axWindowsMediaPlayer

 axWindowsMediaPlayerの使い方をググっても情報が少なかったのでメモします。

【準備】

参照設定する。

ツールボックスで右クリック、アイテムの選択

COMコンポーネントタブをクリック

Windows Media Playerをチェック

これでツールボックスにWindows Media Playerが追加されるのでフォームに貼り付ける。

【フォームデザイナでプロパティ設定】

Ctlenabled falseにするとボタン操作が無効になる

stretchToFit 動画、画像がウィンドウのサイズに合わせて変わる。

uiMode none ボタンが表示されない。UIをお好みで実装するならこれ。

    full ボタンが表示される。WMPそのまんま。お手軽。

    invisible 表示されないって意味らしい。設定したら表示が大変なことになった。オーディオ専用ならこれか、Visible = falseでいい気がするけど。

    他に何かあったら教えて下さい。

URL 再生するファイルのパスを渡すとロードして再生の準備をする。settings.autoStart = true なら再生を開始する(既定ではfalseみたい)。

windowlessVideo trueにすると動画が表示されない。用途がわからない。

【メソッドとかプロパティとか】

Ctlcontrols.play() 再生。

Ctlcontrols.stop() 停止。

Ctlcontrols.pause() 一時停止。

Ctlcontrols.fastReverse() 早戻し、出来ないファイル形式があるみたい。

Ctlcontrols.fastForward() 早送り、上に同じ。

Ctlcontrols.currentPosition 再生位置、秒数。

Ctlcontrols.currentPositionString 再生位置、mm:ssの形式。

settings.volume = 0~100 ボリューム

settings.balance = -50~50 左右のバランス

settings.mute 消音。えってぃ動画とか見るなら必須。

status 準備完了とか一時停止とか表示されるあれ。StatusChangeイベントで更新してやるといいみたい。

currentMedia.duration 再生中のファイルの総時間。

他はよくわからなかった。

【シークバーを実装してみる】

 再生位置を更新するイベントがいくら探しても見付かりません。どうやら無い様です。Windows.Forms.Timerを使って定期的に更新することにします。スライドにはTrackBarを使います。

 再生開始したらTimerをStart()する。Intervalは既定の100でいいと思います。Windous Madia PlayerのPlayStateChengeイベントが使えるかも。currentMedia.durationでファイルの長さが得られるのでintにキャストしてTrackBarのMaxValueにセット。

 TimerのTickイベントでCtlcontrols.currentPositionをintにキャストしてTrackBarのValueにセット

 これで再生時間が刻々と更新されます。

 後はTrackBarの操作で再生位置を操作しましょう。

 TrackBarのScrollイベントでTrackBarのValueをdoubleにキャストしてCtlcontrols.currentPositionにセット。

 これだけじゃエレガントに動かないので、操作中は更新を止めましょう。

 TrackBarのMouseDownイベントでTimerをStop()。MouseUpイベントでStart()するとエレガントに動くようになりました。

 以上、WindowsMediaPlayer弄りメモでした。他にも情報がありましたら教えて下さい。

C#|VC#2008

 昨晩、Visual C# 2008 Expess Editionをインストールしました。少し弄ってみたのですが、IDEの使い勝手は変わりません。

 と、思ったのですが、ヘルプの起動が速くなっています。2005だと待てど暮らせどヘルプが出なかったのに、2008になってサクッと出るようになりました。

 エディタはどんなもんよ?と思いFizzBuzzしたら物凄い新機能を発見しました。インテリセンス表示中にCtrlを押すと、インテリセンスの選択メニューが透けるんです!その下のコードが見えるんです!これだけでも乗り換える価値があります。

 一番の目玉らしい、LINQとか匿名なんたらとかのC#3.0構文についてもグーグルで調べてみました。なんというか、キモいです。キモぅいです。コードの見た目からして変態臭を漂わせてます。こんなの僕に使いこなせる訳がありません。

 VBとVC++も2008にしようかしら。