Antoine.st 2009-05

2009-05-12

Convert IHtmlDocument to HtmlDocument

タイトルは IHtmlDocument から HtmlDocument への変換になってますが、"Internet Explorer_Server" から IHtmlDocument2 相当の取得なども含んでます。見かけたサンプルでは、ObjectFromLresult() 関数で mshtml.IHtmlDocument2 への変換をしてしまうのがあったんですが、mshtml への参照をしたくなかった関係から、IDispatch な object への変換です。

そこから、GetTypeFromCLSID() メソッドで取得した型情報を利用して、いつものごとくリフレクションです。

HtmlDocument クラスのコンストラクタは internal なので、外部から呼び出せません。ということで、GetConstructors() メソッドを利用して取得し、Invoke() してます。GetConstructor() メソッドだと、これまた internal な型の引数をどうやって指定すればいいんでしょう?

これで、HtmlDocument クラスのインスタンスが作れた、と思いきや、一部のプロパティ ( Url とか ) は利用できません。リフレクションで直接とか、Window.Url プロパティなら取得できるんですけどね。この辺がダメな理由はちょっとよくわかってません...。


  [DllImport("user32.dll",
    EntryPoint = "GetClassNameA")]
  private static extern int GetClassName(
    IntPtr hwnd,
    IntPtr lpClassName,
    int nMaxCount);

  [DllImport("user32.dll")]
  private static extern bool EnumChildWindows(
    IntPtr hWndParent,
    EnumProc lpEnumFunc,
    ref IntPtr lParam);

  [DllImport("user32.dll",
    EntryPoint = "RegisterWindowMessageA")]
  private static extern int RegisterWindowMessage(
    string lpString);

  [DllImport("user32.dll",
    EntryPoint = "SendMessageTimeoutA")]
  private static extern IntPtr SendMessageTimeout(
    IntPtr hwnd,
    int msg,
    IntPtr wParam,
    IntPtr lParam,
    uint fuFlags,
    uint uTimeout,
    out IntPtr lpdwResult);

  [DllImport("OLEACC.dll")]
  private static extern uint ObjectFromLresult(
    IntPtr lResult,
    ref Guid riid,
    IntPtr wParam,
    [MarshalAs(UnmanagedType.IDispatch)] ref object ppvObject);

  private const int SMTO_ABORTIFHUNG = 0x2;
  private Guid IID_IHTMLDocument =
    new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
  private delegate bool EnumProc(IntPtr hWnd, ref IntPtr lParam);

  private void button1_Click(object sender, EventArgs e)
  {
    Process[] processes;
    IntPtr hWnd;
    EnumProc proc;      
    int msg;
    IntPtr result;
    uint hr;
    object doc;
    Type t;
    string buf;
    Type thd;
    HtmlDocument hdoc;
    ConstructorInfo[] ci;

    processes = Process.GetProcessesByName("iexplore");
    if (processes.Length == 0)
    {
      return;
    }

    hWnd = processes[0].MainWindowHandle;
    doc = null;      
    proc = new EnumProc(EnumChildProc);

    EnumChildWindows(hWnd, proc, ref hWnd);
    if (hWnd.Equals(IntPtr.Zero))
    {
      return;
    }

    msg = RegisterWindowMessage("WM_HTML_GETOBJECT");
    if (msg == 0)
    {
      return;
    }

    SendMessageTimeout(
      hWnd,
      msg,
      IntPtr.Zero,
      IntPtr.Zero,
      SMTO_ABORTIFHUNG,
      1000,
      out result);
    if (result.Equals(IntPtr.Zero))
    {
      return;
    }

    hr = ObjectFromLresult(
      result,
      ref IID_IHTMLDocument,
      IntPtr.Zero,
      ref doc);
    if (doc == null)
    {
      return;
    }

    t = Type.GetTypeFromCLSID(
      new System.Guid(
        "{626FC520-A41E-11CF-A731-00A0C9082637}"));
    buf = t.InvokeMember(
      "URL",
      BindingFlags.GetProperty,
      null,
      doc,
      null).ToString();
    MessageBox.Show(buf, "HtmlDocument.URL");

    thd = typeof(HtmlDocument);
    ci = thd.GetConstructors(
      BindingFlags.NonPublic | BindingFlags.Instance);
    hdoc = (HtmlDocument)ci[0].Invoke(
      new object[] { null, doc });

    buf = hdoc.Window.Url.ToString();
    MessageBox.Show(buf, "HtmlDocument.Window.Url");

    // Error!
    // buf = hdoc.Url.ToString();
  }

  private bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam)
  {
    IntPtr p;
    string buf;

    p = Marshal.AllocHGlobal(256);
    GetClassName(hWnd, p, 256);
    buf = Marshal.PtrToStringAnsi(p);
    Marshal.FreeHGlobal(p);

    if (buf == "Internet Explorer_Server")
    {
      lParam = hWnd;
      return false;
    }
    return true;
  }


2009-05-06

Windows 7 - API

for Windows 7 な Windows SDK は見あたりませんが、ドキュメント的には、とりあえずリリースごとの API 一覧が参考になりそうです。

あとは、↓あたりの Developers Guide とかでしょうかね。ざっと見ておきたいのは。

Windows 7 RC - 2

Windows Update まで行って、ひととおりの環境構築はできました。実際、こんなもんです。あとは、XKeymacs 辺りなんですが、キーボードのリマップがうまくいきませんでした。おそらく、HKLM ではなくて HKCU を変更しているのが原因のようで。

HKLM で [Caps] -> [Ctrl] リマップする .reg ファイルを拾ってきて、それで OK でした。


2009-05-05

Windows 7 RC - 1

とりあえず、Windows 7 RC をインストールして、Windows Update で更新。Windows Vista 辺りから、メーカーが提供するデバイスドライバも Windows Update に出てくるのでいい感じです。環境は、Thinkpad X61 ですが、ひととおりのドライバが入った模様。

その後、Daemon Tools Lite 4.30.4 をインストール。互換性うんぬんで怒られましたが、とりあえず動作的には問題ないようです。あとは、Office 2007、Visual Studio 2008 とインストール。さくさくいきますね。


2009-05-04

Windows 7 RC

ゴールデンウィーク直前に、Windows 7 RC の提供が開始されました。最近の Microsoft のリリース状況からすると、RC レベルであれば充分に使えそうな感じです。ということで、さっそく物理環境にインストール。

といいつつ、この記事は Windows Vista の方で書いてます。Emacs 環境の移行も含め、いろいろ試してみようと思います。