2013年1月27日日曜日

CHtmlViewのスクロール位置を取得する。 (VC++, MFC)

MFCのCHtmlViewクラスはブラウザを表現する為に便利なViewクラスですが、スクロールバーの制御に関してはCOMを扱わないと上手く動作しません。CHtmlViewクラスは下記のようにCScrollViewから派生しています。
CView <-- CScrollView <-- CFormView <-- CHtmlView
CScrollViewのスクロールメソッド を使用すれば制御できそうですが、実際には出来できません。CHtmlViewはWebBrowserコントロールのCOMコンポーネントを使用し表現しており、スクロールバーもWebBrowserコントロールの一部になっている為です。

スクロール位置を取得する為には、MSHTMLコンポーネントをインポートしDOMから制御するしかありません。下記にスクロール位置取得のコードを記載します。
#import <mshtml.tlb> no_auto_exclude auto_rename

static long getScrollTop(CHtmlView* pView){
    long scrollTop = 0;
    
    try {
        MSHTML::IHTMLDocument3Ptr document = pView->GetHtmlDocument();
        MSHTML::IHTMLElement2Ptr  root     = document->documentElement;
        scrollTop = root->scrollTop;

        if (0 == scrollTop){
            MSHTML::IHTMLElement2Ptr body = 
                root->getElementsByTagName(_T("body"))->item(0);
            scrollTop = body->scrollTop;
        }
    }
    catch (_com_error& e){
        // TODO: Error handling...
    }
    return scrollTop;
}
  1. MSHTMLのインポート
    mshtml.tlbを#importする事で、MSHTML名前空間のスマートポインタが使えるようになります。no_auto_excludeは同名の識別子定義があった場合に自動除外(exclude)されるのを拒否します。auto_renameは同名のマクロ定義(inline定義も含む)があった場合に自動的にアンダーバーを二つ付けて定義します。
    "TranslateAccelerator" -> "__TranslateAccelerator"
  2. Documentポインタとルート要素の取得
    ドキュメントポインタに使用するインターフェイスはdocumentElementメンバを持ったIHTMLDocument3を使用しルート要素を取得します。ルート要素ポインタはscrollTopメンバを持ったIHTMLElement2インターフェイスを使用します。
  3. スクロール位置の取得
    <!DOCTYPE html>などDOCTYPE宣言が行われている場合、ルート要素からスクロール位置の取得ができます。しかし、DOCTYPE宣言が行われていない場合、ブラウザは後方互換モードで動作します。その場合、ルート要素からのスクロール位置取得は常にゼロを返します。後方互換モードの場合にスクロール位置を取得するにはbody要素のscrollTopメンバから取得できます。



0 件のコメント:

コメントを投稿