2024年5月
      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 31  
無料ブログはココログ

 

« 読了:屍肉の聖餐 | トップページ | 今日届いた本 »

2009年11月22日 (日)

CookieGetterの修正

和魂に入れているCookieGetterの修正を、本来のCookieGetter側に入れようとしている。
それだけではつまらないので、CookieGetterの最大の問題である「firefoxを使うときSQLiteのC#ラッパDLLのバージョンがビルド時と違うモノを使うと落ちる」を修正してみる。
この間書いたエントリの通り、動的にDLLを読み込めばOK。

まだ、十分見直していないのだが、classFirefoxCookieGetter.cs ファイルを以下の様に書き換える。

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;

namespace CookieGetter
{
    class classFirefoxCookieGetter
    {
        static public ICookieGetter getInstance(classCookieGetter.BROWSER_TYPE browser)
        {
            ICookieGetter obj = null;
            switch (browser)
            {
                case classCookieGetter.BROWSER_TYPE.FIREFOX3:
                    obj = new classFirefox3CookieGetter();
                    break;
            }
            return obj;
        }

        private class classFirefox3CookieGetter : classCookieGetter
        {
            string assemblyName_ = "System.Data.SQLite.dll";
            object hConnection_;
            Type typeSQLiteConnection_;
            Type typeSQLiteCommand_;
            Type typeSQLiteDataReader_;

            public classFirefox3CookieGetter()
            {
                // アセンブリ内のモジュールを取得
                Assembly assembly = Assembly.LoadFrom(assemblyName_);
                // アセンブリ内のクラスを取得
                Module module = assembly.GetModule(assemblyName_);

                typeSQLiteConnection_ = module.GetType("System.Data.SQLite.SQLiteConnection");
                // クラスを動的に作成する
                if (typeSQLiteConnection_ != null)
                {
                    string file = searchFile(base.getAppdataPath() + "\\Mozilla\\Firefox\\Profiles\\", "cookies.sqlite", true);
                    hConnection_ = Activator.CreateInstance(typeSQLiteConnection_, new Object[] { "Data Source=" + file });
                }

                typeSQLiteCommand_ = module.GetType("System.Data.SQLite.SQLiteCommand");
                typeSQLiteDataReader_ = module.GetType("System.Data.SQLite.SQLiteDataReader");
            }

            override  public string getCookieValue(string url, string key)
            {
                string result = "";
                string query = "SELECT value FROM moz_cookies where host==\'" + url + "\' AND name==\'" + key + "\'";
                string[][] values = select_table(query);

                if (values != null && values.Length > 0)
                {
                    result = values[0][0];
                }
                else
                {
                    result =  "";
                }
                return result;
            }

            override public string[][] getCookies(string url)
            {
                string query = "SELECT name, value FROM moz_cookies where host==\'" + url + "\'";
                return select_table(query);
            }

            private string[][] select_table(string query)
            {
                ArrayList values = new ArrayList();

                    //SQLiteConnection hConnection = new SQLiteConnection("Data Source=" + file);

                    //SQLiteCommand myCommand = new SQLiteCommand(query, hConnection);
                    Object myCommand = Activator.CreateInstance(typeSQLiteCommand_, new Object[] { query, hConnection_ });   

                    // データベース接続を開く
                    //hConnection_.Open();
                    // ※:SQLiteConnection::Open()は、引数ありのメソッドが無いので、GetMethod()の第二引数を指定しなくてもOK
                    MethodInfo connectionOpen = typeSQLiteConnection_.GetMethod("Open");
                    connectionOpen.Invoke(hConnection_, null);

                    //SQLiteDataReader myReader;
                    //myReader = myCommand.ExecuteReader();
                    // ※:SQLiteCommand::ExecuteReader()はoverloadなメソッドが他にあるため、GetMethod()の第二引数に明示的に"引数なし"を指定する
                    MethodInfo connectionExecuteReader = typeSQLiteCommand_.GetMethod("ExecuteReader", new Type[0]);
                    object myReader = connectionExecuteReader.Invoke(myCommand, null);

                    //int fieldCount = myReader.FieldCount;
                    PropertyInfo readerfieldCount = typeSQLiteDataReader_.GetProperty("FieldCount");
                    int fieldCount = (int)readerfieldCount.GetValue(myReader, null);

                    string[] col;

                    MethodInfo readerRead = typeSQLiteDataReader_.GetMethod("Read");
                    MethodInfo readerGetString = typeSQLiteDataReader_.GetMethod("GetString", new Type[] { typeof(int) });

                    //while (myReader.Read())
                    // ※:SQLiteDataReader::Read()はoverloadなメソッドが他にあるため、GetMethod()の第二引数に明示的に"引数なし"を指定する
                    while ((bool)readerRead.Invoke(myReader, new Type[0]))
                    {
                        col = new string[fieldCount];
                        for (int i = 0; fieldCount > i; i++)
                        {
                            //col[i] = myReader.GetString(i);
                            col[i] = (string)readerGetString.Invoke(myReader, new object[] { (object)i });
                        }

                        values.Add(col);
                    }

                    //myReader.Close();
                    // ※:SQLiteDataReader::Close()は、引数ありのメソッドが無いので、GetMethod()の第二引数を指定しなくてもOK
                    MethodInfo readerClose = typeSQLiteDataReader_.GetMethod("Close");
                    readerClose.Invoke(myReader, null);

                    //hConnection.Close();
                    // ※:SQLiteConnection::Close()は、引数ありのメソッドが無いので、GetMethod()の第二引数を指定しなくてもOK
                    MethodInfo connectionClose = typeSQLiteConnection_.GetMethod("Close");
                    connectionClose.Invoke(hConnection_, null);

                    //hConnection.Dispose();
                    // ※:SQLiteConnection::Dispose()は、引数ありのメソッドが無いので、GetMethod()の第二引数を指定しなくてもOK
                    MethodInfo connectionDispose = typeSQLiteConnection_.GetMethod("Dispose");
                    connectionDispose.Invoke(hConnection_, null);

                if (values.Count == 0)
                {
                    return null;
                }
                else
                {
                    return (string[][])values.ToArray(typeof(string[]));
                }
            }
        }
    }
}

問題はすでにfirefoxが実行されている状態でCookieを読もうとすると SQLiteConnection::Open() で例外「The database file is locked\r\ndatabase is locked」が発生してしまう。 これは、frefoxが起動中はクッキーファイルを LOCK したままにする仕様(?)の所為らしい。しょうがないので、例外をキャッチしなければならない・・・。

●ついで
SQLiteを使用するには、SQLite.dll と C#ラッパDLLが必要である。

  • SQLite.dllは、本家HPから(上の方にある)メニューDOWNLOAD→Precompiled Binaries For Windowsにあるどれかで sqlite3.dll を取得する。例えば2009/11/22現在最新であるsqlite3_analyzer-3.6.1.zipとか。sqlite3.dllは、パスが通っているところに入れる。別にCookieGetterを動かすAPと同じディレクトリにあってもよい。
  • C#ラッパDLLは、sourceFORGEから拾ってくる。System.Data.SQLite.DLLが必要。SQLite-1.0.65.0-source.zip を落として、binディレクトリにある System.Data.SQLite.DLL をアプリのexeがあるところに置けば良い。

もう眠い・・・、実際に修正したものをアップするのは明日ソースを確認してからにしよう。 

« 読了:屍肉の聖餐 | トップページ | 今日届いた本 »

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: CookieGetterの修正:

« 読了:屍肉の聖餐 | トップページ | 今日届いた本 »