Visual Studio Community 2013始めました。

Visual Studio Community 2013が出ましたね。Expressでは使えなかった拡張が使えるようになりました。これのためにProの購入を考えては踏み止まって、ということを繰り返していたところなのでやっと来たかという感じ。

真っ先に入れたのがVsVim。お仕事ではPHPStorm + ideavimなので、この環境に慣れ切った指で素のVSでC#を書くのはちょっと腰が重かったのです。

Ctrl+n、Ctrl+pを上下に割り当てて、インテリセンスの選択もカーソルを使わないようにしているのですが、Ctrlを押しているとインテリセンスが半透明になってしまうのが邪魔になっていて回避策を模索中。この機能が付いた当時はとても嬉しかったんですけどね。

あとはPython Tools for Visual Studio。まだしっかりとは試せていないのですが、ClipboardExtenderの拡張スクリプト(IronPython)を書くのが捗りそうです。

MSさん超GJです。

MetroスタイルアプリでUser-Agentを指定しつつクッキーも使ってHTTP通信したい

※この記事はWindows8RPについて書いていますがわかりません。当然今後のことも本当のところも分かりません。

User-Agent指定してダウンロードするコード

using System.Net.Http;
using System.Threading.Tasks;

static class Connection
{
    public static async Task<string> Get(string url)
    {
        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("User-Agent", "Hogezilla");
            return await client.GetStringAsync(url);
        }
    }
}

 

とっても簡単です。でもこれクッキー使えないんですよね。

そこで、クッキー使えそうなコード。

using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;

static class Connection
{
	static CookieContainer cookies = new CookieContainer();
	static Encoding enc = Encoding.GetEncoding("Shift-Jis");
	public static async Task<string> Get(string url)
	{
		HttpWebRequest req = HttpWebRequest.CreateHttp(url);
		req.CookieContainer = cookies;
		req.UserAgent = "Hogezilla"; //←そんなプロパティねーよって怒られる
		req.Headers.Add("User-Agent", "Hogezilla"); //←そんなメソッドねーよって怒られる

		using (WebResponse res = await req.GetResponseAsync())
		using(Stream resStream = res.GetResponseStream())
		{
			byte[] resBytes = new byte[res.ContentLength];
			await resStream.ReadAsync(resBytes, 0, resBytes.Length);
			return enc.GetString(resBytes, 0, resBytes.Length);
		}
	}
}

 

確かにここを見るとUser-AgentヘッダーはHeadersプロパティから変えられないからUserAgentプロパティから変更しろって書いてるんだけどなー。

WinRTの時だけ違う方法があるのだろうか。かれこれ数日間悩んでるんで、上手く書けたらアウトプットしますよ。

 

ってことで数日悩んでやっと出来ました。HttpClientHandlerクラスが鍵でしたね。

using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

static class Connection
{
	static CookieContainer cookies = new CookieContainer();
	public static async Task<string> Get2(string url)
	{
		using (var handler = new HttpClientHandler())
		using (var client = new HttpClient(handler))
		{
			handler.CookieContainer = cookies;
			client.DefaultRequestHeaders.Add("User-Agent", "Hogezilla");
			return await client.GetStringAsync(url);
		}
	}
}

 

TwitterizerでUserStreamを利用する

TwitterのAPIライブラリ、Twitterizer Ver 2.3.1を使ってUserStreamを利用しようと以下のコードを書いたんです。

using System;
using System.Net;
using System.Reflection;

namespace ConsoleApplication1
{
	class Program
	{
		static void Main(string[] args)
		{
			string consumerKey = "hoge";
			string consumerSecret = "hogehoge";
			Twitterizer.OAuthTokenResponse reqToken = Twitterizer.OAuthUtility.GetRequestToken(consumerKey, consumerSecret, "oob");
			Uri uri = Twitterizer.OAuthUtility.BuildAuthorizationUri(reqToken.Token);
			System.Diagnostics.Process.Start(uri.ToString());
			Console.WriteLine("Pinコードを入力しる");
			string pinCode = Console.ReadLine();
			Twitterizer.OAuthTokenResponse accToken = Twitterizer.OAuthUtility.GetAccessToken(consumerKey, consumerSecret, reqToken.Token, pinCode);
			Twitterizer.OAuthTokens token = new Twitterizer.OAuthTokens
			{
				ConsumerKey = consumerKey,
				ConsumerSecret = consumerSecret,
				AccessToken = accToken.Token,
				AccessTokenSecret = accToken.TokenSecret
			};
			using (var twitterStream = new Twitterizer.Streaming.TwitterStream(token))
			{
				twitterStream.OnStatusReceived += (Twitterizer.TwitterStatus status) =>
				{
					Console.WriteLine(string.Format("{0}/({1})\r\n\t{2}",
						status.User.Name,
						status.User.ScreenName,
						status.Text));
				};
				twitterStream.StartUserStream();
				while (true) { }
			}
		}
	}
}

何度試しても404が返ってくる。実はこれ、ベータ版のアドレスにアクセスしてるんですよ。これがソースコード

no title

がっつりとハードコーディングされちゃっててどうにもなりません。自家ビルドして使う?嫌ですよ、そんなの。面倒じゃないですか。幸い、このStartUserStreamメソッドは短いです。じゃあStartUserStreamメソッドを呼び出してる部分のコードをURLだけ置き換えた同じ内容のコードに書き換えればいいじゃない!

以下の3行までは問題ないです。

WebRequestBuilder builder = new WebRequestBuilder(new Uri("http://betastream.twitter.com/2b/user.json"), HTTPVerb.GET, this.Tokens);
HttpWebRequest request = builder.PrepareRequest();
request.KeepAlive = true;

URLを置き換えるだけです。WebRequestBuilderクラスはpublicなので問題なく利用出来ます。引数に渡しているthis.Tokensはコンストラクタに渡したインスタンスそのものなので、こちらのスコープで保持しているものに置き換えればいいです。

問題は最後の行ですね

request.BeginGetResponse(StreamCallback, request);

引数に渡しているStreamCallbackっての、これprivateなメソッドなんですよ。これはリフレクションで取ってくることにしました。

MethodInfo method = twitterStream.GetType().GetMethod("StreamCallback",
    BindingFlags.Instance |
    BindingFlags.NonPublic);
AsyncCallback callback = (_) =>
{
    method.Invoke(twitterStream, new[] { _ });
};

リフレクションで取ってきたメソッドをInvokeするコードをAsyncCallbackデリゲートで包んであげればOKじゃんって寸法です。

で、最終的なコードがこんな感じ

using System;
using System.Net;
using System.Reflection;

namespace ConsoleApplication1
{
	class Program
	{
		static void Main(string[] args)
		{
			string consumerKey = "hoge";
			string consumerSecret = "hogehoge";
			Twitterizer.OAuthTokenResponse reqToken = Twitterizer.OAuthUtility.GetRequestToken(consumerKey, consumerSecret, "oob");
			Uri uri = Twitterizer.OAuthUtility.BuildAuthorizationUri(reqToken.Token);
			System.Diagnostics.Process.Start(uri.ToString());
			Console.WriteLine("Pinコードを入力しる");
			string pinCode = Console.ReadLine();
			Twitterizer.OAuthTokenResponse accToken =Twitterizer.OAuthUtility.GetAccessToken(consumerKey, consumerSecret, reqToken.Token, pinCode);
			Twitterizer.OAuthTokens token = new Twitterizer.OAuthTokens
			{
				ConsumerKey = consumerKey,
				ConsumerSecret = consumerSecret,
				AccessToken = accToken.Token,
				AccessTokenSecret = accToken.TokenSecret
			};
			using (var twitterStream = new Twitterizer.Streaming.TwitterStream(token))
			{
				twitterStream.OnStatusReceived += (Twitterizer.TwitterStatus status) =>
				{
					Console.WriteLine(string.Format("{0}/({1})\r\n\t{2}",
					status.User.Name,
					status.User.ScreenName,
					status.Text));
				};
				//twitterStream.StartUserStream();
				//StartUserStreamメソッドがベータ版のURLに繋いでエラーになるから
				//下記ソースの動作をURLだけ変えて実行
				//http://pm.twitterizer.net/projects/twitterizer/repository/entry/tags/twitterizer-2.3.1/Twitterizer2.Streaming/TwitterStream.cs#L138
				var builder = new Twitterizer.WebRequestBuilder(new Uri("https://userstream.twitter.com/2/user.json"), Twitterizer.HTTPVerb.GET, twitterStream.Tokens);
				HttpWebRequest request = builder.PrepareRequest();
				request.KeepAlive = true;
				MethodInfo method = twitterStream.GetType().GetMethod("StreamCallback",
					BindingFlags.Instance |
					BindingFlags.NonPublic);
				AsyncCallback callback = (_) =>
				{
					method.Invoke(twitterStream, new[] { _ });
				};
				request.BeginGetResponse(callback, request);
				while (true) { }
			}
		}
	}
}

 

これでめでたくUserStreamが使えるようになりました。ちなみにtrunkの最新のソースコードでもURLはベータ版のものがベタ書きのままでした。中の人忙しいのかな…。

C#舐めんなよC#だって出来る子なんだぞ!

低レイヤの文字列操作

なんかC#をバカにされてるようで(←酷い被害妄想)イラっときて書いた。後悔も反省もしない。

 

using System;

class Program {
	unsafe static void Main() {
		string fileName = "hoge.ScR";
		char lc = (char)('a' - 'A');
		fixed(char* p_ = fileName) {
			char* p = p_ + fileName.Length;
			if((*--p | lc) == 'r' && (*--p | lc) == 'c' &&
					(*--p | lc) == 's' && *--p == '.') {
				Console.WriteLine("めっかったぜフォー!");
			}
		}
	}
}

 

IntPtrをbyte*にキャスト出来る

NonSoft – Bitmap処理を高速化するサンプル(C#.NET)

のサンプルの

 

byte* adr = (byte*)_img.Scan0;

 

 

ってコードに驚いた。

何故って、今まで

 

byte[] argbValues = new byte[bmpData.Stride * bmp.Height];
fixed(byte* pixel = &argbValues[0]) {
    byte* pixel_ = pixel;
    Marshal.Copy(bmpData.Scan0, argbValues, 0, argbValues.Length);

 

 

ってな感じで配列にコピーしてからその配列のポインタを操作してたから。

早速コード保管庫のコードに反映させましたよっと。

C#|Bitmap処理の高速化

C#|WebBrowserで表示中のWebページのファビコンを取得

Visual Basic 中学校 掲示板

http://rucio.groupsite.jp/commu/ThreadDetail.aspx?ThreadId=9423

こんなやりとりがありまして。

最初の返信でWikipediaのリンクだけ示したのは、眠くてまともにコードが書けなかったからです。

その後、管理人のるきおさんがコードを書いていたので、僕も書きたくなったわけです。

眠くなかったのでサクっと出来ました。折角なのでC#に書き直してここに記録。

 

using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {
	public partial class Form1:Form {
		public Form1() {
			InitializeComponent();
		}

		private void Form1_Load(object sender, EventArgs e) {
			this.webBrowser1.Navigate("http://blogs.dion.ne.jp/anis7742/");
		}

		private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
			foreach(HtmlElement linkTag in this.webBrowser1.Document.GetElementsByTagName("link")) {
				string relAttribute = linkTag.GetAttribute("rel");
				string iconUrl;
				if(relAttribute == "shortcut icon" || relAttribute == "icon") {
					iconUrl = linkTag.GetAttribute("href");
					if(iconUrl.StartsWith("http")) {        //完全なURLの場合
						this.Icon = getIconFromUrl(iconUrl);
					} else if(iconUrl.StartsWith("/")) {    //絶対パスの場合
						this.Icon = getIconFromUrl("http://" + e.Url.Host + iconUrl);
					} else {                                //相対パスの場合
						this.Icon = getIconFromUrl(e.Url.ToString() + iconUrl);
					}
					break;
				}
			}
			//タグでの指定が無い場合
			this.Icon = getIconFromUrl("http://" + e.Url.Host + "/favicon.ico");
		}

		private Icon getIconFromUrl(string url) {
			using(WebClient webClient = new WebClient())
			using(MemoryStream stream = new MemoryStream(webClient.DownloadData(url))) {
				return new Icon(stream);
			}
		}
	}
}

 

あの楽器じゃないけどC#で楽器作ってみた

普通のPCを使ってガチ演奏って出来ないかなぁと思って色々試してみました。

途中経過はmixiで全体に公開の設定で書いたので、アカウントをお持ちの方はそっちで。

http://mixi.jp/view_diary.pl?id=1264945935&owner_id=2620995

http://mixi.jp/view_diary.pl?id=1265825769&owner_id=2620995

http://mixi.jp/view_diary.pl?id=1265873603&owner_id=2620995

http://mixi.jp/view_diary.pl?id=1267163178&owner_id=2620995

http://mixi.jp/view_diary.pl?id=1270510815&owner_id=2620995

つまりはソフトウェアキーボードを作ろうってことです。あれはMIDIというプロトコルで音源にメッセージを送ることで音を出しているようです。音源はWindowsに標準で付いています。MIDI規格で通信する為のWindowsAPIがあることもわかりました。

作り方を超簡単に書くと、midiOutOpen関数でMIDIデバイスを開いてmidiOutShortMsg関数で音を出す等のメッセージを送って、使い終わったらmidiOutResetしてmidiOutCloseで後始末完了です。”MIDI プログラミング”とかで検索してもDTM関連ばかりで使える情報にはなかなか辿り着けないけど、上記の関数名で検索すると詳しい情報がHITします。

結果出来たのがこれ

http://www.k4.dion.ne.jp/~anis7742/anogakki.zip

実験と称して汚いコード書いてるので実行ファイルのみの公開です。

操作方法は以下の通り

・左手のキーで対応した音階が鳴る。

・↑↓キーで音色が切り替わる。

・マウスホイールでオクターブが切り替わる。

・左ボタンを押しながらマウスを縦方向に動かすとピッチが変わる。

・右ボタンを押しながらマウスと横方向に動かすとビブラートがかかる。

僕の下手クソな演奏。こんな感じの表現が出来ます。

http://www.k4.dion.ne.jp/~anis7742/wavemode20090828224419.wav

※規定のMIDIデバイスがMicrosoft GS Wavetable SW Synth以外になってると音が鳴らない不具合があって原因を調査中です。←直った

ここまでやってみて、次の問題があることがわかった。

1.デバイスから得られるフィードバックが、その操作の結果として出る音しかない。通常の楽器は身体と楽器の接点の感触から色々な情報を得て演奏している。画面を工夫することで若干の改善は可能だが、限界がある。

2.キーボードのストロークの深さが正確なタイミングでの操作を妨げる。ストロークが浅いキーボードや、Realforceの様な奥まで押し切らなくても反応するキーボードで改善されるかも。

3.操作してから音が鳴るまでのタイムラグがある。音源や出力デバイス、その他ソフトウェア等でどこまで改善出来るか。

マウスとキーボードを本来の目的以外に使うわけだから色々無理があるわけですね。

メーラーを電信八号からSylpheedに乗り換えた

メーラーを電信八号からSylpheedに乗り換えた。何故かって?飽きたから。電八で何か不便な点や不満があったわけじゃない。

メーラーの選択の条件

・細かいメールの選別を全てPOPFileに任せているので、ヘッダの内容でメールを振り分けられること。

・1メール1テキストファイルで保存されること。

・軽いこと

・今後の乗り換えに備えてメールのインポート、エクスポート機能があること

で、Sylpheedに決めた。

電八からSylpheedへのメールの変換はちょちょいと以下のようなC#のコードをこさえてサクッと完了。厳密に正しいコードかはわからないけど、上手くいったからよし。

using System.IO;
using System.Text;
class Program {
static void Main(string[] args) {
int fileNumber = 0;
Encoding enc = Encoding.GetEncoding("Shift-Jis");
foreach(string mailFile in Directory.GetFiles(
"電八のメールフォルダ",
"*.txt",
SearchOption.AllDirectories)) {
string mailTxt = File.ReadAllText(mailFile, enc);
mailTxt = mailTxt.Replace("