2005年01月14日

Application Dataフォルダの取得

SHGetSpecialFolderPathで、ユーザーごとのApplication Dataフォルダ ( CSIDL_LOCAL_APPDATA ) を取得するためには、Internet Explorer 5、Windows 2000 もしくはWindows Me 以上が必要。

投稿者 Takenori : 02:34 | トラックバック

ブラウザでURLを開く

HINSTANCE hInstShell = ShellExecute( hWnd, "open", "http://taregeturl.com/", NULL, NULL, SW_SHOWDEFAULT );
とやれば、標準ブラウザで http://taregeturl.com/ が開かれる。
引数の意味などはShellExecuteを参照のこと。

投稿者 Takenori : 02:39 | トラックバック

文字コードの変換

mixiからHTMLを取得した後、文字コードの変換が必要だ。
しかも、面倒なことにmixiはEUC-JPで返してくる。
それで、まず思い付いたのがNKFだ。
これのWin32ライブラリ版がないか探したところNKF32.DLLがあった。
でも、UTF-8対応版ではない。

もう一つはlibiconvだ。
GNU Win32から取得し、試そうとするがlibintlも必要と言われたのでDL。
自動認識がないのが難点だな。

これは強引にEUC-JPでやるか? と思ったけど、boost::regexを使おうと思ったらUnicodeにする必要があるようだ。
文字コード認識の良さそうなライブラリを探すが、どれが良いかイマイチよくわからない。と言うか、知らない。
で、HTMLのcharsetを頼りに認識を行うのであれば、正規表現で簡単に取得できる。
これで行こうかと思ったが、面倒なのでEUC-JP決め打ちでいいかと思った。
このツールは、mixiに変更が合った場合認識できなくなる可能性が高い。
なら、文字コードは決め打ちでも問題ないと考えたからだ。

で、結局iconvでEUC-JP からUTF-16LEへ変換することにした。

投稿者 Takenori : 03:55 | トラックバック

libiconvを使おうとしたが

まず、libiconvをソースからmakeしようとしたが、うまくいかなかった。
で、バイナリのやつを使おうとしたけど、よくわからなかった。
で、いろいろと検索するとKaoriYa.netにiconv.dllをVCでビルドした物があったので、これを使うことにした。
そして、使ってみるが、文字列などによってうまくいくときといかない時がある。
iconv.cを見ると、その辺りはなんか面倒なことをしている。
この辺りでかなりiconvを使う気が減衰。
NKF32.DLLを使ってSHIFT_JISにした後、MultiByteToWideCharでUnicode(UTF-16)に変換しようかと思った。
だが、MultiByteToWideCharを使って、いきなりEUC-JPからUnicodeへ変換できない物かと考えて調べてみた。
調べるとEUC-JPのコードページは、51932 とある。キャラクタセットの認識および、Windowsコードページ一覧を参照のこと。
つまり、MultiByteToWideCharでコードページ 51932 を使えばうまくいくかと思ったが、変換できず。
文字コード掲示板過去ログにもそのことが書いてあった。
ConvertINetMultiByteToUnicodeを使うしかない様子。
で、ConvertINetMultiByteToUnicodeを使おうとするが、MSDNに必要なヘッダーファイルの記述がない。
いろいろ調べてMLANG.IDLから、MLang.h だろうと思い、MLang.hをinclude。
しかし、リンク時にエラーになる。
DLLはmlang.dllだと記述されているので、検索し発見。
mlang.dll からC++Builder用のインポートライブラリを作る。
implib mlang.lib mlang.dll
と、コマンドラインで入力すれば、mlang.libが出来るので、これをプロジェクトに追加。
メイクが通るようになった。
初めはうまく動かなかったが、キチンとリファレンス読んで書いたらうまく動くようになった。
その部分のコードは次のような感じ。
なお、エラー処理は省いている。

#define CP_EUCJP 51932
FILE *ifp, *ofp;
ifp = fopen( "test.html", "rb" );
ofp = fopen( "unicode.html", "wb" );
if( ifp && ofp ) {
    char inbuf[1024*64];
    wchar_t *outbuf = (wchar_t*)malloc(1024*64);
    wchar_t *out_base = outbuf;
    int out_cnt;
    DWORD dwMode = 0;
    while( fgets( inbuf, 1024*64, ifp ) != NULL )
    {
        out_cnt = 1024*32;
        outbuf = out_base;
        ConvertINetMultiByteToUnicode( &dwMode, CP_EUCJP, inbuf, NULL, outbuf, &out_cnt );
        fwrite( out_base, 1, out_cnt*2, ofp );
    }
    fclose(ifp);
    fclose(ofp);
}

今回はファイルからなのでfgetsで読んでいるけど、実際はInternetReadFileで読むから行読み込みを行う物が必要だな。
確か、昔作った記憶があるけど・・・探さないと。

ConvertINetMultiByteToUnicode を使用するには、Internet Explorer 5.5 以降、Windows 95、Windows NT 4.0以降が必要。

投稿者 Takenori : 04:27 | トラックバック

2005年01月15日

boost::regexで悩む

L"\<a href=view_diary\.pl\?id=([0-9]+)\>"
と書いた正規表現が通らない。
あるはずなのにヒットしない。
perlでやるとヒットする。
なぜだ?としばらく悩んで気づいた。
L"\\<a href=view_diary\\.pl\\?id=([0-9]+)\\>"
と\マーク自体をエスケープしないといけないことを。
でも、ここが出来たら後は細かいところと全体の結合だな。
HTTPでHTMLを取得するところは、Win32 Inetを使ってperlでプロトタイプを書き、動作することを確認しているので、これはC++に書き換えなければならないが。

投稿者 Takenori : 09:57 | トラックバック

perl でWin32 Inet

次のようにすれば、perlでWin32 Inetを使いmixiからログイン後のHTMLデータを取得できる。

use Win32::Internet;
$email = 'your_addr@yourhost.ne.jp';
$password = 'your_password';
$next_url = '/home.pl';
$target_url = 'mixi.jp';
$target_object = 'login.pl';
$post_req = 'email=%EMAIL%&password=%PASSWORD%&next_url=%NEXT_URL%';
$success_login = 0;
$INET = new Win32::Internet();    # WinInetのインスタンスを得る
if( defined( $INET ) ) {
    local $HTTP;
    $INET->HTTP( $HTTP, $target_url );
    if( defined( $HTTP ) ) {
        $send_command = $post_req;
        $send_command =~ s/%EMAIL%/$email/g;
        $send_command =~ s/%PASSWORD%/$password/g;
        $send_command =~ s/%NEXT_URL%/$next_url/g;
        {
            my $REQ;
            my $params;
            $params{"path"} = $target_object."?".$send_command;
            $params{"flags"} = INTERNET_FLAG_RELOAD;
            $params{"method"} = "POST";
            $HTTP->OpenRequest( $REQ, \%params );
            if( defined( $REQ ) ) {
                $REQ->SendRequest( $send_command )
                $file = $REQ->ReadEntireFile();
                $REQ->Close();
                @read_data = split( /\n/, $file );
                foreach( @read_data ) {
                    chomp;
                    if( /url=\/check.pl\?n=\%2Fhome.pl/ ) {
                        $success_login = 1;
                    }
                }
            }
        }
        if( $success_login ) {
            my $REQ;
            my $params;
            $params{"path"} = 'check.pl?n=\%2Fhome.pl';
            $params{"flags"} = INTERNET_FLAG_RELOAD;
            $params{"method"} = "GET";
            $HTTP->OpenRequest( $REQ, \%params );
            if( defined( $REQ ) ) {
                $REQ->SendRequest();
                $file = $REQ->ReadEntireFile();
                $REQ->Close();
                @read_data = split( /\n/, $file );
                foreach( @read_data ) {
                    chomp;
                    print $_."\n";
                }
            }
        }
    }
    $HTTP->Close();
}
$INET->Close();

perlでWin32 Inetを使えばプロトタイプを書いたり、そのまま使ったりするのに意外と便利。
と言うか、他のモジュールでHTML取得するスクリプト書いたことないんだけど。
ま、Winなら問題ないし、いいでしょ。

投稿者 Takenori : 10:13 | トラックバック

2005年01月20日

バッファからの行読み込み

自作の関数ではなく、STLのstrstreamとgetlineを使えば、簡単に実現できることが判明。
次のような感じ。

char *read_buff = new char[html_size];
unsigned long read_size_all;
// read_buffへWinINetを使って読み込み処理
std::istrstream read_stream( read_buff, read_size_all );
while( std::getline( read_stream, line ) )
{// 何か処理
}

std::istrstreamではなく、std::strstreamにしたらなぜかうまくいかなかった。(これでしばらく悩んだ)
std::ios::in を指定すれば同じだと思っていたのだが、違うのだろうか?
まあ、出来たからいいか。

投稿者 Takenori : 07:02 | トラックバック

C++でWinINet

perlの場合、かなりお気楽に使えるが、C/C++で使うとなると、少し事情が違った。
まず、perlの場合読み込みバッファは自動的に確保してくれるので、気にしなくても良かったが、Cの場合は明示的に確保しないといけない。
で、HttpQueryInfo( hHttpRequest, HTTP_QUERY_CONTENT_LENGTH, BufSizeText, &BufSizeTextSize, NULL); とコールするが、サイズが返ってこない。
仕方ないので、512KBぐらい確保して読み込み処理をするが、1回のInternetReadFile コールではすべてのデータを取得しきれない時があるようだ。
そこで、次のようにして読み込むこととした。

read_buff = new char[htmlSize];
memset( read_buff, 0, htmlSize );
DWORD curPos = 0, ReadSizeAll = 0;
int bootstrap = 0;
while(1)
{
    BOOL ret;
    ret = InternetReadFile( hHttpRequest, &read_buff[curPos], (htmlSize-ReadSizeAll), &ReadSize);
    if(ret && (ReadSize == 0)) break;
    curPos += ReadSize;
    ReadSizeAll += ReadSize;
    bootstrap++;
    if( bootstrap > TRY_MAX) break;
}

curPos と ReadSizeAll は同じだから両方は必要ないかも。
他はperlの時とだいたい同じでいけた。
ラッパークラスとかあると便利かも。

投稿者 Takenori : 07:11 | トラックバック

2005年01月21日

とりあえず完成

実装した機能は以下の通り
新着メッセージ、新着コメントを定期的に確認。
確認サイクルは固定。
アラートウィンドウは一定期間で非表示に。
非表示になるまで時間は固定。
ログイン用メールアドレス、パスワードの設定。
タスクトレイへのアイコンの登録。
イマイチなアイコン。

要求システムは次のとおりのはず。
Internet Explorer 5.5 以降
Windows 2000 もしくはWindows Me 以降
とりあえず、XP と 2000 では動作確認している。

その他制限事項
IEを普段使っている場合、自動ログインが切れてしまう。IEは使わずにFirefox使ったほうが良いと思われ。


他に対応したいこと
インストーラー
マルチユーザー
新着日記、新着コミュニティー書き込み、新着レビューの確認。
確認サイクルの指定。
アラートウィンドウを自動的に非表示するかどうか。また、その時間。
自動的に非表示された場合、タスクバーのアイコンで未チェックかどうか明示。
アイコンがイマイチなので、何とかしたい。
確認の一時停止。(ユーザーの操作がない場合など)
メッセージやコメントへのダイレクトリンクをアラートウィンドウに表示する。
それぐらいだったかな。

投稿者 Takenori : 12:00 | トラックバック

2005年01月25日

機能追加&変更

変更項目
接続時のエラーメッセージを詳細に表示するように変更。
Alertウィンドウが自動的に消えないように変更。
ログイン時のレスポンスのリダイレクトURLを認識し、そのURLを読み込むように変更。
その時、boost::regexの正規表現でまたハマる。
<と>は別にエスケープしなくても良いようだ。と言うか、しないようにしないとヒットしない?
不必要なエスケープを減らしたらヒットするようになった。
チェックサイクルの時間をインターバルに変更。(以前は定期的に実行)

追加機能
チェックサイクルを1分、2分、3分、5分、10分、15分、20分、30分、1時間の中から選択できるように機能追加。

ソース上の変更
設定ウィンドウの各コントロールの設定を、前は呼び出し元が行っていたが、設定ウィンドウが表示される時に、自分で取得、設定を行うように変更。また、同時に設定ウィンドウのプロパティもなくす。

投稿者 Takenori : 01:59 | トラックバック

2005年01月26日

新着日記もチェック

新着日記もチェックにも対応した。

インストール後、初回起動時は常に新着日記があると表示。
Alert Windowで「mixiを開く」もしくは「Close」がクリックされたら、見たとみなす。
仕様はそんなところ。

投稿者 Takenori : 10:53 | トラックバック

2005年01月27日

公開開始

そこそこまともに動くようになったと思うので、公開を開始した。

公開前に変更&追加したこと
一部エラーメッセージの変更。
アクセス時にエラーが発生した場合、エラーログを出力するようにした。
設定ウィンドウの表示位置を画面中央になるようにした。

投稿者 Takenori : 10:39 | トラックバック

2005年01月28日

WinInetの接続周りの見直し

WinInetのAPIを調べたら、キャッシュが有効になっていた。
キャッシュが効くと困るので、修正。
あと、接続が常に直接接続となっていたので、レジストリの設定を参照するようにした。

投稿者 Takenori : 03:10 | トラックバック

2005年02月01日

少しだけ変更

起動すると毎回、新着日記がありますと表示されている気がしたので、コードを追ったが問題はなさそう。
今までプログラム終了時にのみ既読日記のIDを保存していたが、アラートウィンドウが閉じられるたびに保存するように変更。
また、設定もプログラム終了時にのみ行っていたが、設定ウィンドウでOKを押された時に保存するように変更。
確認サイクルの設定変更が、次のチェック時に反映されるようになっていたのを、即座に反映するように変更。

投稿者 Takenori : 02:32 | トラックバック

ON/OFFを追加

各種アラートの有効/無効を設定できるように変更した。
C++Builderだと、こう言う時楽だ。
でも、デバッガでテストするのは面倒だったけど。

投稿者 Takenori : 23:51 | トラックバック

2005年02月14日

トレイアイコンのポップアップメニュー

C++ Builderでタスクトレイアイコンのポップアップメニューがフォーカスを失った時に、キチンとメニューを非表示にする方法がわかった。
サンプルコードは次のような感じ。

TrayRPopupMenu->PopupComponent = Form_Alert;
SetForegroundWindow(Handle);
TrayRPopupMenu->Popup(X,Y);

TPopupMenu の PopupComponent に所有者となるコンポーネントを設定。
次に、そのフォームをフォアグランドに。
そして、ポップアップ。
こうすれば、ポップアップメニューがフォーカスを失った時に、キチンと消えてくれる。

そう言えば、フォアグランドにしないといけないって言うのあったね。
すっかり忘れていた。
確か、タスクトレイに限らず、フォアグラウンドにないウィンドウでポップアップメニューを使う時はこれが必要だったような気がする。

投稿者 Takenori : 03:08 | トラックバック

2005年03月01日

TTrayIconのダブルクリック

C++Builder 6 のTTrayIconを使ってダブルクリックの処理を行いたいと思った。
昔読んだ記憶によるとタスクトレイアイコンのダブルクリックは面倒だったような・・・と思い、"Visual C++ 5パワフルテクニック大全集"を出してきて読むと、タイマーを作ってダブルクリックを判定している。
やっぱり面倒だなぁと思って、いろいろと考えていてふと気づいた。
TTrayIconのRestoreOnプロパティがデフォルトではimDoubleClickになっていて、実際にダブルクリックするとOnRestoreがコールされていたのを思い出した。
だが、イベントを見てもOnDblClickなるものはない。
そこで、grepでソースを探したら、Examples/Controls/Sourceの中に有ったので見てみると、FOnDblClickがプライベートメンバで、プロパティにはない。って、ない!
なぜだ?
ダブルクリックのメッセージが来た時にはキチンDoDblClick()をコールしていて、その中ではFOnDblClickをコールしている。しかし、FOnDblClickにイベントを設定する場所はない。
なんだこれは?
仕方ないので、ソースに変更を加えて、コンポーネントをインストールしようとしたが、重複する名前があるとかで失敗。
あらら。
さてどうしたものか。
サブクラス化を使うか?
HWNDは取得できるし、GetWindowLongを使えば、ウィンドウプロシージャも得られる。
これでいけるかと思ったが、C++Builderのウィンドウプロシージャのプロトタイプが違うのが気がかりだ。しかも、クラスのメソッドを普通に渡せる。
何らかのトリックがあるのだと思うが、どのようになっているのかわからないので不安だ。
C++Builder用のフックする仕組みが用意されていればいいんだけど・・・
でも、TTrayIconを基に独自にコンポーネントを作るのが無難かなぁ。
うーん。
もう少し調べて考えよう。

投稿者 Takenori : 06:16 | トラックバック

2005年03月03日

メニューWebっぽく

タスクトレイアイコンをクリックした時に表示されるメニューをオーナードローを使い、Webっぽく白地に青文字で表示され、ポイントすると下線が入るようにしてみたが、なんかイマイチ。
やっぱり普通のメニューが一番かなぁ。

メニューにアイコンを付けたみた。
微妙。
まあ、わかりやすくなったことはなったけど・・・

投稿者 Takenori : 19:29 | トラックバック

2005年03月04日

アイコンダブルクリック対応とか

タスクトレイアイコンのダブルクリック対応のためにはやはりTTrayIconコンポーネントを独自のものにした方が良さそう。
独自と言っても、サンプルについているソースのOnDblClickイベントを公開しただけのものだけど。

TLabelの一部のテキスト上にカーソルがあるときにカーソルの形状を変えたり、一部分がクリックされた時にブラウザを開くのは厳しそうだ。
やはり、TRichEditを使ったほうが良さそうだな。
でも、TRichEditは使ったことがないので、簡単なサンプルを作ってみるか。

投稿者 Takenori : 02:27 | トラックバック

TrayIconのダブルクリック対応

Borland C++Builderのコンポーネント サンプルのTTrayIconでダブルクリックがサポートされていないのがなんとなくわかった。
単純にイベントに設定できるようにしただけだと、左マウスUPと左ダブルクリックの両方のメッセージがくる。
なので、メニューが表示されつつ、ダブルクリックが効くので、なんか嫌な感じ。
仕方ないので、ダブルクリックメッセージには反応しないようにし、タイマーを使うようにした。
ダブルクリック時間は GetDoubleClickTime() を使って取得し、それをタイマーの時間とする。
で、左マウスUPメッセージがきたらタイマーをスタート、タイマーの処理が実行されるより前にもう一度左マウスUPメッセージがきたら、タイマーをオフにしダブルクリックイベントの処理。タイマーの処理で左マウスUPイベントの処理をするようにした。
これで左クリックも左ダブルクリックも処理できるようになった。

初めから付いている物ではなく、こちらのTrayIconコンポーネントに切り替えたら、実行ファイルのサイズが数十KB減った。
リソースなどは削ったので減っても不思議ではないが、結構減っているのでなんとなく不安。動作は問題ないようだけど。
もともと付いているコンポーネントはサイズでかいのかなぁ。
Delphiでコンパイルされていそうだし。

投稿者 Takenori : 19:31 | トラックバック

2005年03月09日

メジャーバージョンアップを検討中

初期バージョンからいろいろと機能追加をしてきて、現状の構造では厳しい面も見えてきたのでそろそろ再設計したいところ。
で、mixi関連のクラスはxilionと共通化したい。
xilionは後から作っただけあって、その辺りはだいぶマシ。
xilionはすでに内部エンコーディングがUNICODEになっているので、mixi Alertもそうなる。
そして、mixi Alertにメッセージ送受信機能を備えたいと思ったが、mixi Alertはアラートに終始した方が良い気がする。
そこで、xilionにアラート機能を追加し、xilionにメッセージ送受信機能つけようと考え中。
xilionは多機能化路線、mixi Alertはアラート機能重視かな。

投稿者 Takenori : 18:31 | トラックバック

2005年03月10日

特定トピックの対応

設定をタブで分けて、チェックするトピックIDを設定できるようにした。
INIファイルへの読み書きも対応。
次は判定だな。
でも、現在の構造だと少しヤな感じなってしまうけど、仕方ないか。
0.X系列で実装して問題点が洗い出せればよい。

チェックするトピックを限定するのと、動的に確認サイクルを変更する機能を実装したら1.X系列の開発にかかるかな。
でも、その前にxilionに日記保存機能を追加したいところ。
さらに要望が出てきたら、タイミングによってどこで入れるか考えないと。

投稿者 Takenori : 00:39 | トラックバック

2005年03月17日

そろそろヘルプ必要?

設定項目が増えてきたので、そろそろヘルプが必要かも。
出来るだけ、ヘルプがなくても使えるように作っているが、動的に確認サイクルを変更する機能を追加したら流石に必要になりそう。
でも、ヘルプって言っても、HP上に作る予定。
HP上のほうが常に最新になっていいだろう。
バージョンに食い違いが発生する可能性があるけど。
と言いつつ、ヘルプは少し先になりそうだな。
ヘルプなしで使えるのがやっぱり一番だし。

投稿者 Takenori : 18:08 | コメント (4) | トラックバック

2005年03月19日

指定ブラウザで開く

既定ブラウザで開く時は、次のようにすれば、urlで指定したページがブラウザで開かれる。

ShellExecute( Handle, "open", url.c_str(), NULL, NULL, SW_SHOWDEFAULT );

なので、特定のブラウザで開く場合は次のようにすれば良いのかと思っていたが、

AnsiString exeTarget("\"" + CustomBrowserPath + "\" \"" + url + "\"");
ShellExecute( Handle, "open", exeTarget.c_str(), NULL, NULL, SW_SHOWDEFAULT );

そうではなく、次のようにしないといけない。

ShellExecute( Handle, NULL, CustomBrowserPath.c_str(), url.c_str(), NULL, SW_SHOWDEFAULT );

参考ページ:
ShellExecuteでのファイルオープン

投稿者 Takenori : 14:51 | トラックバック

2005年03月22日

WideCharBufSizeのサイズ

AnsiString::WideCharBufSize が返すバッファのサイズと言うのは文字数のようだ。
でも、AnsiString::WideChar に渡すサイズはバイト数と明記している。
なんというか・・・ 合わせるか、明記するかして欲しいものだ。

投稿者 Takenori : 12:36 | トラックバック

暗号化

mixiはメアドやパスワードをそのまま送るので、設定ファイルでは特に何も考えずそのまま保存していた。
暗号化しても、パケット見たら即バレだしと思ったからだ。
でも、設定ファイルに直にパスワードが書かれているのは精神衛生上よろしくないようなので、暗号化対応しようと思って少し調べてみた。
暗号化と言ったらPGPOpenSSLだろうか?
PGPは古いみたいなので、最近はOpenSSLを使うことが多いのかな?
で、少し見てみるが面倒くさくなってきた。
そんなに強力な暗号化じゃなくてもいいような・・・
OpenSSLの暗号化アルゴリズムのうちどれかをお手軽に使えないかなぁ。

OpenSSLのlibcryptoを使えば良さそう。
あれ? blowfishって、C++Builderで使うためのページがあったような。
ここだ。
blowfish も結構有名な暗号化アルゴリズムなのか。
知らなかった。
DES か RC4 を使おうかと思っていたけど、別にblowfish でも問題ないか。
使い方は、BlowFishでファイル暗号化がわかりやすい。
BlowFishを試してみるか。

投稿者 Takenori : 23:01 | トラックバック

2005年03月29日

タスクトレイアイコンが登録できない

時々、起動時に落ちると報告を受け調査。
タスクトレイアイコンの登録できないことが出来ないことがある様子。

原因は、SDK32: 通知領域にアイコンが登録されないことがある のよう。
通知領域のアイコンが消えてしまうことがある によると、『ユニバーサルプラグアンドプレイ機能が動作している場合に、この無応答状態が発生することが確認できています。』とある。

3回ぐらいリトライするようにするかな。
どれぐらいリトライするかやどれぐらい待つかは難しい問題だが・・・
UPnPはそれなりに時間がかかりそうだし。
後、初期化中にSleep()していいかどうかだが・・・
問題はTTimerだな。
このOnTimerイベントハンドラがコールバックとして登録されているとまずいことになる可能性ある。
面倒だが、TTimer はフォームからはずし、自分で生成し初期化するようにしたほうが良さそう。

投稿者 Takenori : 15:24 | トラックバック

Zオーダーのみを変える

アラートウィンドウ表示時はTCustomForm::Showをコールしているが、この場合フォーカスも移動するようだ。
ヘルプによると、『Show メソッドを使うと,フォームの Visible プロパティを true に設定し,そのフォームを画面の最前面に表示できます。』 と書かれている。
フォーカスについては書かれていないけど、SetForegroundWindow をコールしているのだろうか?
SetForegroundWindowは、『定されたウィンドウを作成したスレッドをフォアグラウンドにし、そのウィンドウをアクティブにします。』 と説明されているので、フォーカスも移動しそう。

関数をカテゴリから探すウィンドウの操作 一覧表示 を見て、Zオーダーのみ変更する適当なAPIを探す。
BringWindowToTop が良さそうかと思ったけど、MSDNによるとアクティブにするとある。
むぅ・・・だめかぁ。
でも、MSDNの解説には、『この関数は、Z オーダーを変更するという点では SetWindowPos 関数とよく似ていますが、ウィンドウをトップレベルウィンドウに変更することはしません。』 とも書かれている。
つまり、SetWindowPos でも、Z オーダーを変更できるようだ。
見ると、『SWP_NOACTIVATE : ウィンドウをアクティブ化しません。 』 と言うちょうど良いフラグがある。
これを使えばうまくいきそうだ。

投稿者 Takenori : 21:50 | トラックバック

アラートウィンドウへフォーカスを移さない

Showの代わりに、次のコードを呼ぶようにした。

Visible = true;
SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0,  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOSENDCHANGING );

これで、フォーカスは移さずに、Zオーダーのみを最前面へ変更出来た。

投稿者 Takenori : 22:50 | コメント (2) | トラックバック

2005年04月05日

暗号化を入れてみる

パスワードの暗号化を組み込んで動かしてみる。
ちゃんと暗号化/復号化されてる様子。
3パターンのパスワードを試したが問題なかった。

投稿者 Takenori : 00:55 | トラックバック

自動非表示とツールチップ

アラートウィンドウの自動非表示とツールチップを追加した。
これで、主だったところは追加した・・・ って、タスクトレイアイコン追加時の不具合の修正忘れていた。
直さないと。まあ、その内でいいか。

にしても、いろんな機能が追加されたなぁ。
細やかな機能もいっぱい。

投稿者 Takenori : 23:35 | コメント (2) | トラックバック

2005年04月19日

イベント以外追加

イベントのアラート対応は面倒なので、その他の機能を追加。
オプションがどんどん多くなってきました。
追加していっているから差分で出来るけど、一からとなるとかなり大変かも。
適度な粒度で関数化しているけど、一つのクラスにメソッドが大量にあるのがなんとも…
C++Builderでフォームにいろいろと置いていくと、そのフォームにメソッドがひたすら追加されるから、そのクラスのメソッドが大変なことに。
そろそろ適当にコンポーネントに分けて行かないと今後辛くなりそう。

投稿者 Takenori : 22:33 | トラックバック

2005年05月02日

イベントにも対応

昨日の夕方頃からmixi Alertを使うとログイン状態が解除されてしまう問題に悩まされていたが、今日さらに仕様変更があり、今まで通りで問題なくアクセスできるようになった。
だからと言うわけではないけれど、さくっとイベントの書き込みにも反応するようにした。
イベントのチェックはデフォルトではオフにした。
コミュ書き込みにある特定トピックのみに反応は、面倒なので対応せず。
後、レビューに対応すれば、すべてアラート対象?

投稿者 Takenori : 23:11 | トラックバック

2005年05月07日

レビューにも対応

マイミクシィ最新レビューの更新確認にも対応した。
これですべてアラート可能になったかな。

投稿者 Takenori : 17:58 | トラックバック

2005年05月10日

Vectorの差し替え

Vectorの差し替えは結構時間がかかる。
1~2週間ぐらいとか。
今回は、ゴールデンウィークを挟んだので余計にかかっていそう。
4/27に0.17.0への差し替え依頼メールを送ったんだけど、すでに0.19.0になってしまっている。
差し替えが完了した瞬間に、0.19.0で再度依頼出すかなぁ。
それとも、0.20.0になってから?
0.20.0の予定ないけど。
そろそろヘルプ作る?

投稿者 Takenori : 00:35 | トラックバック

連絡来た

昨日なかなかって書いたけど、今日更新の連絡メールが来た。
実際に反映されるのは水曜か、土曜の午後らしいけど。

投稿者 Takenori : 21:24 | トラックバック

2005年05月11日

アラートウィンドウを閉じると終了

アラートウィンドウへcloseメッセージが行くと、プログラム自体終了してしまうようだ。
たまたま、アラートウィンドウが表示された時に、マウスジェスチャーで閉じる動作をしていて、そのメッセージがアクティブになったアラートウィンドウへ行き、mixi Alertが終了してしまった。
普段、アラートウィンドウに出ているcloseは、hideしているだけなので問題はない。

アラートウィンドウがメインフォームとなっているために起きる問題だが…
途中から、メインフォームは別フォームにして常に非表示にするのが良いことに気づいたが、mixi Alertではまだそのようになっていない。
うーん、分離するのはちょっと大変かも。
簡単に出来そうな気もするけど…
特に大きな問題ではないと思うので、しばらくはそのままにしておく。
機能追加の予定もないし。

投稿者 Takenori : 21:29 | トラックバック

2005年06月28日

ヘルプの作成

mixi Alertのヘルプを書いた。
でも、今までのように細かくバージョンアップするとしたら、ヘルプも細かく書き換えねばならず大変だ。
まあ、可能な範囲内で追従すると言うことにしよう。

投稿者 Takenori : 22:08 | トラックバック

2005年07月16日

メインフォームの分離

今までアラートウィンドウとメインフォームが同じだったので分離した。
これで少しすっきりした。
また、フォーカスの問題を解決するために、VCLを使わずにWin32 APIだけでこのアラートウィンドウを組む事も楽になる。
でも、あんまりそれはやりたくない。
出来れば、VCLを使いつつフォーカスの移動が起こらないように出来ればいいんだけど…

後、メール送信のために少し調べてみた。
Indy Clientsを使うとよさげ。
調べるとIndy Clientsは、オープンソースコンポーネントらしい。
ライセンスは、Modified BSD LisenceとMPL Lisenceのデュアルライセンスとなっているようす。
詳しくは調べてみる必要がありそう。

投稿者 Takenori : 18:33 | トラックバック

2005年09月08日

構造を変えていく

現在ごちゃごちゃしている部分を整理したクラス図を書いてみた。
かなりいい感じになりそう。
一気にバージョンを1とするのではなく、少しずつ内部構造を変えて拡張性を高め、まだ追加していない機能を追加してから、メジャーバージョンを上げよう。

投稿者 Takenori : 01:37 | トラックバック

2005年10月19日

続・アラートウィンドウへフォーカスを移さない

前回の対処方法(以下のソース参照)でもフォーカスが移動してしまう時がある。

Visible = true;
SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0,  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOSENDCHANGING );

移動しない時もあるのだが、いつ移動していつ移動しないのかはなぞ。
C++ BuilderでVCLを使っている以上避けられない問題なのだろうか?
と言う事で、VCLのソースを追ってみた。
でも、Object Pascal…… 変数の宣言で型が後に来るのと、if-thenやbegin-endさえ理解していれば、ある程度勘で読めるはず。

見たところ……
TCustomForm::CMShowingChangedで、表示に切り替わった時にShowWindowがコールされている。
TCustomForm::CMShowingChangedは、TWinControl::UpdateShowingが、メッセージを投げることで呼ばれる。
TWinControl::UpdateShowingは、TWinControl.UpdateControlStateで呼ばれる。
TWinControl.UpdateControlStateは、TWinControl::CMVisibleChangedで呼ばれる。
TWinControl.UpdateControlStateは、TControl::SetVisibleで値がセットされた時に呼ばれる。
TControl::SetVisibleは、Visibleプロパティに値が設定される時に呼ばれる。

実際には途中でいろいろと判定があるが、このような流れでShowWindowがコールされるようだ。

で、すぐに思いつく対処方法はーー
1. 上述の処理を自前で実装して、ShowWindowのところをSetWindowPosにする。
2. GetForegroundWindowで事前にフォーカスのあるウィンドウのハンドルを取得しておいて、自分を表示した後にSetForegroundWindowをコールして元に戻す。
ぐらい。
1. はコードを追った感じだとかなり大変。
でも、CMShowingChangedをオーバーライドすれば…… と思ったけど、privateだった。
そうだ、そうじゃなくてWndProcをオーバーライドしてCM_SHOWINGCHANGEDメッセージへの応答を書き換えれば比較的少ないコード量で対処できそう。
2. の方法に傾きかけていたけど、トリッキーなので避けたいなぁと思っていた。

が、すぐに問題は表出する。
Object Pascalがわからない。
TCustomForm::CMShowingChangedは、100行以上ある大きい関数。
そのほとんどすべてをC++に書き換えたいわけだが、raiseとかInclude()がよくわからない。
Object Pascalを勉強してもいいが……
方法2を使うことにしよう。
これであれば何があっても問答無用でフォーカスを元に戻せる。
ただ、他に機能拡張している途中なので実装はまた今度。
バージョン管理はしているので、ブランチさせてもいいが、マージが面倒。
結構長い間放置していたので、少し先になってもいいだろう。

投稿者 Takenori : 08:37 | トラックバック

続々・アラートウィンドウへフォーカスを移さない

コミュのアドバイスによって解決(?)。
次のようにすれば良いよう。

SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW );
Visible = true;

Visible = true;より前にウィンドウを表示させておけばフォーカスの移動が起こらないようだ。
現在のところこれでフォーカスの移動は起こっていない。
前回の対処方法では、起こる時と起こらない時があったので安心は出来ないが。

投稿者 Takenori : 16:51 | トラックバック

2005年10月21日

URLエンコーディング

WinINetのInternetCanonicalizeUrlを使ってエンコードしたらエンコードされていない。
どうやらこれは、WinINetで使う時に問題のないようにエンコードするだけのようだ。
仕方ないので、C++用の適当なものはないかと探すがないので作った。
時々使うと思うので、ここにメモ。
ソースは次の通り。

#include <string>
#include <vector>
#include <ctype.h>
void UrlEncode( const std::string &in, std::vector<char> &out )
{
    out.clear();
    out.reserve( in.size() * 3 + 1 );    // 最大長で確保
    for( std::string::const_iterator i = in.begin(); i != in.end(); ++i )
    {
        unsigned char c = static_cast<unsigned char>(*i);
        if(c == ' ' )
        {
            out.push_back('+');
        }
        else if( isalnum( c ) || c == '$' || c == '-' || c == '_' || c == '.' ||
            c == '!' || c == '*' || c == '\'' || c == '(' || c == ')' || c == ',' )
        {
            out.push_back(c);
        }
        else
        {
            out.push_back('%');
            unsigned char nibble = (c >> 4) & 0xF;
            out.push_back( nibble < 10 ? nibble + '0' : nibble - 10 + 'A' );
            nibble = c & 0xF;
            out.push_back( nibble < 10 ? nibble + '0' : nibble - 10 + 'A' );
        }
    }
    out.push_back('\0');
}

#ifdef __TEST__
#include <windows.h>
#include <shellapi.h>
#include <mlang.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "shell32.lib")
int wmain( int argc, wchar_t *argv[] )
{
    if( argc < 2 ) return 1;

    // mlan.dllのロードと関数ポインタの取得
    typedef HRESULT (CALLBACK* PCONVERTINETUNICODETOMULTIBYTE)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
    PCONVERTINETUNICODETOMULTIBYTE pConvertINetUnicodeToMultiByte = NULL;
    HMODULE                hMod = NULL;
    hMod = LoadLibrary(_T("mlang.dll"));
    pConvertINetUnicodeToMultiByte = reinterpret_cast<PCONVERTINETUNICODETOMULTIBYTE>( GetProcAddress(hMod, _T("ConvertINetUnicodeToMultiByte")) );

    // ConvertINetUnicodeToMultiByte用の変数準備
    DWORD    dwMode = 0;
    int        srcLen = static_cast<int>( wcslen(argv[1]) );
    char    outbuf[1024];
    int        destLen = 1024;
    if( pConvertINetUnicodeToMultiByte( &dwMode, CP_UTF8, argv[1], &srcLen, outbuf, &destLen ) == S_OK )
    {
        outbuf[destLen] = '\0';
        std::string in( outbuf );
        std::vector<char> out;
        UrlEncode( in, out );
        std::string url("http://www.google.co.jp/search?hl=ja&lr=lang_ja&q=");
        url += std::string(&(out.at(0)));
        ShellExecute( GetDesktopWindow(), "open", url.c_str(), NULL, NULL, SW_SHOWDEFAULT );
    }
    if(hMod) FreeLibrary(hMod);

    return 0;
}
#endif // __TEST__

__TEST__の部分は、コマンドラインで引数にとったものを使いGoogleで検索している。
mlang.dllのロード周りのエラーチェックなどはやっていない。
後、__TEST__の部分を動かすにはIE5.5以降が必要。

投稿者 Takenori : 10:28 | トラックバック

2005年11月06日

設計変更

初期の設計のままで、今まで機能拡張を行ってきたが、更新情報リスト機能を追加するにあたって一部設計をしなおすことにした。
そして、HPアクセス部分を設計し実際にコーディングした。
この部分の設計自体はかなり汎用的で、アクセスする対象がmixiじゃなくてもそのまま適用できる。
CHomePageクラスにどこのページの情報が欲しいと要求すれば、そのページの情報が扱いやすい状態で返ってくるといったものになっている。
ただし、実装自体はmixiに特化しているので、他のページを扱う時にソースコードをそのまま持っていくといったことは出来ない。
そもそも、そのようなことは現在考えていない。
どこかのページへアクセスして何かする場合は、perl+wgetで作るか、phpにすることが多いので、あまり汎用的なソースコードにしても今は仕方ない。

特定ページの情報が得られた後は、フィルタークラスを使って情報をふるいにかける。
オプションでOFFにされているものや、前回と同じものなどはフィルタークラスを使って削る。
フィルタークラスは継承を使っており、簡単に情報のふるいを実装できるようにしている。

ふるいにかけられた情報はNotifierに渡される。
Notifierは、サウンドを鳴らすや、ウィンドウを表示するなどを実装したクラス。
これもフィルタークラスのようにして、通知方法を追加しやすいようにしている。
機能追加予定にあるメールで通知する機能も、このクラスで実装する。

と、今回はここまでの設計変更にしようかと思っていたのだが、オプション設定周りも変更してしまおうと思い直す。
まあ、今回の変更が終わった後、MVC的な構造にしようと思っていたので、遅かれ早かれ変えるつもりではいたが。
と言うことで、その辺りを今設計中。
クラス図がかなり大きくなってきた。

こうなってくると将来追加しようと思っている機能の設計もやってしまったほうがいいかな。
ついでに実装もしてしまうか?
今まで細かくリリースしてきたけど、今回で予定しているものをほとんど実装してしまって、無駄に拡張性を持たせた構造にするのもいいかも。
でも、そうなると1週間ぐらいかかってしまうなぁ。
後、2、3日で出来る程度にとどめておくか。

しかし、今回の設計変更でクラスの数が増えた。
前は5個ぐらいしかなかったのに。
その分機能追加が行いやすい構造になってはいるが。

投稿者 Takenori : 01:46 | トラックバック

2005年11月12日

mixi読込みをスレッド化

今回の変更でmixiからの読込みをスレッド化している。
非同期読み取りメカニズムのあるライブラリを使えばこんなことをしなくてもいいんだろうけど、今まで通りの方法でWinINETを使っているので、別スレッドにした。

ワーカースレッドの処理はCommandパターンで実装した。
具体的には…
フォームがキューへ実行したいコマンドを入れたオブジェクトを入れイベントをセット。
ワーカースレッドは、イベントがセットされたらキューを確認し、コマンドを取得実行する。
コマンドの実行はキューが空になるまで行う。
処理の終了通知はコマンドの中に埋め込む。(フォームが作ったコマンドの最後でフォームへメッセージを投げるようにしている)

これによって様々な処理をワーカースレッドへ依頼出来るようになる。
ただし、mixi Alertではmixiへのアクセスのみ。

今まではすべて一つのスレッドにしていたので、時々メニューのレスポンスが落ちていたが、この変更によってそのようなことは減るはず。

投稿者 Takenori : 20:49 | トラックバック

2005年11月15日

mixiからの読み取りまでのmake

メンバ関数ポインタなどのテンプレートでかなり手間取ったが、なんとか読み取り処理が出来る段階までのmakeが通った。
動作確認はまだ。
やはり一気にやるとコンパイルエラーでまくりで大変だ。
アラートウィンドウを表示する部分などは少しずつ追加していくことにしよう。

投稿者 Takenori : 23:20 | トラックバック

2005年11月19日

デバッグしてたら

makeが通ったのでデバッグ。
相変わらずBCBのデバッガは使いづらい。
それより、なぜかブレークポイントで止まってくれないことがよくある。
一度でも止まると、その実行中は問題なく動いているのだが、一度終了して次やると止まらなかったりする。
再構築したりブレークポイントの設定をいじったりしていると突然ブレークポイントがきくようになったりする。
なんか、すごいイライラする。
次からはwxWigetsで組み直すか? などとも考えてしまう。
うーむぅ。
いったい何が原因なのだろう?
なんかこのマシンのBCBは不調だ。

それでもデバッグを続けているとコミュニティーの最新書き込みが取得出来ないことに気付く。
なんだろうなぁ? と思ったら、mixiの方で仕変があったようだ。
URLが変わってる。
対応したらきちんと取得できるようになった。
これでmixiのhome.plからのデータ取得部分は確認出来た。
次はここから差分をとって通知するところ。
そこはまだ組んでいないのでこれから組まないと。
後、ログイン部分の確認もまだ。
今回の変更で、ログインされていない時のみログインするようにした。
これによって通信量が少し減るはず。
そうだ、500 Internal Server Errorのチェックも入れようと思っていたんだった。

投稿者 Takenori : 22:54 | トラックバック

2005年11月21日

読み込みエラーの処理など

ログインの確認が出来ていなかったので、クッキーを消してデバッガで追った。
home.plが読めなくてログインページだと認識した場合には、キチンとログイン処理をすることを確認。
これで、ログインできていない場合のみログイン処理をするようになった。
また、Internal Server Errorの判定も追加。
今まで、ログインが失敗した場合は無条件でアカウントやパスワードがおかしいのでは? とエラーを出していたが、Internal Server Errorの場合はリトライするようにした。
何度もInternal Server Errorが出る場合は、次の確認時間まで確認しないようにした。

読み込み終了メッセージのハンドラも追加し、エラーの場合の処理は書いた。(タイマーを再び動かすの忘れてた)
次はフィルターを適用するようにするのと、Notifierのコーディングしないと。

投稿者 Takenori : 02:09 | トラックバック

フィルター部を追加

フィルターで足りなかったものを追加した後、適用する部分も追加。
Notifierもサウンドとウィンドウのみ追加。
もうそろそろ出来そう。
どうも、mixi Alertの開発意欲がわかず、微速前進中。
でも、ま、そのうち出来るっしょ。

投稿者 Takenori : 22:41 | トラックバック

2005年11月24日

Notifierを作った

Notifierを作りビルドした。
呼び出す部分の処理はまだ書いていない。
後もうちょっとで動作確認。
でも、teaspireのツールの方が楽しいのでそっちをやってしまう。
そしたら、「この前言ってたやつまだ?」と言われた。
もうちょっと言っておく。

投稿者 Takenori : 02:23 | トラックバック

2005年11月26日

TrayIconのToolTipが変わらないと思ったら...

一通り機能を組み込みデバッグ。
動くようになったと思ったら、TrayIconのToolTipが変わらない。
ソースコードを追ってみても怪しいところは見当たらない。
トレースしてみると、TrayIconコンポーネント内ではじかれてた。
Shell_NotifyIconに渡すNOTIFYICONDATAのszInfoは64文字(\0を含む)までだとか。
Shell32.dll がversions 5.0以降なら128文字(\0を含む)になるようだ。

そこで、64文字を超えている場合は60文字にした後、"..."を加えることにした。
Shell32.dll のバージョンを調べてからサイズを変更しても良いが、そこまでする必要もないだろう。
なんかいっぱいあることがわかればいい。

後、ついでにSDK32: 通知領域にアイコンが登録されないことがあるの対策も行っておく。
ただし、登録の時のみしか対策していない。
ま、登録されないことがあるなので、これで大丈夫でしょう。

投稿者 Takenori : 16:58 | トラックバック

remove_ifの思い違い

オプションでOFFにしてあるはずなのになぜか通知されるのでソースを追うが良くわからず。
remove_ifで消しているはずなんだけど…… と悩み、remove_ifの動作について調べてみた。
削除アルゴリズムに解説があった。
remove_ifは削除するのではなく、移動するだけ!?
知らなかった。
今までは大体findで見つけてeraseしていることがほとんどで、remove系は使ったことなかった気がする。
removeだけど、移動するだけだったのか。
removeの意味を辞書で見てみると最初に「移動させる」って意味が載っていた。
remove=削除って思い込んでいたけど、そうじゃないのか。

投稿者 Takenori : 23:28 | トラックバック

2005年11月30日

一つずつ片付ける

mixi Alertへ更新をリスト表示する機能の追加を行った。
次は設定を追加する予定。
他にも追加を予定している機能がいくつかある。
しばらくは、と言っても数日だけどmixi Alertへの機能追加をすることにした。

その次は吉里吉里のVMR機能を片付けよう。
その後はSara。
いろいろと中途半端になっているので、着実に片付けていくことにした。
でも、吉里吉里で作ってるのもSaraで作ってるのも絵が上がってこないのが何とも……
システム出来てもゲーム完成しないのぅ。
ま、そのうち上がってくるっしょ。

投稿者 Takenori : 22:49 | トラックバック

2005年12月01日

タクスバーからアイコンを消す

Formを表示した時のwindowsタクスバーの表示
アクティブなウィンドウだけをタスクバーに表示
タスクバーに表示されないようにする
実行時にタスクバーアイコンの表示・非表示を切り替える方法
これらのリンクを参考にやってみるも、どうもうまくいかない。
振る舞いがおかしくなったり、Tool Windowの見た目が変わったり。
Main Formを常に非表示にしているのが関係あるのか?
タスクバーへアイコンが表示された後、1回消すとなぜか表示されなくなし。

で、一瞬だけMain Formを表示した後、非表示にするようにしてみたが、特に効果なし。
次に何らかのWindowが表示された時にはやはりタスクバーへアイコンが表示される。

Application 変数3.2.3 アプリケーションウィンドウのメッセージ処理3.2.4 アプリケーションウィンドウの問題点が関係ありそうだ。

そもそもの問題は、Formを表示した時にタクスバーにアイコンが表示され、そのアイコンをクリックするとFormが消えてしまうのだが、FormのVisibleプロパティはtrueのままなこと。
そこで、GetWindowPlacementを使い最初化状態かどうかを調べて、最初か状態ならリストアするようにしたのだが、状態はSW_SHOWNORMALになっている。
それではとTApplicationEvents コンポーネントを使い、OnMinimizeへメソッドを設定、設定したメソッド内ですべてのFormをHideにした。
これで、Visibleプロパティはfalseになったのだが…… タスクバーのアイコンのメニューが変。
なぜか元に戻すが有効になっている。
Formは表示されているのだが……
そういえば、OnMinimizeでHideを呼んでいると、次にFormを表示した時にはタスクバーのアイコンが復活する。
呼ばなかった場合は、タスクバーのアイコンは消えたままだ。
なんだろう?
変だ。

タスクバーのアイコンは謎だが、GetWindowPlacementでSW_SHOWNORMALが返ってきたのは、調べた対象がFormだからではないか?
そこで、GetWindow( Handle, GW_OWNER )を使用してオーナーウィンドウ、つまりVCLのアプリケーションウィンドウを取得し、そのウィンドウハンドルをGetWindowPlacementで調べるとSW_SHOWMINIMIZEDが返ってきた。
ならば、ShowWindow( hOwner, SW_MINIMIZE )で最初に最小化しておけばと思ったが、やってみると初めからタスクトレイにアイコンが表示されることになっただけ。

オーナーウィンドが最小化状態でかつFormのVisibleがtrueの時はリストアを呼ぶようすれば…… と思ってやってみたが、Formを閉じてもタスクトレイにアイコンが残るようになった。

OnMinimizeでHideを呼ぶのでいいかな。
タスクバーのアイコンのメニューが少し変だけど。
それにしてもいろいろと不可解だ。
どうなっているのだろう?
もう一度整理して考えた方がいいかもしれないな。

投稿者 Takenori : 01:36 | トラックバック

2005年12月02日

続・タクスバーからアイコンを消す

拡張ウィンドウスタイルには、WS_EX_APPWINDOWと言うものがあり、これを指定するとウィンドウが表示されているときには、必ずトップレベルウィンドウがタスクバー上に置かれるようになる。
つまり、このスタイルが設定されているものがあると、タスクバー上にアイコンが置かれてしまう。
が、オーナーウィンドウ(アプリケーションウィンドウ)にはWS_EX_APPWINDOWは設定されていないようだ。
また、メインフォームにも設定されていない。
つまり、オーナーウィンドウが表示状態の時にタスクバーにアイコンが置かれると思われる。
そこで、オーナーウィンドウの表示状態をGetWindowPlacementで調べることにした。
まず、フォーム生成時のフォームが非表示の時はSW_SHOWNORMALだった。
フォームが表示された時もSW_SHOWNORMALだった。
あれ?
上述の推測は間違ってた。
オーナーウィンドウが表示状態でかつ他のいずれかのフォームが表示状態の時にタスクバー上にアイコンが置かれるようだ。(メインフォームが非表示の場合?)

と言うことは、オーナーウィンドウの状態とフォームの状態によって、タスクバーにアイコンが出たり出なかったりするようだ。
そこで、フォームが表示される時にオーナーウィンドウを非表示にしてみた。
タスクバー上のアイコンは消えた。
やった。
これで目的は達した。
でも、何かしら問題があるかもしれないので、いろいろと動作確認した方が良さそう。

投稿者 Takenori : 16:58 | トラックバック

2005年12月03日

非メインフォームを常に最前面ウィンドウに

多くのページでは
SetWindowPos(Handle,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE );
とすれぱ、常に最前面に出来るとか、FormStyleにfsStayOnTopを設定すれば、出来ると書かれていたが、それはメインフォームの場合で、そうでないフォームだとそれでは出来ない。
VCLの場合、アプリケーションが非アクティブになる時にTApplication::NormalizeTopMoststがコールされ、メインフォーム以外の最前面ウィンドウを非最前面ウィンドウに戻してしまうようだ。
それではと、TApplication::OnDeactivateでまた最前面ウィンドウになるようにしたのだが、それでは不十分だった。
非最前面ウィンドウに戻されてしまうケースがある。
その後いろいろなイベントで最前面ウィンドウになるようにしてみるがうまくいかず、諦めてメインフォームにしてみたら、SetWindowPosとfsStayOnTopでうまくいった。
が、そのフォームをメインフォームにしてしまうといろいろと都合が悪い。
で、非メインフォームに戻すと最前面ウィンドウでなくなるケースが発生する。

もう無理かなと諦めかけていて気付いた。
非最前面ウィンドウになる時になんらかのメッセージが送られてくるのではないか?と。
調べると、WM_WINDOWPOSCHANGINGがウィンドウのサイズ、位置、または Z オーダーが変更される時に呼ばれるようだ。
SetWindowPosがSWP_NOSENDCHANGINGフラグ付きで呼ばれた場合、このメッセージは送られてこないようだが、幸いVCLのソースを見るとSWP_NOSENDCHANGINGフラグは付いていない。
そこで、目的のフォームでWM_WINDOWPOSCHANGINGをディスパッチすることにした。
WM_WINDOWPOSCHANGINGメッセージのlParamがWINDOWPOSへのポインタになっているので、WINDOWPOS::flagsにSWP_NOZORDERが付いていない時で、WINDOWPOS::hwndInsertAfterがHWND_TOPMOSTでない場合に再びSetWindowPosで最前面ウィンドウにするようにした。(実際の処理は設定によって切り替わる)
で、実際に動作させてみると常に最前面ウィンドウになるようになった。

投稿者 Takenori : 14:03 | トラックバック

WebBrowser Controlを使う

文章中の一部の文字をクリックしたらリンク先をブラウザで開くってことがやりたいというのと、HTMLでの整形を考えてWebBrowser Controlの使用を考える。
C++ BuilderだとTCppWebBrowserを使えば、少し楽が出来るようだ。
単に特定のページを表示するだけであれば、CppWebBrowser->Navigate(L"url");とすれば出る。
でも、やりたいのはメモリ上にある文字の表示。

IEコンポーネントの使い方 そのほかのTipsの『about:blank のページに動的にページを入れ込みたい』にメモリ上のデータを表示する方法が書いてある。
C++だとBSTRやVARIANTは、_bstr_tや_variant_tを使った方が楽。
SAFEARRAYはCComSafeArrayを使った方が楽そうだが、C++Builderだとヘッダーがなかった。
それはともかく、ほぼこの通りにしたら出た。
リンクページでは、whileで読み込み待ちをしているが、DocumentCompleteを使った方が良い思われので、そうした。
IHTMLDocument2はCppWebBrowser->Document->QueryInterface( IID_IHTMLDocument2, (void**)&pDoc );として取得した。
でも、この方法よりもIStreamを使う方法の方が良さそうだ。
vectorやstringをラップしたIStreamクラスを作った方が手軽に書き換えられそう。(どっちも大差ないか?)

投稿者 Takenori : 23:23 | トラックバック

WebBrowser Controlでイベントに反応する

IEコンポーネントの使い方でonclick や onmouseover などのイベントをハンドルしたいが出来ないと書いてあったのでリンクを見てやったみたら、すんなり出来た。
具体的には、

DocumentCompleteで次のようにしてオブジェクトのコネクション ポイントとクライアントのシンクとの間に接続を確立。

    hr = pDoc->QueryInterface(&pSrcUnk);
    hr = AtlAdvise(pSrcUnk, pSink, DIID_HTMLDocumentEvents, &dwDocCookie);

pDocは、読み込んだドキュメントのIHTMLDocument2を表している。

BeforeNavigate2で次のようにして、以前のドキュメントに確立された接続を終了。

if( pSrcUnk )
{
    hr = AtlUnadvise(pSrcUnk, DIID_HTMLDocumentEvents, dwDocCookie);
    pSrcUnk.Detach();
}

pSrcUnkはCComPtr<IUnknown> pSrcUnk;と定義している。

シンクのヘッダーは次のようにした。

#ifndef __EVENT_SINK_H__
#define __EVENT_SINK_H__

#include <oaidl.h>

class CEventSink : public IDispatch
{
protected:
    int m_cRef;

public:
    CEventSink() : m_cRef(1) {}
    ~CEventSink() {}

    //Methods of IUnknown
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
    ULONG STDMETHODCALLTYPE AddRef();
    ULONG STDMETHODCALLTYPE Release();

    // Methods of IDispatch
    STDMETHOD (GetTypeInfoCount)(UINT* pctinfo) { return E_NOTIMPL; }
    STDMETHOD (GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
    STDMETHOD (GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; }
    STDMETHOD (Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr);
};
#endif

ソースは次のようにした。

#include "CEventSink.h"
#include <olectl.h>
#include <mshtmdid.h>

// {8773DF07-30E6-4f21-9568-2B6D326626D7}
static const GUID IID_ClickEventSink =
{ 0x8773df07, 0x30e6, 0x4f21, { 0x95, 0x68, 0x2b, 0x6d, 0x32, 0x66, 0x26, 0xd7 } };

HRESULT STDMETHODCALLTYPE CEventSink::QueryInterface(REFIID iid, void** ppvObject)
{
    if (iid == IID_IUnknown || iid == IID_IDispatch|| iid == IID_ClickEventSink)
    {
        if( ppvObject == NULL ) return E_POINTER;
        *ppvObject = this;
        AddRef();
        return S_OK;
    } else {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }
}
ULONG STDMETHODCALLTYPE CEventSink::AddRef()
{
    m_cRef++;
    return m_cRef;
}
ULONG STDMETHODCALLTYPE CEventSink::Release()
{
    int ret = --m_cRef;
    if (ret <= 0) {
        delete this;
        ret = 0;
    }
    return ret;
}
HRESULT STDMETHODCALLTYPE CEventSink::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
    HRESULT hr;
    if( dispid == DISPID_CLICK ) {
        pvarResult->vt = VT_BOOL;
        pvarResult->boolVal = TRUE;
        hr = S_OK;
    } else if( dispid == DISPID_EVMETH_ONCONTEXTMENU ) {
        pvarResult->vt = VT_BOOL;
        pvarResult->boolVal = TRUE;
        hr = S_OK;
    } else {
        hr = DISP_E_MEMBERNOTFOUND;
    }
    return hr;
}

DISPID_CLICKは左クリックされた時のイベントで、DISPID_EVMETH_ONCONTEXTMENUはコンテキスメニュー(右クリックメニュー)が表示され時のイベント。
これらのイベントはmshtmdid.hに定義されている。
上述のようにするとコンテキスメニューは表示されなくなる。
が、良く考えたらテキストが選択されていた場合などで表示するメニューを変えたいので、IDocHostUIHandler を実装して設定してやる方法の方が良さそう。
それはまた今度やろう。

投稿者 Takenori : 23:42 | トラックバック

2005年12月08日

どこまで組み込もう?

数日で終わらせようと思っていたけど、もう少し機能を組み込むことにしたので1、2週間かかりそうだ。
組込みたい機能はまだまだあって、それ全てを組込もうと思ったら数ヶ月~1年かかりそうだ。
そして、全てを組み込んだらすでにmixi関係ないじゃないか状態になる。
ま、まずはmixi関連機能を追加していこう。

今の機能追加は今週中に終わらせる予定だが、その他はどうしようかと考え中。
今月いっぱいはmixi Alertの機能追加に費やしてもいいかとも思ってはいるが……
やるとしても後+1週間ぐらいかな。
その1週間で追加する機能があればしばらくは十分。
機能を追加したらなんやかんやと出てくるし、見えていなかったものも見えてくる。
しばらく考えた方がいいだろうし。
インターフェイスも見直さないとなぁ。

投稿者 Takenori : 03:27 | トラックバック

2006年01月31日

ファイルのアップロード

日記アップロード機能を付ける時、一緒にファイルのアップロードもやろうとしたけど、なぜだかうまくいかなかったので、とりあえずファイルのアップロードは非サポートとしてリリースした。
でも、やはりファイルのアップロードは出来た方が良いと言うことで再調査。

ファイルのアップロードにはmultipart/form-dataが使われている。
この仕様自体はそれほど難しくなく、区切り文字列を定義してその文字列でデータを区切ってつなげたものをPOSTすればいいはずなのだが、うまくいかなかった。
リプレイ付きオンラインランキングの苦労話にあるように、謎の2バイトを追加したりしたのだが、前回はうまくいかなかった。
今回も前回同様Etherealを使ってブラウザでアップロードした時のパケットの中身を見てみる。
ただし、前回はFirefoxでやっていたが、今回はIEにした。
で、出来るだけパケットの中身が一致するようにしてみる。
前回のソースコードを復活させて実行してみるとサイズが違う。
謎の2バイトが足りないようだった。
"--"を足して動かしてみる。
すんなりアップロードできた……
あれ?
前は何に苦労していたのだろう?
まあ、なんだかわからないけれどうまくいったのでよしとしよう。

投稿者 Takenori : 00:19 | トラックバック

PNGの読み込み

mixiの日記にアップロードできるのはJPEGのみだ。
だけど、ツールとしてはいくつかのファイルフォーマットをサポートしていた方が使い勝手がいいだろう。
と言うことで、JPEG以外にPNGとBMPもサポートすることにした。
C++BuilderではJPEGやBMPは読めるがPNGは読めない。
GDI+を使うか、libpngを使って自分でサポートするか。
ってか、PNGならコンポーネントが公開されていそうだ。
と言うことでDelphian Worldで検索。
すぐに見つかった。
GLDPNGを使うことにした。
GLDPNGはBSDライセンスのようなので、気軽に使えそうだ。
でも、Delphi用でパスカルで書かれている。

C++Builderでの使い方を調べると意外と簡単。
ユーザーコンポーネントのプロジェクトにGLDPNGの*.pasを加えてコンパイルしたら、*.hppファイルが自動的に出来る。
後は、GLDPNGを置いたパスをライブラリとインクルードディレクトリに追加して、必要なhppをインクルード。
メイクしたら使えた。

他にSUSIEプラグインをサポートすることも考えたが、JPEGとPNG、BMPがあれば十分だろう。GIFも欲しいかもしれないがそこは気にしない。
ただし、クリップボードに入っている画像も添付出来るようにする予定。
GIFをどうしても使いたい場合は、他のツールで変換しなくても、とりあえずブラウザなどにD&Dして表示させ、画像をコピーしてクリップボードに入れた後貼り付ければいい。
他にもクリップボードを介せばいろいろと使える。
ひと手間増えるけどそんなに使わないだろうからいいだろう。

投稿者 Takenori : 00:28 | トラックバック

2006年02月11日

ブルースクリーン

Windows XPでmixi Alertを使い始めてから1・2週間経った頃から時々フリーズしたり、青画面が表示されたりするようになったと言う記述を見かけた。
フリーズしたり、青画面になるような不具合は致命的だ。
普通のWindowsアプリケーションで青画面を表示するようなプログラムを組む方が難しいと思うのだが、そうでもないのだろうか?
なんにしても、対策しないといけないと言うことで情報を集めることにした。
やっかいなことに、自分の環境ではまったく発生していないので、全然気付かなかった。
でも、4件ぐらい情報が得られたことから、それなりに発生するようではある。

いったいなぜ発生するのか謎だったのだが、青画面になった時のスクリーンショットを得られたことで一気に解明に向かった。
青画面でのエラーは、IRQL_NOT_LESS_OR_EQUALだった。
そこで、IRQL_NOT_LESS_OR_EQUALについていろいろと調べる。

IRQL_NOT_LESS_OR_EQUALについては、偽偽夜食日記 - IRQL_NOT_LESS_OR_EQUALに詳しい解説があった。
ドライバの不具合のようだ。
当然のことながら、mixi Alertはドライバではない。
ググった他のページなどを見てみると、メーカー製パソコンで発生したと言う記述も多い。
自作マシンより、メーカー製パソコンを使っている人の方がドライバのアップデートは少なそうだから、そういう人の方がよく目にするのかもしれない。
自分の周りからこの問題の話を聞かなかったのはその辺りが関係しているかもしれない。

そして、次のような発生傾向があるようだ。
・CPUが過負荷状態になると発生しやすくなる。
・メモリアクセスが多いと発生しやすくなる。
・セキュリティーソフトが入っていると発生率が高くなる。

上のリンクの解説から考えると、DPC/ディスパッチレベル以上のレベルでページ可能メモリにアクセスしてしまっているドライバがあり、その付近でメモリがアクセス過多になるとページフォルトが発生し、スケジューリングも発生、IRQL_NOT_LESS_OR_EQUALでブルースクリーン。
と言った流れだろうか。
CPUが過負荷状態と言うのは、メモリアクセスが多くてスワップなどが発生し重いから過負荷状態だと思ったしているのかもしれない。
後、セキュリティーソフト云々は、メモリを監視するセキュリティーソフトによってメモリアクセス過多が発生と言うことのようだ。

また、IRQL_NOT_LESS_OR_EQUALの発生はハードウェアの不具合の可能性もあるとか。
で、対策としては、memtest86、もしくはmemtest86+でメモリをチェックしたり、ドライバを最新のものにすることだ。
最新のドライバにしてもまだ不具合があるかもしれないけど。


そもそも、なぜmixi Alertでこの問題が表出したのだろう?
Process Explorerでmixi Alertを見てみると、Page Faultsが妙に多い。
その辺りが原因か。
でも、なぜPage Faultsが多いのだろう?
mixi Alertは常駐型でずっとアクティブじゃない。
定期的にWebにアクセスする。
その間隔は分単位。
つまり、1回使った後しばらく使わないからページアウトが行われやすいのかも。


ところで、ページ可能メモリじゃないメモリとかってどこだろう?
どこかドライバ用に用意されているのかな?

投稿者 Takenori : 13:48 | トラックバック

2006年02月13日

SQLiteのトランザクション

トランザクションなしで何件もデータを追加すると重いな。
何度かそういう記述を見かけたが、今まで実感がなかった。
で、実際にトランザクションなしで作ってて、固まった? と思ったら、70件程度のデータ追加があったからだった。
はじめはなぜそこで重くなるのかわからなかったけど、もしかしてSQLite? と思ってトランザクションを追加するとかなり軽くなった。
この程度ならなくてもいいだろうと思っていたが、そうでもないようだ。
データを追加する際はなるべく明示的にトランザクションした方が良いかも。
1件だけなら同じだろうけど。

投稿者 Takenori : 16:00 | トラックバック

2006年02月15日

SQLiteと日本語パス

まだ書いていなかったのでメモ。
古いバージョンのSQLiteだと、データベースファイルのパスにマルチバイト文字が含まれているとうまく扱えないようだ。
どうやら、ファイルパスもUTF-8で扱ってしまっていたようで、保存や読込みがうまくいかない。
この問題はSQLiteの3.1.3を使っていた時に起こった。
でも、その時の最新版だったSQLite 3.2.8にしたら問題は解決した。
ざっと変更履歴を見てみたが、この不具合がいつ直ったのかはよくわからない。
細々とした不具合修正のなかに入っているようだ。
なので、SQLite 3.2.8より古いバージョンを使う場合には気をつけたほうが良さそう。

投稿者 Takenori : 13:47 | トラックバック

SQLiteでレコードの削除

SQLiteでレコードを削除しても、ファイルにはそのレコードの残骸が残る。
その残骸は、VACUUMを実行すると消される。
残骸が残っていても特に問題はないようなので、削除を時々実行するような使い方をする場合は、時々VACUUMしてやればいいようだ。
後、autovacuumと言う設定があるようだが、詳しくは知らない。
mixi Alertでは起動時にVACUUMをするようにしているがそれで十分。

投稿者 Takenori : 13:59 | トラックバック

SQLiteとSenna

全文検索のためにSennaのSQLiteバインディングないかなぁと探すも見付からず。
あんまり真剣に探していないけど。

SQLiteのページ見るとバージョンアップが激しいのでなかなか大変かも。
SQLで何とかしようとせずに別に使った方がいいかな。

投稿者 Takenori : 23:51 | コメント (2) | トラックバック

2006年02月16日

SQLiteに全文検索を?

MySQLには全文検索用の構文"MATCH(field) AGAINST('検索クエリ' IN BOOLEAN MODE)"というものがあるけど、SQLiteには同じ物はないようだ。
だから全文検索を追加するとしたらそれ用の構文も追加する必要がある。
まあ、MySQLと同じでいいと思うけど。

SQLiteの構文解析器はyaccで書かれている様子。
.lファイルは見付からないので字句抽出器はlexじゃなさそう。

parse.yを見てみた。
yaccの記述方法忘れてる……
左のものは右のパターンで表される。で、右に現れたものを今度は左に書いて……
と記述していくのは何となく覚えているけど、細かい部分はよくわからない。
lex/yacc本を見て思い出さないと。


SQLiteのソースをざっと見た感じではSennaのSQLite組込みはそんなに大変と言うことはなさそう。
でも、まだ必要ないからやるのはもう少し先かな。
1Mぐらいのデータベースファイルであれば、 LIKE %KEY_WORD% で検索かけてもそんなに遅くないし。インデックスがあれば一瞬だろうけど。

投稿者 Takenori : 18:02 | トラックバック

Webサービスクラスター

mixi内で出来ることは限られている。
例えば、メッセージにファイルを添付することは出来ない。(メールのようにエンコード/デコードすれば出来ないことはないが)
そこで考えていた方法として、Yahooのブリーフケースを利用すると言うものがある。
つまり、Yahooのブリーフケースにファイルを上げてからメッセージにはそのURLを添付することでファイルの送信を実現する。

これと同じような感覚で、1つのサイトでは実現できないことを複数のサイトの機能をクライアント側で集約し、あたかも1箇所で様々な機能が利用できるようなものにしていこうと考えていた。
スケジュールやブックマーク、掲示板など欲しい機能はいろいろとある。
が、そんなことしなくても欲しい機能を詰め込んだサイトを自分で作ってしまった方がいいんじゃないかと思った。
前から作ろうと思っていたHPにそれらの機能も追加してしまおう。

投稿者 Takenori : 18:17 | コメント (2) | トラックバック

2006年02月18日

SQLiteへのSennaの組込み方

前回はSQLiteのSQL文を拡張することで対応することを考えていたけど、pg_sennaの実装方法を見て、構文を拡張するのではなく、トリガーとユーザー定義関数のみで実現出来そうだと気付いた。
そのように実装すればSQLite本体に手を加える必要はなくなる。

SELECT create_fulltext_index( 'table_name', 'column_name' );
でインデックスを作り、
SELECT * FROM table_name WHERE fulltext_index_match( 'coluon_name', 'words', true );
と言うように検索をするとか。(このままで実現できるかどうかわからないけど)
fulltext_index_matchの最後のtrueは、集合演算(?)を使うかどうか。
つまり、'+word1 -word2'とかすると、何々を含んで、何々は含まないものと言うようなことが出来るやつ。
MySQLにあったのでそれと同じようなことをするものがあった方がいいなぁと思って付ける事に。

でも、よくよく考えるとmixi Alertではこれを使わないかも。
日記などのバックアップ先はSQLite内ではなく単なるファイルとして保存した方が手軽な気がする。
で、DB内にはそのファイルへの参照やタイムスタンプ、タイトルだけ持てばいい。
本文はSennaでインデックスを作り、別途検索出来ればその方が扱いやすいだろう。
と言うことで、mixi Alertの日記バックアップ機能に関しては、これは使わないな。
Webの方では使うと思うので作るけど。

投稿者 Takenori : 21:45 | トラックバック

2006年03月05日

WinInet 以外を考える

別に WinInet を使っていても大して困らないと思うけど、IEバージョン依存の問題や移行を考える時のために他の手を探した。

WinSockを使って1からゴリゴリと言うような骨の折れることは初めから考えないとして、良さそうなライブラリがないかググって見るがすぐには出てこない。
そこで、wxWidgets の wxHTTP が使えないかやってみた。

wxbase26_net.lib wxbase26.lib wsock32.lib をリンクすれば使えるみたい。
使い方は次のような感じ。(エラー処理をまったくしていないのでこのままでは使えない)

#include <stdio.h>
#include "wx/protocol/http.h"
#include <vector>
#include <memory>

int main( int argc, char *argv[] )
{
  wxHTTP http;
  http.Connect(wxT("www.kaede-software.com"));
  std::auto_ptr<wxInputStream> in( http.GetInputStream( wxT("/") ) );
  size_t size = in->GetSize();
  if( size == -1 ) {
    size = 256 * 1024; // 256KBと仮定
  }
  std::vector<char> data(size,0);
  in->Read( &(data.at(0)), size ) );
  printf( "%s", &(data.at(0)) );
}

これでhttp経由でデータを取ってこれる。
POSTを使ったり、クッキーを使ったりする場合はもう少しいろいろとする必要があるけど、結構手軽に利用できる。
上記のプログラムで実行ファイルのサイズは184KB。
wxWidgets の wxHTTP を使うのもありかもしれないな。

投稿者 Takenori : 22:38 | トラックバック

2006年09月18日

マイミクのグループ化

少し前になるが、mixiにマイミクのグループ化機能がついた。
でも、現状まったく使えない機能。
グループは、フィルタリングと一括処理のためにあるのに、今のところそれっぽい機能がない。
でも、mixi Alertとしては、かなり期待の機能。
グループを取り込む機能を早めに実装したいところ。
グループがあれば、メッセンジャーのマイミクリストの上にグループのプルダウンメニューを付けて、グループを選択することであて先をフィルタリング出来る。
後、グループへ一斉送信も可能。
他に日記の通知などのフィルタリングにも使える。
ログブラウザの足あとの分類にも使えるけど、そういうのはたぶん実装しないと思う。
まずは実用的な機能から。
グループマネージャと言うようなグループ分けをD&Dなどで手軽に出来る機能も欲しい。

たぶん、今後mixi側にもそれっぽい機能が追加されていくだろうから、グループの取り込みは早めにやっておきたい。

投稿者 Takenori : 12:09 | トラックバック

2007年02月13日

RSSメモ

mixi AlertへRSSリーダー機能を組み込むことを考え、下調べ中。

RSSのバージョンの流れ
0.9→0.91→0.92→0.93→0.94→2.0
 +-----------------------→1.0 ( 0.9と1.0はRDF形式 )

現在主に使われているRSSのバージョンは、0.91、1.0、2.0。
でも、サポートするとしたらRSSは1.0と2.0で十分だろうか?
0.91は各アイテムに更新日が含まれないので、使いづらい。
Atomの場合は、Atom 0.3 と Atom 1.0 をサポートした方が良さそう。

面倒なのが日付の書式。
RSS 1.0とAtomはRFC3339(日本語訳)。
RSS 2.0はRFC822(日本語訳)。
となっている。
RFC822の日付書式は「Mon, 05 Feb 2007 22:46:10 +0900」のような形になっておりイマイチ。
RFC3339の日付書式は「2007-02-05T13:54:25Z」のような形で、こちらの方がいい。
見やすいし、ソートもやりやすい。

RSSとAtomを透過的に扱えるC++のライブラリが欲しくて探したが見つからず。
PHPとかPerlならすぐに見つかるのだが……
とりあえずはXMLパーサーにexpatを使って自作する方向で。

関係ないけど、RSSで調べていたらこんなのがあった。
行き当たりばったり指向プログラミング
行き当たりばったり…… なんかいいな。

投稿者 Takenori : 21:16 | トラックバック

2007年02月14日

ATOM と RSS の 各要素の対応

ATOM と RSS のいくつかのバージョンの各要素の対応をある程度まとめた。
実際に他のバージョンのそれに対応しているかどうかは不確かで、仕様書などから類推したり、Movable Typeで出力されるRSSやATOMからそれらしいものを当てはめています。
o はオプション、m は必須として書いていますが、まだ正確ではありません。また、何箇所か空欄もあります。
ATOM に対応する要素で他のフォーマットにないものでDublin Coreモジュールにあり、実際に使われているものがあればそれを当てはめています。
RSS 0.91などでDublin Coreモジュールが使えるのかどうかなどは、まだ調べておらず空欄にしています。
また、managingEditor や webMaster など Author に当てはまりそうなものもありますが、実際の使われ方などをいくつか見て、似たようなものであれば追加する予定です。

各要素の型や属性などは後日また整理しようと思います。

Feed全体の要素

Atom 1.0Atom 0.3 RSS 0.91RSS 1.0 RSS 2.0
authoro authorm dc:creatoro
categoryo dc:subjecto dc:subjecto categoryo
contributoro contributoro dc:contributoro
generatoro generatoro generatoro
icono
idm ido dc:identifiero
linko linkm linkm linkm linkm
logoo
rightso copyrighto copyrighto dc:righto copyrighto
subtitleo taglineo
titlem titlem titlem titlem titlem
updatedm modifiedm pubDateo dc:dateo pubDateo
infoo
descriptionm descriptionm descriptionm
languagem dc:language languageo
ratingo
lastBuildDateo lastBuildDateo
docso docs
managingEditoro managingEditoro
webMastero webMastero
skipHourso skipHourso
skipDayso skipDayso
itemm itemsm itemo
imageo imageo imageo
textinputo textinputo textinputo
cloudo
ttlo

各エントリーの要素

Atom 1.0Atom 0.3 RSS 0.91RSS 1.0 RSS 2.0
authoro authoro dc:creator authoro
categoryo dc:subjecto dc:subjecto categoryo
contento contento descriptiono descriptiono descriptiono
contributoro contributoro dc:contributoro
idm idm dc:identifiero guido
linko linkm linkm linkm linko
publishedo issuedm dc:dateo pubDateo
rightso copyrighto dc:righto
sourceo sourceo
summaryo summaryo
titlem titlem titlem titlem titleo
updatedm updatedm
createdo
commentso
enclosureo

参考文献
以下の文書を元に上記表をまとめています。

HP
Atom 1.0仕様
Atom 0.3 ドラフト
Atomフォーマット 0.3 (ウィザシステム)
Moving from Atom 0.3 to 1.0
このサイトのMovable Typeで出力されたRSSやAtom。

書籍
詳解 RSS RSSを利用したサービスの理論と実践
Web開発者のためのRSS & Atomフィード

しかし、こういうのはブログのエントリーではなく、普通にHTMLでまとめたほうが良さそう。
なので少しずつHTMLでまとめて行こうと思う。
と言うか、綺麗にまとめられたサイトってないのだろうか?

投稿者 Takenori : 22:47 | トラックバック

2007年09月21日

セッションの共有

mixi の仕様が変更され、2重ログインが禁止されるようになった。
例えば、Firefox でログインした後、IE でログインすると、Firefox 側はログアウトされてしまう ( 異なる PC でアクセスした場合もログアウトされるはず )
つまり、mixi Alert を使っていて、ブラウザを Firefox にしていた場合、mixi Alert が更新をチェックするたびにログアウトされてしまい、使い物にならない。
mixi Alert は、Win32 Inet を使用してアクセスしているので、IE を使っている場合は問題ない ( ただし、Vista の場合は IE と他でクッキーが分離されているらしく、Vista では問題になる )

IE は使いたくないので対処法を考える。
1. IE のクッキーを Firefox にコピー
2. Firefox のセッション情報を使って mixi にアクセス
3. Firefox のクッキーを IE にコピー

1の場合、Firefox のクッキーファイルを書き換えるタイミングの問題や IE 基準となっているところがよろしくない。いつも Firefox を使っているので、2 か 3 の方法がよさそうだ。
ということで、まずは 2 の方法を取るべく HttpSendRequest にクッキー情報を渡すがなんかうまくいかない。
仕方なく、3. の方法 InternetSetCookie を使ってクッキーを上書きしてしまうことにした。
いろいろと試行錯誤したところ、クッキーのすべてを渡すとどうもうまくいかないらしく、必要なもののみにしないとうまくいかないようだ。
で、そのようにしたらうまく動くようになった。

ということで、Firefox が使われる設定になっていた時、Firefox のセッションが使われるようになった。
ただ、Vista の問題は残る。
Vista で IE のクッキー取得とか出来るのかなぁ。
そもそも、Vista 持っていないのですぐには対応できないのだが。

この仕様変更は複数人での ID 共有を排除する目的で設定されたのかもしれないが、少し知識があればまったく意味がない ( 少なくとも今の私は簡単に突破できる ) 。
でも、普通の人にはそれなりに効くのかな?
セキュリティの向上を考えるのなら、使い勝手は落ちるがずっとログイン状態を維持する設定を何とかしたた方が良いと思うのだが、ID 共有の方が問題になっているのだろうか?
ま、私は普通に使うことが目的なのでどうでもいい話だが。

そうそう、通常使うブラウザの判定はこの辺に書いてある。
要は、レジストリの "HKEY_CLASSES_ROOT\http\shell\open\ddeexec\Application" を見て、以下のどれかで判定する。
・iexplore(またはIExplore)を含む文字列が設定されていたら、Internet Explorer
・firefox(またはFirefox)を含む文字列が設定されていたら、Firefox
・opera(またはOpera)を含む文字列が設定されていたら、Opera

投稿者 Takenori : 15:00 | トラックバック

2007年10月03日

まぶしいトップページ

10/1 に mixi がリニューアルされ、認識できなくなっていた部分を対応し、とりあえず判明している箇所は対応が完了した。
にしてもまぶしい。
mixi の自分のホームを見るとまぶしい。
デザイン変更されたら毎度不満が出るが、慣れればそれほど気にならなくなる。
でも、今回はひどい。
2 カラムから 3 カラムになった時も幅が広くて嫌だと思っていたが、慣れるとそんなでもなくなった。
でも、今回はひどい。
何がひどいってまぶしいのだ。
これをデザインした人は目がおかしいんじゃないかと思ってしまう。
普通にまぶしいだろう?
そんなページを見ようと思うか?
勢いで専用ブラウザを作ろうかと思うぐらいだ。

投稿者 Takenori : 13:04 | トラックバック

2007年10月06日

いろいろと直接リストを見られるように

トップページがまぶしいので、Instant mixi でいろいろなリストを直接参照できるようにしています。
とりあえず、開発中のものでは以下のが見れるようになっています。

日記関係
・マイミクシィ最新日記
・日記コメント記入履歴
・自分の日記一覧
・最近の日記コメント一覧

コミュニティ関係
・コミュニティ最新書き込み
・参加しているコミュニティで指定したコミュニティのトピック一覧

日記関係は、ほぼ完全網羅ですね。
1ページ目しか見れないのと、特定のマイミクさんの日記一覧が見れないだけで、大体見れます。
自分の日記一覧は、トップから1件しか見れないので追加したのですが、意外と役立ちます。
Diary Publisher から日記をアップロードした後、アップロードした日記を参照する時に便利です。

コミュニティ関係は、見れないものが多いですが、コミュニティ最新書き込みがあれば大体事足ります。

ただ、既読判定がないので、そこがやや難ですね。

後、更新のチェックをコミュニティは、コミュニティ最新書き込みページから行うようになったので、読みのがしがなく、さらにすばやくチェックできるようになりました。

投稿者 Takenori : 17:18 | トラックバック

 
Total : Today : Yesterday :