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と同じ方法でドロップを受け付けるようにするためには、数百行程度のコードを追加する必要がある。




   

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

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);