Search
Categories
Articles
Rainmeter関連
ファイル置き場
お知り合いなど

スポンサーサイト

--.--.-- | スポンサー広告

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

微修正点とか

2009.04.14 | Rainmeter-dev // その他

0 Comments

Rainmeter本家ではどんどんと追加要素が入っていってますが、何を追加していってるのかさっぱりなので(スキンの部分ではないとはいえ、今まであった設定項目を削るってどうなの?とは思ったりしましたが)、そちらは少し置いといて。
今回は、自分用にビルドして使っているRainmeterのソースのうち、変な処理などを微修正した部分を書き出してみます。追加要素はまた別の機会に。
(修正前のソースを貼るとえらい長くなるので、GoogleCodeへのリンクと行番号だけ書いておきます)

■いろんなとこ
・new char[]やnew WCHAR[]で確保したバッファを、単にdeleteしてしまっている部分を修正(delete tmpSz; → delete [] tmpSz;)。ほとんどがConvertToAscii()、ConvertToWide()、ConvertToUTF8()絡み。複数のファイルにあるので全部(主にプラグインのソースにあります)。
・後置インクリメント/デクリメントをしてる部分のうち、処理的に後置でなくていいものをすべて前置に置き換えた。主にforループでまわしてるイテレータのため。
・forなどのループの条件のうち、処理的に変化のない条件を何度も計算しないようにした。主に「i < wcslen(tmpSz)」みたいなもの。
・構造体の初期化をmemset()でなく、宣言時に{0}を代入することで済ますようにした。NOTIFYICONDATAのcbSizeなど、サイズを指定しなければいけないものは{sizeof(NOTIFYICONDATA)}で初期化(サイズ指定部分は大抵、構造体の先頭にあるため。先頭でない場合は仕方ないので後から代入する)。

■Application.cpp
・コマンドラインからクォート(")を取り除く処理で、取り除いた後の文字列を格納しておくバッファ(WCHAR Path[256])のサイズを超えて書き込もうとするのを修正。……でも、これって何のために存在する処理なのかがよくわかりませんでした。(後述)
・すべてのMeterWindowが"On Desktop"に設定されているときに、!BANG Commandが届かない問題を修正。(後述)

■MeterHistogram.cpp
・ヒストグラムのバーの高さが微妙に設定とズレるのを修正。DrawLine()で描いていたものを、すべてFillRectangle()で描くようにする。(ソースは追加要素と入り混じりすぎてて抜き出せないので割愛)

■MeterString.cpp
・フォントによって、StringAlign=RIGHTのときに文字の位置がズレることがあるのを修正(?)。……というよりは、直っているのかどうか、正しいのかどうかすらわからないやり方なので、おまじない程度。(後述)

■MeterWindow.cpp
・スキン内容を読み込むためのバッファの解放漏れを修正。1054行目で、returnする前にitemsをdelete[]する。
・描画用のダブルバッファを、毎度deleteして作り直すのではなく、サイズの変化がないときは透明色で塗りつぶして再利用するようにしてみた。単に、やたら増えるページフォルトを減らしたかっただけ。速度的には作り直すよりも遅い。(後述)

■Rainmeter.cpp
・OSの判定で、XPでもたぶん2kとして判定されてしまうのを修正。dwMajorVersionだけでなくdwMinorVersionも含めて判定する。……とはいえ、どのへんでOSごとに(例えば2k or XPで)処理を変えるのに使われているのかは、よくわからない。Vista以上で処理を変えたいとかいう流れになってくると、判定処理をしっかり書いたほうがいいのかも。

■WebParser.cpp
・すべてのMeterWindowが"On Desktop"に設定されているときに、FinishActionが届かず実行されない問題を修正。原因はApplication.cppのものと同じ。

■WindowMessagePlugin.cpp
・std::mapにwindowData丸ごとでなく、ポインタを突っ込むようにした。どっちがいいのかは……。

……と、こんな感じです。
他にも、「Meter=STRINGでAutoScale=1のときに、Measureによっては値が小さく表示されてしまう(210か、103かの違い)」なんてのもあるのですが、これは設定を追加するなりして処理を分けないと無理かなぁということで、今回は省略しました。ディスクやメモリ容量などの表示には問題ないけど、Net関連は少しズレてるかもしれません。

続きからは、(後述)って書いてあるものの詳細。

■Application.cpp
クォートを取り除く処理(68-78行目)では、255文字+ヌルターミネータ分のバッファが用意されていますが、lpCmdLineからクォートを取り除いた文字列が255文字を超えることは想定されていません。2kでは2047文字、XPでは8191文字使えるらしい?(こういう情報ってどこに書いてあるんだろう?)ので、長い引数が指定されるとバッファオーバーランします。
対策としては、(1)バッファを動的に増やして全部収まるようにしてやるか、(2)バッファのサイズはそのままに最大255文字まで取り込むようにするか、(3)255文字を超えたら引数を無視するようにするか……あたりでしょうか。(2)はこれはこれで問題ありそうな気もします。
そもそも、この処理がなんのために存在するのかわからず、255文字以上にバッファを増やしていいのかすらわからないという状態ですので、とりあえずは(3)がいいのかなぁ……。今は(2)で書いちゃってるので、書き直し書き直し。

……こんな感じ?(チェックできてません)

	// Remove quotes from the commandline
	WCHAR Path[256];
	Path[0] = L'\0';
	if(lpCmdLine && lpCmdLine[0])
	{
		size_t CmdLineLen = wcslen(lpCmdLine);
		size_t PathMaxLen = (sizeof(Path) / sizeof(Path[0])) - 1;
		size_t Pos = 0;

		for(size_t i = 0; i < CmdLineLen; ++i) 
		{
			if(lpCmdLine[i] != L'\"')
			{
				if(Pos >= PathMaxLen)
				{
					Pos = 0;
					break;
				}
				else
				{
					Path[Pos++] = lpCmdLine[i];
				}
			}
		}
		Path[Pos] = L'\0';
	}

もうひとつの、!BANG commandが届かない問題(159行目-)は、すべてのMeterWindowが"On Desktop"に設定されているときに起こります。
FindWindow()は、親ウィンドウを持たないトップレベルウィンドウの中から指定されたウィンドウを探してきますが、"On Desktop"に設定されたMeterWindowのウィンドウは、親ウィンドウが「プログラムマネージャ」に設定されているため、探索範囲から除外されてしまいます。よって、すべてのMeterWindowが"On Desktop"に設定されていると、FindWindow()では1つも見つけることができなくなり、!BANG commandが送られなくなります。

対策としては、FindWindow()で見つからなかった場合にFindWindowEx()を使い、「プログラムマネージャ」の子ウィンドウの中からMeterWindowを探すようにします。

void Bang(HWND hWnd, const WCHAR* command)
{
	// Check if Rainmeter is running
	HWND wnd = FindWindow(L"RainmeterMeterWindow", NULL);
	if (wnd == NULL)
	{
		// Check if all window are "On Desktop"
		HWND ProgmanHwnd = FindWindow(L"Progman", L"Program Manager");
		if (ProgmanHwnd)
		{
			wnd = FindWindowEx(ProgmanHwnd, NULL, L"RainmeterMeterWindow", NULL);
		}
	}

	if (wnd != NULL)
	{
		/* WM_COPYDATAを送る処理 */

185行目で見つからなかった場合、189行目で取得した「プログラムマネージャ」のウィンドウハンドルを元に、192行目で子ウィンドウの中からMeterWindowを探しています。これで見つからないなら、どこにいるかわかりません!

WebParser.cppにも同様の箇所があります(2箇所)。そちらも上記の186-194行目の内容を追加してやれば動くと思います(WebParserを使っていないので、チェックまではしていません)。

■MeterString.cpp
ズレるようになる/ズレなくなる条件がよくわかりませんが、うちの環境ではStringAlign=RIGHTのときに、文字列の内容が変わるタイミングで右端がぴょこぴょこ左右にズレます。フォントによるものなのかは不明(今使っているのはhooge 05_53で、AAなしのFontSize=6)。

398行目のMeasureString()がダメなのかなぁとか考えて、他の測り方も試してみたけれど上手くいかず、なぜか関係ないと思われるSetMeasurableCharacterRanges()を追加すると、ぴたっとズレなくなりました。

	CharacterRange range(0, wcslen(m_String.c_str()));
	stringFormat.SetMeasurableCharacterRanges(1, &range);

	REAL x = (REAL)GetX();
	REAL y = (REAL)GetY();

	if (rect)
	{
		/* MeasureString() */

本来はMeasureCharacterRanges()と対になるもののようですが、MeasureString()をMeasureCharacterRanges()に置き換えても上手くいきませんでした。内部でどうなってるのか、サッパリわかりません。
使い方が間違っている気もするのですが、とりあえず意図した通りに動いているように見えるので、そのままにしてあります。環境によって変わるんだろうか?

■MeterWindow.cpp
更新間隔ごとにm_DoubleBufferをdelete→newしてるので、ページフォルトがえらいことになってます。速度的には遅くなりますが、縦横のサイズが変わらない場合には透明色で塗りつぶすだけで済ますようにしてみました。

	{
		Bitmap* buffer = GetDoubleBuffer();
		int w = m_WindowW;
		int h = m_WindowH;

		if (buffer)
		{
			if (w == buffer->GetWidth() && h == buffer->GetHeight())  //size not changed
			{
				Status st;
				{
					//Clear the doublebuffer
					Graphics graphics(buffer);
					st = graphics.Clear(Color::Transparent);
				}

				if (st != Ok)  //failure
				{
					delete buffer;
					buffer = NULL;
				}
			}
			else  //size changed
			{
				delete buffer;
				buffer = NULL;
			}
		}

		if (!buffer) m_DoubleBuffer = new Bitmap(w, h, PixelFormat32bppARGB);
	}

ページフォルトがほんの少ししか減らない割りに、Graphicsオブジェクトの作成とClear()で結構時間を食われるので、微妙なところです。
BitmapDataを使って直接memset()でゼロクリアする方法もありますが、色が変わってしまう上に(Color::Transparentは0x00FFFFFF)、BitmapData.Strideの値が正か負かによってポインタの始点を変えないといけないみたい?なので、こちらもあまりメリットがないかなぁ。ページフォルトを気にしないなら、元のままでいいと思います。

« M@STER TRAXX Google Reader »

- Comments
0 Comments

管理者にだけ表示を許可する
- Trackbacks
0 Trackbacks


この記事にトラックバックする(FC2ブログユーザー)

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。