初めに
壁紙チェンジャーを作るに必要な要素は、
壁紙にする画像ファイルをリストアップする。
画像をJpegファイルのExif情報を元に回転する。
画像をDesktopの大きさに合わせる。
一定時間ごとに壁紙を変える。
(おまけ)タスクトレー常駐する。
といったところでしょうか。この内、壁紙の設定以外は、.NET Frameworkですべて間に合います。以下の紹介です。
壁紙にする画像ファイルをリストアップする。
フォルダから画像ファイルを取り出すには、GetFIlesを使います。
array<String^> ^fileEntries; // 画像ファイル名 String^ dir; // 画像ファイルフォルダ名 fileEntries = System::IO::Directory::GetFiles(dir)
これでOKです。ただし、dir フォルダー直下のファイルしか拾えません。そこで、再帰的関数を定義します。
void getAllFiles(String^ dir, ArrayList^ fileList) { array ^dirEntries; array ^tmpEntries; tmpEntries = System::IO::Directory::GetFiles(dir); fileList->AddRange(tmpEntries); dirEntries = System::IO::Directory::GetDirectories(dir); for (int i=0; iLength; i++) getAllFiles(dirEntries[i], fileList); }
ファイル名は、fileList に入ります。fileList を ArrayList で定義しているのは、AddRange を使ってファイル名を追加したいためです。関数getAllFiles の使い方はこうです。
array<String^> ^fileEntries; // 画像ファイル名 String^ dir; // 画像ファイルフォルダ名 ArrayList^ tmpList = gcnew ArrayList; getAllFiles(dir, tmpList);> fileEntries = gcnew array<String^>(tmpList->Count);
最後の行で、ArrayList を String の array に直しています。と、ここまで書いてきましたが、サブ・フォルダー下のファイル名を拾うだけなら、実は再帰的関数など必要ありません。
fileEntries = System::IO::Directory::GetFiles(dir, "*.*", SearchOption::AllDirectories); で出来ます。再帰的関数を使ったのは、arrayに要素を追加する方法を残したかったからです。
画像をJpegファイルのExif情報を元に回転する
jpegファイルのExif情報を取得するには、次のようになります。
Bitmap^ image = gcnew Bitmap("test.jpg"); try { array<System::Drawing::Imaging::PropertyItem^>^ propItems = image->PropertyItems; array<int>^ propIDList = image->PropertyIdList; int index = propIDList->IndexOf(propIDList, 0x112); } catch (Runtime::InteropServices::ExternalException^) { return nullptr; }
PropertyItems と PropertyIdList の使い方は、MSDN を参照してもらうとして、tryで囲んであるのは、Exif がない場合を考えてです。Exif の無い jpegファイルもありますからね。 0x112 という定数は、画像の回転情報が入っている Exif の Tag番号です。その他の Tag番号や詳細は、こちらでどうぞ。回転方向が判れば、回転するのは、簡単です。 Image の RotateFlipType を使います。
if (index > 0) { switch (System::BitConverter::ToInt16(propItems[index]->Value, 0)) { case 8: // 8 left-bottom 右が上 1000
image->RotateFlip(RotateFlipType::Rotate270FlipNone); break; case 6: // 6 right-top 左が上 0110 image->RotateFlip(RotateFlipType::Rotate90FlipNone); break; case 3: // 3 bottom-right 下が上 0011 image->RotateFlip(RotateFlipType::Rotate180FlipNone); break; default:// 1 top-left 上が上 0001 break; } }
画像をDesktopの大きさに合わせる
Desktop の大きさは、以下で参照できます。
SystemInformation::PrimaryMonitorSize.Height; SystemInformation::PrimaryMonitorSize.Width;
上で使った image の大きさを幅高さとも半分にするには、
float rate = 0.5; Bitmap^ tmp = gcnew System::Drawing::Bitmap((int)(rateW * image->Width), (int)(rateW * image->Height)); Graphics^ g = Graphics::FromImage(tmp); RectangleF rect = RectangleF(0, 0, 1.0F * image->Width, 1.0F * image->Height); RectangleF torect = RectangleF(0, 0, rateW * image->Width, rateW * image->Height); g->DrawImage(image, torect, rect, GraphicsUnit::Pixel);
image = tmp;
こんな感じです。もっと簡単にできるのかもしれませんが、私は、こうしています。
一定時間ごとに壁紙を変える
一定時間ごとには、Timer コンポーネントを使います。まあ、説明はいらないかと。
壁紙を変えるには、正式には、SystemParametersInfo を使います。
#include <windows.h> int err = SystemParametersInfo(SPI_SETDESKWALLPAPER, // 壁紙の設定 0x14 NULL, L"TJwallpaper.bmp", // 壁紙にするBMPファイル 0);
もちろん、user32.lib が必要で、プロジェクトに追加しておきます。
しかし、今回は、別の API を使います。SetDeskWallpaper です。このAPIは、ドキュメントされていないuser32.dll の API なので、タイマー付きメッセージボックスで使った手法を使います。
int SetDeskWallpaper(LPCSTR lpText) { static SETWPAPI SetWallpaper = NULL; if (!SetWallpaper) { HMODULE hUser32 = GetModuleHandle(TEXT("user32.dll")); if (hUser32) SetWallpaper = (SETWPAPI)GetProcAddress(hUser32, "SetDeskWallpaper"); else return 0; } if (SetWallpaper) return SetWallpaper(lpText); else return 0; }
user32.dll を直接参照していますから user32.lib は要りません。使い方はこうなります。
HMODULE hUser32 = LoadLibrary(TEXT("user32.dll")); if (hUser32) { int err = SetDeskWallpaper("TJwallpaper.bmp"); FreeLibrary(hUser32); }
引数は、画像ファイルのみです。XPまでは、BMPファイルしか使えなかったのに、vistaになったらjpegファイルが使えます。アンドキュメントAPI なのに、機能アップしてたりします。
タスクトレー常駐する
壁紙には、直接関係ないので、おまけです。タスクトレーに入れるには、コモン コントロールの NotifyIcon を使います。タスク・トレー上にあるアイコンにカーソルを重ねると出てくるテキストはTextプロパティで設定します。
private: System::Windows::Forms::NotifyIcon^ notifyIcon1; this->notifyIcon1->Text = L"WallpaperChanger";
また、右クリックで出てくるメニューは、メニューのContextMenuStrip を使います。これを NotifyIcon のContextMenuStripプロパティに設定します。
private: System::Windows::Forms::ContextMenuStrip^ contextMenuStrip1; this->notifyIcon1->ContextMenuStrip = this->contextMenuStrip1;
これだけだと、左クリックでも出てしまうので、NotifyIcon の MouseClickイベントで左クリックの動作を定義します。
this->notifyIcon1->MouseClick += gcnew System::Windows::Forms::MouseEventHandler(this, &Form1::notifyIcon1_MouseClick); private: System::Void notifyIcon1_MouseClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { if (e->Button == Windows::Forms::MouseButtons::Left) { this->Visible = true; // 例えば、Formを表示するとか :(他に必要な動作を記述) } }
というところでしょうか。以上で説明は終わりです。
完成版とソース(WallpaparChanger.zip)は、こちらからどうぞ。完成版では、フォルダー名や切替時間などをiniファイルに設定するなどの手法も含まれています。詳細は、ソースをご一読下さい。起動画面は、下図になります。
使い方は、見ての通りです。Folder Change で画像フォルダーを選択し、Timer Start でチェンジャー動作をします。同時に、Form が消えて、タスクトレイにのみ残ります。見慣れないアイコンがあったらそれです。アイコンを右クリックすると、終了のメニューが出ます。左クリックだと、起動画面が出ます。WP Change は、クリックする度に壁紙を変えます。残りのオプションは、ご想像にお任せいます。ソースを見れば一目瞭然ですけどね。
なお、プログラム中のJpeg->BMP変換とリサイズの部分のみをまとめた Jepg2Bmp.exe もあります。ダウンロード(jpeg2bmp.zip)は、こちらから。
プログラム作製に使ったツールは、Visual C++ 2008 Express Edition 日本語版です。レジストリ等は使用していませんので、適当なフォルダに実行ファイル(WallpaparChanger.exe)を解凍すれば使えます。なおプログラムの実行に際しては、以下のモジュールが必要です。必要に応じてインストールして下さい。
Microsoft .NET Framework Version 2.0 再頒布可能パッケージ (x86)
Microsoft .NET Framework 2.0 Service Pack 1 (x86)
Microsoft Visual C++ 2008 再頒布可能パッケージ (x86)
なお、掲載したソースおよび実行ファイルは、ご自由にお使い下さい。ただし、ご使用により、いかなる弊害や不具合が生じたとしても、当方ではいかなる責任も持ちません。予め、ご了承下さい。
注記:Visual C++ 2008 Express Edition の .NET Framework はデフォルトでは、3.5 ですが、今回のプログラムは、2.0 で構成しています。これはプロジェクトのプロパティで設定できます。
Thinking-J
https://sites.google.com/site/thinkingj2007/home
mail : thinkingj.2007@gmail.com