CDHtmlDialog で Windows XP luna テーマを表示させる方法
CDHtmlDialog で Windows XP luna テーマを表示させる方法
たったこれだけのことが、なかなか分からず苦労したため、メモしておく。
(実は最後の (6)結論 以外は読む必要なし。)
(1) CDHtmlDialog で検索
最初、「cdhtmldialog manifest」といったキーワードで検索した。
テーマを反映させるにはmanifestだろう、と考えたためだ。
この考えは全然違うようであった。
「Code Project」でこんな↓のを見つけた。
Dialog with HTML skin using CDHtmlDialog and SetWindowRgn
http://www.codeproject.com/KB/MFC/HtmlSkinCDHtmlDialog.aspx
だがこれは単にHTMLダイアログベースで非矩形のウィンドウを作るためのものであった。
luna風コントロールは表示されない。
最近の CodeProject はダウンロード時のログインだけでなく、さらに余計な確認までさせられるようになっている。orz
(2)IWebBrowser で検索してみた
色々なキーワードを試してみた。
「iwebbrowser luna」というキーワードで得るものがあった。
2ちゃんねるのスレを発見した。
http://ir9.jp/prog/ayu/datlog/tech_ie_component/982930049/982930049_03.html
546-550でまさにその話題が
2ちゃんねるなのであんまり詳しくは教えてくれないが、MSDNのこの↓ページが紹介されていた。
http://msdn.microsoft.com/workshop/browser/hosting/reference/enum/dochostuiflag.asp
DOCHOSTUIFLAG_THEME を指定すれば良いのだそうだが、情報としてはそれだけ。
(3)DOCHOSTUIFLAG_THEME とやらは、どうやって指定するのか?
さて、DOCHOSTUIFLAG_THEME とやらは、どうやって指定すればいいというのだ?
SetDocHostUIFlag() といったような関数があるのか?
で、
IDocHostUIHandler インターフェイスを自分で(!)用意して、その中のGetHostInfoメソッドでそのフラグを返してやる、ということがわかった。
この程度のことを実現するのに、なんてことをさせるのだろう。
orz orz orz
と、思いついて、unDonut (及び派生品)のソースコードをダウンロードして調べてみた。
が、該当箇所だけ取り出して参考にできるような規模ではなかった。
(unDonutのソースコードのダウンロード場所が非常にわかりにくい。ソースを見たがる人なんてあまりいないのだろう。orz)
(4) じっくり腰を据えて調べる
じっくり腰を据えてMSDNのこちら↓などを読みながら、基本からやろうと思った。
http://www.dotnet247.com/247reference/a.aspx?u=http://msdn.microsoft.com/workshop/browser/hosting/wbcustomization.asp
これによると、WebBrowserコントロールはインスタンス化されるとすぐに、コンテナ側の IOleClientSite に対して IDocHostUIHandler 取得要求を出すらしい。
ということは、IOleClientSite のQueryInterface に細工をすれば良いはず。
CDHtmlDialogはWebBrowserコントロールのコンテナなので、IOleClientSite を持っているはず。
ということで、もう一度、ちょっとCDHtmlDialogを調べてみることに。
(5) 青い鳥はすぐそばに
デバッガでCDHtmlDialogベースのスケルトンを作って追いかけて行ったら、CDHtmlDialogのコンストラクタで、
void CDHtmlDialog::Initialize()
というメンバを呼んでいる。
Initalize内で、なんと!!
SetHostFlags(DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_SCROLL_NO);
などという呼び出しがあるではないか。
ここで設定された値は、
CDHtmlDialog::m_dwHostFlags;
に保持されて、必要に応じてWebBrowserコントロールに渡されるというしくみであった。orz
(6) 結論
CDHtmlDialogの派生クラスを作り、コンストラクタで次のようにすればよい。
SetHostFlags(m_dwHostFlags | DOCHOSTUIFLAG_THEME);
CHtmlViewでCDHtmlDialogと同様のイベント処理を行う方法
ご存じのとおり、CDHtmlDialog では、HTMLファイル内のボタンやリンク等がクリックされた、といったようなイベントを受け取ることができる。
例えば次のような具合で、簡単にハンドリングできる。
BEGIN_DHTML_EVENT_MAP(CMyDHtmlDialog)
DHTML_EVENT_ONCLICK(_T("ID_MY_BUTTON"), OnMyButton)
END_DHTML_EVENT_MAP()HRESULT CMyDHtmlDialog::OnMyButton(IHTMLElement* pElement)
{
・・・省略・・・
return S_OK;
}
なんと驚いたことに、CHtmlView ではこれができないのだ。
CDHtmlEventSink の派生クラスでなければダメらしい。
CDhtmlDialog は CDHtmlEventSink を継承(多重継承)しているが、CHtmlViewはしていないからダメみたいだ。
この悩みを解決してれた方がいる。
CodeProject のここ↓だ。
http://www.codeproject.com/KB/MFC/dhtmlview.aspx?df=100&forumid=3217&exp=0&select=1322469
もし見つからない場合は
Integrating DHTML into MFC Views
という記事名で検索すれば良い。
CDHTMLView という名前で実装されている。
CViewからの派生になっている。
まだ MFC CHtmlView が出る前に書かれた記事だから?
ただし、残念なことに、このクラスではドロップターゲット機能がサポートされていない。
つまりこうだ。
CDHtmlDialog イベント:○ ドロップ:×
CHtmlView イベント:× ドロップ:○
このクラス(CDHTMLView) イベント:○ ドロップ:×
MFCのCHtmlViewから、ドロップ機能に必要な個所を抜き出して、CHTMLViewクラスにねじ込んだら、動いた。
抜き出すのは結構大変そうに思えたが、一か所にまとまっていたのでなんとかなった。
MFC の CHtmlView からの派生クラスにして、イベント機能をそこに追加する、という解決をしてみたかったのだが、そちらの方法はとりあえず断念した。
そもそも可能なのかどうかすら分からないのだが。
とりあえずはてなダイアリーにメモることにしたのだが、勝手に p タグが入ってしまうのには弱った。
なんとかならないんかな。
自分用のメモのためだけなので、見やすさとかは考えないことにした。orz
CHtmlView で独自のドラッグ&ドロップする方法
CHtmlViewを使っている場合、そのままでは自分のViewクラスの OnDragEnter や OnDrop が呼ばれない。
以下のように、OnGetDropTarget をオーバーライドして、自分が管理している IDropTarget を返してやればよい。
class CMyView : public CHtmlView
{
・・・省略・・・
virtual HRESULT OnGetDropTarget(LPDROPTARGET pDropTarget, LPDROPTARGET* ppDropTarget);
COleDropTarget* m_pDropTarget;
};int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
・・・省略・・・(後始末なども省略)
m_pDropTarget = new COleDropTarget;
m_pDropTarget->Register(this);
}// この OnGetDropTarget をオーバーライドするのがポイントだ
HRESULT CMyView::OnGetDropTarget(LPDROPTARGET pDropTarget, LPDROPTARGET* ppDropTarget)
{
*ppDropTarget = (LPDROPTARGET)m_pDropTarget->GetInterface(&IID_IDropTarget);
if (*ppDropTarget == NULL) {
return E_FAIL;
}
// 呼び出し側でReleaseするようなので、ここでAddRefしたままで良い。
// (自分でReleaseするとおかしなことになる)
(*ppDropTarget)->AddRef();
return S_OK;
}
これにより、 CMyView の OnDragEnter とか OnDrop が呼び出されるようになる。
CDhtmlDialog でも同様のやり方ができるかと思ったのだが、CDHtmlDialog には OnGetDropTarget がない。
ということは同じやり方はできない。
別の記事で書いたが、CHtmlViewと同じ方法でドロップを受け付けるようにするためには、数百行程度のコードを追加する必要がある。