[jiangsheng大哥帮忙]WebBrowser窗口子类化bug(up有分)

大狗狗 2011-06-13 07:34:01
环境:VS2005 C# WinForm XPSP2 IE8 -- 另注:电脑硬件绝对没问题


问题起因:

WebBrowser控件在重绘时(比如它被从容器底部提到了顶部)。先是重绘背景,然后再绘制内容。重绘背景不仅多余而且造成闪烁。在VC中,只需屏蔽WM_ERASEBKGND消息即可消除闪烁。但是在C#中,试图通过重载WebBrowser自己的WndProc去捕获WM_ERASEBKGND是行不通的。可行办法是通过查找Internet Explorer_Server窗口然后进行窗口子类化。这样才能捕获到WM_ERASEBKGND。


using PARAM = System.IntPtr;
using MESSAGE = System.Int32;
using RETURN = System.Int32;
////////////////////////////////

[DllImport("user32.dll")]
protected static extern IntPtr GetWindowLong(int hwindow, int unindex);

[DllImport("user32.dll")]
static extern RETURN CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, MESSAGE Msg, PARAM wParam, PARAM lParam);

[DllImport("user32.dll")]
protected static extern int SetWindowLong(int hwindow, int unindex, WndProcDelegate lnewvalue);

private void Form1_Load(object sender, EventArgs e)
{
this.webBrowser1.Navigate("http://www.google.com.hk/");
this.webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);//必需在文档加载完后才能查找窗口成功
}

bool add = false;
IntPtr oldWindow = IntPtr.Zero;
const int GWL_WNDPROC = -4;
public delegate RETURN WndProcDelegate(IntPtr hWnd, MESSAGE msg, PARAM wParam, PARAM lParam);
public WndProcDelegate MyCallWindowProc;

void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if(add)
{ return; }
add = true;
FindWindow fw = new FindWindow(this.Handle, "Internet Explorer_Server");
IntPtr hIE = fw.FoundHandle;

if (hIE.ToInt32() != 0)
{
oldWindow = GetWindowLong(hIE.ToInt32(), GWL_WNDPROC);
MyCallWindowProc = new WndProcDelegate(WndProc);
SetWindowLong(hIE.ToInt32(), GWL_WNDPROC, MyCallWindowProc);
}
}

public RETURN WndProc(IntPtr hWnd, MESSAGE Msg, PARAM WParam, PARAM LParam)
{
const int WM_ERASEBKGND = 0x14;

if (Msg == WM_ERASEBKGND)
{
return 1;
}

return CallWindowProc(oldWindow, hWnd, Msg, WParam, LParam);
}

class FindWindow
{
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
//IMPORTANT : LPARAM must be a pointer (InterPtr) in VS2005, otherwise an exception will be thrown
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
//the callback function for the EnumChildWindows
private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

//if found return the handle , otherwise return IntPtr.Zero
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

private string m_classname; // class name to look for

private IntPtr m_hWnd; // HWND if found
public IntPtr FoundHandle
{
get { return m_hWnd; }
}
// ctor does the work--just instantiate and go
public FindWindow(IntPtr hwndParent, string classname)
{
m_hWnd = IntPtr.Zero;
m_classname = classname;
FindChildClassHwnd(hwndParent, IntPtr.Zero);
}

private bool FindChildClassHwnd(IntPtr hwndParent, IntPtr lParam)
{
EnumWindowProc childProc = new EnumWindowProc(FindChildClassHwnd);
IntPtr hwnd = FindWindowEx(hwndParent, IntPtr.Zero, this.m_classname, string.Empty);
if (hwnd != IntPtr.Zero)
{
this.m_hWnd = hwnd; // found: save it
return false; // stop enumerating
}
EnumChildWindows(hwndParent, childProc, IntPtr.Zero); // recurse redo FindChildClassHwnd
return true;// keep looking
}
}


使用以上方法,webBrowser在重绘时不再擦除背景。但没料到的是,出现了这样一个bug:

在打开中文输入法情况下,一些标点符号无法输入到网页上的编辑框里。包括";‘,。"等等。但输入汉字没问题,英文(标点)也没问题。

测试发现,一次按键(标点符号键),WndProc收到了正确的WM_KEYDOWN及WM_KEYUP消息。但没有收到WM_IME_CHAR。收到了两个WM_CHAR,但不论是单独还是组合起来,都和按键内容没有任何关联。


我找不出我代码中有什么错误,估计这又是C#的一个bug。欢迎大家给出建议或帮忙顶贴。并盼JinagSheng大哥能再次给出指点。如果是确实是C#的bug,能否向微软反应?









...全文
314 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
足球中国 2011-06-15
  • 打赏
  • 举报
回复
从你的代码来看和文字输入没有啥关系。考虑下输入法吧。有几款输入都是有BUG的。
ningfeihu 2011-06-15
  • 打赏
  • 举报
回复
路过,学习,打酱油,接分,完毕。
PerDign 2011-06-15
  • 打赏
  • 举报
回复
眼睛看麻了
大狗狗 2011-06-15
  • 打赏
  • 举报
回复
楼上朋友一语中的!

我安装的输入法都是老式的微软五笔和微软拼音。下载了一个QQ输入法后,果然没问题了!微软的输入法坑爹呀!

再次感谢zanfeng!!
大狗狗 2011-06-14
  • 打赏
  • 举报
回复
楼上朋友:

它假如一个字符也画不出来,我反倒不怕。怕就怕英文字符和汉字全能正常显示,只是一些中文标点显示不出来。另外,VC中WebBrowser广泛采用了不画背景。
足球中国 2011-06-14
  • 打赏
  • 举报
回复
好象也并不存在什么输进去与输不进去。
楼主所说输进去与输不进去也只是按的键盘能不能显示。显示也是一个绘制的过程。
楼主既然钩住winproc这个消息。已经阻止背景重绘。未必webbrower控件 不是因为重绘背景来产生文字。
大狗狗 2011-06-14
  • 打赏
  • 举报
回复
实在是无计可施了,求帮忙。
ohkuy 2011-06-14
  • 打赏
  • 举报
回复
在高点的版本中有没有呢?
比如VS2010+Win7+IE9
isjoe 2011-06-14
  • 打赏
  • 举报
回复
有高度。。。。。。。。。。
大狗狗 2011-06-14
  • 打赏
  • 举报
回复
再up一下
hangang7403 2011-06-14
  • 打赏
  • 举报
回复
bangding...
大狗狗 2011-06-13
  • 打赏
  • 举报
回复
它要是一个字符都收不到,获者只能接收英文字符而中文字符一个都收不到,我反而不怕。怕就怕只是个别中文标点输不进去,其余都没事。这个实在有点无解。。
足球中国 2011-06-13
  • 打赏
  • 举报
回复
webbrower底下其实是MSHTML.dll。
这个好象不是BUG.WM_CHAR 消息不在winpro这个消息内。。

ProcessKeyPreviewmsg 重载这个消息。

大狗狗 2011-06-13
  • 打赏
  • 举报
回复
自己顶一下
Maa 2011-06-13
  • 打赏
  • 举报
回复
帮顶吧,呵呵。
bforesc 2011-06-13
  • 打赏
  • 举报
回复
帮你UP。

110,579

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧