11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Wallpapper Engineみたいなのを作りたい その1

Last updated at Posted at 2019-03-18

初めましてらいちです。
一昨年ぐらいに流行ったアプリ
Wallpaper Engine
あれの仕組みが気になっていろいろ探りながら自作できないかと。

##Wallpaper Engineとは
いわゆる壁紙の拡張
普通壁紙は静止画が常識ですが
このアプリを使えば動画等を壁紙にしたりできる
約400円の有料ソフト
私はまだ買っていませんが()

でこいつがどんな仕組みで動いてるか気になったけどそもそもソフト買ったわけでもないから検証もできない
でもなんとなく想像はできる

用は壁紙を何かしらで上書きしてやればいいんだ

まぁ結局いろいろやってみないとわからん

#Windowsでの描画の基礎
WindowsではGDI(Graphics Device Interface)というグラフィックス描画機能を提供している。
(Direct CompositionとかいうのもWindows 8辺りから追加されたけど割愛)
で、このGDIを使うためにはデバイスコンテキストのハンドルを取得する必要があると

デバイスコンテキストとは
Windowsが描画するための情報を管理しているメモリ上のデーターベースで
ハンドルはそのデーターベースを指すポインタのことである
でこのデバイスコンテキストはウィンドウハンドルから取得できるので壁紙を描画しているウィンドウのハンドルを取得してしまえばいいんじゃないかと。

#DesktopWindow
探してみたらあった
GetDesktopWindow
こいつで取得して試しに描画してみよう

desktop_draw.cpp
//必要なライブラリを読み込むVC++コンパイラへの命令
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")

#include <iostream>
#include <functional>
#include <Windows.h>

int main() {
//デスクトップウィンドウの取得
 HWND deks = GetDesktopWindow();
 //デスクトップウィンドウからデバイスコンテキストの取得
 HDC desk_hdc = GetDC(desk);
 
 //描画用ペン&ブラシの用意
 HGDIOBJ old_pen = SelectObject(desk_hdc, GetStockObject(BLACK_PEN)); //黒のペン(周りの描画用の色)
 HGDIOBJ old_brush = SelectObject(desk_hdc, GetStockObject(BLACK_BRUSH));//黒のブラシ(塗りつぶしの色)
 
 //四角の描画

 Rectangle(desk_hdc, 100, 100, 500, 500);
 
 //元のペン&ブラシに戻す
 SelectObject(desk_hdc, old_pen);
 SelectObject(desk_hdc, old_brush);

 //デバイスコンテキストを取得したら必ず終わりにリリースする
 ReleaseDC(desk, desk_hdc);
}

こんな感じですね
最初の#pragma comment(lib, "ライブラリ名")はライブラリ使用の宣言みたいなもので
user32.libgdi32.libを使用します
user32.libはウインドウ操作やメッセージ、入力処理とかのライブラリで
gdi32.libはGDIを利用するためのライブラリ
.libはあまり聞かないかもだけど用は.dllの中の関数を使うよってこと
user32.dllgdi32.dllなら聞いたことあるでしょ
(C#書く人はきっと[DllImport("user32.dll")]とか書いたことあるはず)
でそのdll関数へのリンクに必要なファイル

でコンパイルして実行!!
2019-03-18_131856.png
おおお黒い四角が描けた!!これで行ける!!!
(ちなみに1度しか描画してないから再描画が起こると消えるよ)

ってちょっと待って?
2019-03-18_132143.png
なんでChromeさんの上に描画されるん!!
ほんとは下に描画されてほしいのに
で調べてみたらGetDesktopWindowで取得されるウィンドウはどうやら本当にデスクトップみたいで?こいつに描画すると最前面に描画されるみたい(描画順序によるのかも?)
2019-03-18_132803.png
Spy++で見たところのこのすべてのウィンドウの親ウィンドウなんだとか?
じゃあどうすりゃいいねん!!

#壁紙ウィンドウ
で壁紙を描画してるウィンドウが見つからない
で、ふと思い出した、Spy++にはD&DでWindowを探す機能がある!!
2019-03-18_133710.png
Folder View ???
ってかなんか階層になってるなぁ、、、
まぁ物は試し。

folder_view_draw.cpp
//必要なライブラリを読み込むVC++コンパイラへの命令
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")

#include <iostream>
#include <functional>
#include <Windows.h>

int main() {
//デスクトップウィンドウの取得
 HWND fv = reinterpret_cast<HWND>(0x00010234);//ウィンドウハンドルを直接記述
 //デスクトップウィンドウからデバイスコンテキストの取得
 HDC fv_hdc = GetDC(fv);
 
 //描画用ペン&ブラシの用意
 HGDIOBJ old_pen = SelectObject(fv_hdc, GetStockObject(BLACK_PEN)); //黒のペン(周りの描画用の色)
 HGDIOBJ old_brush = SelectObject(fv_hdc, GetStockObject(BLACK_BRUSH));//黒のブラシ(塗りつぶしの色)
 
 //四角の描画

 Rectangle(fv_hdc, 100, 100, 500, 500);
 
 //元のペン&ブラシに戻す
 SelectObject(fv_hdc, old_pen);
 SelectObject(fv_hdc, old_brush);

 //デバイスコンテキストを取得したら必ず終わりにリリースする
 ReleaseDC(fv, fv_hdc);
}

前のとほぼ一緒ですが
ウィンドウハンドルはSpy++が示してた値を直接入力しました(自分の環境で試す場合はご自身でお調べください。エクスプローラーが起動する度に代わります)
では実行
...
何も表示されない...
試しに色を変えてみよう
BLACK_BRUSHWHITE_BRUSH
2019-03-18_135423.png
おお!ちゃんと下に描画されるじゃん!!
で、Folder Viewってことはだよ?
もしかするとデスクトップのフォルダーとかを描画してるウィンドウなのかな?
と思ってフォルダーを動かしたりしたらドンピシャ!
再描画が走って四角は消えた!ついでに描画範囲にフォルダーがあったらそいつも上書きされた
なるほどね?でもそのフォルダーとかが消えたら壁紙じゃないな
じゃあこのウィンドウの一番親ウィンドウのWorkerWウィンドウ?こいつに描画してみよう
コードはウィンドウハンドルを書き換えただけなので割愛
で、まぁ実際描画されないんですね
はい。
でよく見るとWorkerWウィンドウ二つあるじゃないですか
もう片方のWorkerWウィンドウに描画してみたところ描画されました。
黒も描画されました
しかもちゃんと壁紙の上に描画されていて
壁紙を変更したとき消えました
はい。
さらに謎ですね
でそっちのウィンドウに送られるメッセージを見てみたところ
2019-03-18_142402.png
デスクトップをアクティブにした場合と壁紙を変えた場合にメッセージが送られてます
WM_WINDOWPOSCHANGINGはまぁ最前面に移動させようとしてるメッセージですね
壁紙なので無視するメッセージでしょう
WM_WINDOWPOSCHANGEDも同様
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGED
WM_ACTIVETEAPPはアクティブ化されようとしてるときと非アクティブ化されようとしているときに送られるメッセージですね
WM_ACTIVETEAPP

まぁこれらは全ウィンドウ共通で送られるはずです。
で、次に気になるメッセージが。
message:0xC1BD [登録された:"ForwardMessage"]
これが壁紙を変えたときに送られているんですね
壁紙を変えろ!って
ちなみにSpy++で表示されるウィンドウの順序は実際のウィンドウの順序と一致しているのでまぁ下のWorkerWが壁紙描画
その上のWorkerWがフォルダーの描画といったところでしょうか
つまりそのWorkerWに描画してあげればいい感じですかね

では次回からいろいろ試行錯誤していきましょう

Wallpapper Engineみたいなのを作りたい その2

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?