コード」タグアーカイブ

C# で ini ファイルの内容を任意のクラスに格納するコードを書いてみた。


どうもみむらです。

C# で ini ファイルを操作するとなると、
よくあるのが GetPrivateProfileString あたりを叩いて取得することになります。

でもその場合、いちいち要素を指定して取得しなければならず、
特に複数のキー(フィールド)がある場合に複数回コードを書くのも面倒です。

特に ini ファイルの項目が多くて、こんな状態になった日には・・。

image

 

・・ということで、 Reflection を使用して
この辺をすごく楽に出来るような感じでコードを書いてみました。

 

コード:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

public static class Ini
{
    [DllImport("KERNEL32.DLL")]
    public static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName);

    [DllImport("KERNEL32.DLL")]
    public static extern uint GetPrivateProfileInt(string lpAppName, string lpKeyName, int nDefault, string lpFileName);

    [DllImport("KERNEL32.DLL")]
    public static extern uint WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName);

    public static T Read<T>(string section, string filepath)
    {
        T ret = (T)Activator.CreateInstance(typeof(T));

        foreach (var n in typeof(T).GetFields())
        {
            if (n.FieldType == typeof(int))
            {
                n.SetValue(ret, (int)GetPrivateProfileInt(section, n.Name, 0, Path.GetFullPath(filepath)));
            }
            else if (n.FieldType == typeof(uint))
            {
                n.SetValue(ret, GetPrivateProfileInt(section, n.Name, 0, Path.GetFullPath(filepath)));
            }
            else
            {
                var sb = new StringBuilder(1024);
                GetPrivateProfileString(section, n.Name, "", sb, (uint)sb.Capacity, Path.GetFullPath(filepath));
                n.SetValue(ret, sb.ToString());
            }
        };

        return ret;
    }

    public static void Write<T>(string secion, T data, string filepath)
    {
        foreach (var n in typeof(T).GetFields())
        {
            WritePrivateProfileString(secion, n.Name, n.GetValue(data).ToString(), Path.GetFullPath(filepath));
        };
    }
}

 

使い方:

ini ファイルの読み取りたいセクションに合わせたクラスを用意します。

    public class Human
    {
        public string name;
        public int age;
    }

でもって次のような ini ファイルを用意して

[01]
name=TARO
age=20

あとはこんな風に呼び出します。

        static void Main(string[] args)
        {
            var h = Ini.Read<Human>("01", "DATA.INI");

            h.age = 15;
            h.name = "JIRO";
            Ini.Write("02", h, "DATA.INI");
        }

 

実行しますと、

image

こんな感じでデータが読み出されます。

でもって、 ini ファイルは

[01]
name=TARO
age=20
[02]
name=JIRO
age=15

こんな感じに、ちゃんとセクション 02 が書き込まれます。


躓きそうなところ:

データを格納するクラスが、こういう感じに {get; set;} な状態になっている場合:

    public class Human
    {
        public string name { get; set; }
        public int age { get; set; }
    }

上記コード内の GetFields を GetProperties に換え、 FieldType を PropertyType に変えれば動作します。


・・そんなわけで、もし良ければ自己責任でご利用ください-。

Twitter の OAuth 1.0 認証を自分でコード書いてやってみた。


みむらです。

ひとまず、おべんきょーということで、後からも分かるように、
変数を多く使って文字列出力をふんだんに出しながら。

ソースコードが、海から来た侵略者に侵略されていますが、
そんなもの全く気にしない、むしろ、侵略されていないでゲソ!

—-

参考資料:

* http://oauth.net/core/1.0
* http://hueniverse.com/oauth/guide/authentication/
* https://dev.twitter.com/docs/auth/authorizing-request/

—-

https://gist.github.com/1395485

using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;

/*
 * この辺を参考に:
 * 
 * http://oauth.net/core/1.0
 * http://hueniverse.com/oauth/guide/authentication/
 * https://dev.twitter.com/docs/auth/authorizing-request
 */

namespace Direct_Commit_Twitter
{
    class Program
    {

        static void Main(string[] args)
        {
            //
            // 使うパラメータは次のようなもの。
            //
            // OAuth Consumer Key       : Consumer Key そのまま。
            // OAuth Token              : Access Token そのまま。 (今回はこれも取得。)
            // OAuth Nonce              : ランダム文字列を与える。 (毎回変更する。)
            // OAuth Signature          : OAuth Signature 以外の値で HMAC-SHA1 をとった値。
            // OAuth Signature Method   : Twitter は HMAC-SHA1 指定っぽいので HMAC-SHA1.
            // OAuth Time Stamp         : UNIX 時間 (1970-01-01 UTC からの秒数) を与える。
            //                          : (今回は GetUNIXTime() メソッドで取得します。)
            // OAuth Version            : 今回は 1.0 を使うので、1.0.
            //

            string consumer_key = "oDcUp76alv6VctYvRx2g";
            string consumer_secret = "mg1U9TEFVafIPQm0Y0YuLR8EZatXiDBvPLiiCConzbg";

            string access_token = "";
            string access_secret = "";

            string tweet_text = "ゲソーゲソー";

            /************************ 以下、黙々と処理 ********************/

            string[] verify_token;

            if (access_token == "" || access_secret == "")
            {

                #region 01. Request Token を取得しなイカ?
                {
                    Console.WriteLine("01 - Token を取得しなイカ?");
                    Console.WriteLine("-------------------------------------------------");

                    Random rand = new Random();
                    byte[] nonce_b = new byte[64];

                    rand.NextBytes(nonce_b);

                    string nonce = Math.Abs(BitConverter.ToInt64(nonce_b, 0)).ToString();
                    long unixtime = GetUNIXTime();

                    //
                    // OAuth Signature 生成のために、それ以外で仮のリクエスト文字列を作成する。
                    // この際、各パラメータは ABC 順にソートされている必要がある。
                    //
                    string signature_request = "POST&" + UrlEncode("https://api.twitter.com/oauth/request_token");
                    signature_request += "&" + UrlEncode(MakeParamString(consumer_key, nonce, null, unixtime, null, null, null));

                    //
                    // ちゃんとしたリクエスト文字列を作る。
                    //
                    string signature = GetSignature(consumer_secret, null, signature_request);
                    string param = MakeParamString(consumer_key, nonce, signature, unixtime, null, null, null);

                    DebugParamOut(consumer_key, consumer_secret, nonce, signature, unixtime, null, null, null);
                    return;
                    //
                    // 問い合わせ。
                    //
                    Console.WriteLine("* Access : https://api.twitter.com/oauth/request_token?" + param);
                    HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create("https://api.twitter.com/oauth/request_token?" + param);
                    hwr.Method = "POST";
                    WebResponse ret = hwr.GetResponse();
                    verify_token = new StreamReader(ret.GetResponseStream()).ReadToEnd().Split('&');

                    ret.Close();

                    Console.WriteLine();
                    Console.WriteLine("Response : ");
                    foreach (string s in verify_token)
                        Console.WriteLine("> " + s);
                }
                #endregion

                #region 02. Access Token を取得しなイカ?
                {
                    Console.WriteLine();
                    Console.WriteLine("02 - Access Token を取得しなイカ?");
                    Console.WriteLine("-------------------------------------------------");

                    string request_token = "";
                    string request_secret = "";

                    //
                    // ブラウザ開いて認証。
                    //
                    foreach (string s in verify_token)
                    {
                        int p = s.IndexOf("oauth_token=");
                        if (p != -1)
                        {
                            request_token = s.Substring(p + "oauth_token=".Length);
                            break;
                        }
                    }
                    Console.WriteLine("- OAuth Token : " + request_token);
                    Console.WriteLine("* Browser Open : https://twitter.com/oauth/authorize?oauth_token=" + request_token);
                    Process.Start("https://twitter.com/oauth/authorize?oauth_token=" + request_token);

                    //
                    // PIN を入力させる。
                    //
                    Console.Write("\nINPUT PIN : ");
                    string pin = Console.ReadLine();

                    foreach (string s in verify_token)
                    {
                        int p = s.IndexOf("oauth_token_secret=");
                        if (p != -1)
                        {
                            request_secret = s.Substring(p + "oauth_token_secret=".Length);
                            break;
                        }
                    }


                    //
                    // 以下 Twitter ともくもく通信。
                    //

                    Random rand = new Random();
                    byte[] nonce_b = new byte[64];

                    rand.NextBytes(nonce_b);

                    string nonce = Math.Abs(BitConverter.ToInt64(nonce_b, 0)).ToString();
                    long unixtime = GetUNIXTime();

                    //
                    // Signature 生成のための一時的なリクエスト文字列を作成。
                    //
                    string signature_request = "POST&" + UrlEncode("https://api.twitter.com/oauth/access_token");
                    signature_request += "&" + UrlEncode(MakeParamString(consumer_key, nonce, null, unixtime, request_token, pin, null));

                    string signature = GetSignature(consumer_secret, request_secret, signature_request);
                    string param = MakeParamString(consumer_key, nonce, signature, unixtime, request_token, pin, null);

                    DebugParamOut(consumer_key, consumer_secret, nonce, signature, unixtime, request_token, request_secret, pin);

                    //
                    // 問い合わせ。
                    //
                    Console.WriteLine("* Access : https://api.twitter.com/oauth/access_token?" + param);
                    HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create("https://api.twitter.com/oauth/access_token?" + param);
                    hwr.Method = "POST";
                    hwr.Headers.Add("Authorization", "OAuth");

                    WebResponse ret = hwr.GetResponse();
                    verify_token = new StreamReader(ret.GetResponseStream()).ReadToEnd().Split('&');

                    ret.Close();

                    Console.WriteLine();
                    Console.WriteLine("Response : ");
                    foreach (string s in verify_token)
                    {
                        if (s.IndexOf("oauth_token=") != -1)
                            access_token = s.Substring(s.IndexOf("=") + 1);

                        if (s.IndexOf("oauth_token_secret=") != -1)
                            access_secret = s.Substring(s.IndexOf("=") + 1);

                        Console.WriteLine("> " + s);
                    }
                }
                #endregion

            }

            #region 03. つぶやかなイカ?
            {
                Console.WriteLine();
                Console.WriteLine("03 - つぶやかなイカ?");
                Console.WriteLine("-------------------------------------------------");
                
                Random rand = new Random();
                byte[] nonce_b = new byte[64];

                rand.NextBytes(nonce_b);

                string nonce = Math.Abs(BitConverter.ToInt64(nonce_b, 0)).ToString();
                long unixtime = GetUNIXTime();

                string tweet_data = UrlEncode(tweet_text);

                string signature_request = "POST&" + UrlEncode("https://api.twitter.com/1/statuses/update.xml");
                signature_request += "&include_entities%3Dtrue%26" + UrlEncode(MakeParamString(consumer_key, nonce, null, unixtime, access_token, null, tweet_data));
                string signature = GetSignature(consumer_secret, access_secret, signature_request);

                string header_param = "OAuth oauth_consumer_key=\"" + UrlEncode(consumer_key) + "\",oauth_signature_method=\"HMAC-SHA1\"," +
                                      "oauth_timestamp=\"" + unixtime + "\",oauth_nonce=\"" + UrlEncode(nonce) + "\"," +
                                      "oauth_version=\"1.0\",oauth_token=\"" + UrlEncode(access_token) + "\"," +
                                      "oauth_signature=\"" + UrlEncode(signature) + "\",";

                DebugParamOut(consumer_key, consumer_secret, nonce, signature, unixtime, access_token, access_secret, null);
                Console.WriteLine("* Access : https://api.twitter.com/1/statuses/update.xml");
                Console.WriteLine("* Tweet at : " + tweet_text);

                HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create("https://api.twitter.com/1/statuses/update.xml");
                hwr.Method = "POST";
                hwr.ServicePoint.Expect100Continue = false;
                hwr.Headers.Add(HttpRequestHeader.Authorization, header_param);
                hwr.ContentType = "application/x-www-form-urlencoded";
                var s = new StreamWriter(hwr.GetRequestStream());
                s.Write("status=" + tweet_data + "&include_entities=true");
                s.Close();

                WebResponse ret = hwr.GetResponse();
                Console.WriteLine();
                Console.WriteLine("Response:");
                Console.WriteLine("> "+(new StreamReader(ret.GetResponseStream()).ReadToEnd()));

            }
            #endregion
        }

        // UNIX 時間を返す。
        static long GetUNIXTime()
        {
            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
        }

        // URLエンコード (どうやらエスケープ文字は大文字にしないといけないらしい。)
        static string UrlEncode(string str)
        {
            string s = HttpUtility.UrlEncode(str);
            return _UrlEncodeUpper(s);
        }

        static string _UrlEncodeUpper(string str)
        {
            int p = str.IndexOf("%");
            if (p != -1)
            {
                str = str.Substring(0, p) + str.Substring(p, 3).ToUpper() + _UrlEncodeUpper(str.Substring(p + 3));
            }
            return str;
        }

        // パラメータ文字列を生成
        static string MakeParamString(string oauth_consumer_key, string oauth_nonce, string oauth_signature, long oauth_timestamp, string oauth_token, string oauth_verifier, string status)
        {
            string param = "oauth_consumer_key=" + oauth_consumer_key + "&oauth_nonce=" + oauth_nonce;

            if (oauth_signature != null)
                param += "&oauth_signature=" + oauth_signature;

            param += "&oauth_signature_method=HMAC-SHA1" + "&oauth_timestamp=" + oauth_timestamp;

            if (oauth_token != null)
                param += "&oauth_token=" + oauth_token;

            if (oauth_verifier != null)
                param += "&oauth_verifier=" + oauth_verifier;
            
            param += "&oauth_version=1.0";

            if (status != null)
                param += "&status=" + status;

            return param;
        }

        // Consumer Secret をKey とした、リクエスト文字列のハッシュを求める。
        static string GetSignature(string consumer_secret, string access_token_secret, string param)
        {
            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = Encoding.ASCII.GetBytes(consumer_secret + "&" + access_token_secret);
            byte[] hash = hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(param));
            
            return Convert.ToBase64String(hash);
        }

        // よくやる出力をまとめてみる。
        static void DebugParamOut(string oauth_consumer_key, string oauth_consumer_secret, string oauth_nonce, string oauth_signature, long oauth_timestamp, string oauth_token, string oauth_token_secret, string oauth_verifier)
        {
            Console.WriteLine("- OAuth Consumer Key = " + oauth_consumer_key);
            Console.WriteLine("- OAuth Consumer Secret = " + oauth_consumer_secret);
            Console.WriteLine("- OAuth Nonce = " + oauth_nonce);
            if (oauth_signature != null)
                Console.WriteLine("- OAuth Signature = " + oauth_signature);
            Console.WriteLine("- OAuth Time Stamp = " + oauth_timestamp);
            if (oauth_token != null)
                Console.WriteLine("- OAuth Access Token = " + oauth_token);
            if (oauth_token_secret != null)
                Console.WriteLine("- OAuth Access Token Secret = " + oauth_token_secret);
            if (oauth_verifier != null)
                Console.WriteLine("- OAuth Verifier = " + oauth_verifier);
        }
    }
}

 

とりあえず、記事自体がむちゃくちゃ長くなるので、
解説云々は次の記事に。

SyntaxHighlighter でコードを示したあと、ずたずたに書式が崩れる不具合の対応


どうもみむらです。

とっても見づらいブログ記事で本当に申し訳ございませんでした。
変に改行とかが入って、おそろしく見づらかったことかと思います。

 

ということで、今回はそれの犯人と、
修正の方法。

 

原因:

<pre> </pre> 以降の HTML データが上手く処理されず、
テキストデータとして改行がなされたところに <br /> たぐが自動挿入されたため。

 

対策:

WordPress 内の wpautop というフィルタによって自動挿入されるため、

http://urbangiraffe.com/plugins/disable-wpautop/
上記URL より入手できるプラグインを導入して処理を除去。

 

結果:

対策前:

image

上記のように、文と文が離れていて大変読みづらい状況でした。

 

対策後:

image

本来、当方が記述した際の正しい記述にて表示が行われ、
段落ごとに文章がまとまり、見やすくなっています。

 


というわけで、
WordPress で <pre> を利用してコードを記述している方で、
ずたずたにスタイルが崩れてしまった場合、利用してみてはいかがでしょうか。

ちなみに、RSS フィードに対しても wpautop は適用され、
改行が挿入されますが、
このプラグインでは RSS フィードに対しても有効であり、
かつ、Wordpress をアップデートしても有効となるため、かなり有用かと思います。