【发布时间】:2014-01-27 21:51:08
【问题描述】:
我需要在 Web 浏览器控件中关闭下载弹出窗口(禁止用户下载文件)。 我怎样才能做到这一点?
我发现了这个: How to block downloads in .NET WebBrowser control?
我使用了第二个答案。它正在工作,但我有问题。似乎调用已创建对象的 GetText 正在阻塞整个线程。我没有任何解决办法。
private static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (idObject == 0 && idChild == 0)
{
if(eventType == EVENT_OBJECT_CREATE)
{
string text = GetText(hwnd);
if (text.Contains("File Download"))
SendMessage(hwnd, 0x0010, IntPtr.Zero, IntPtr.Zero); //close window
}
}
}
public static string GetText(IntPtr hWnd)
{
int length = GetWindowTextLength(hWnd); //my app is freezing here - i think it's because i'm calling it from message loop.
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
//编辑
好的,感谢@sgorozco 的建议。现在我正在使用 SetWindowsHookEx 和 WH_CBT。然后在消息循环中,我正在捕获 HCBT_CREATEWND 事件。但是我从 lparm 获取 CBT_CREATEWND 有问题。我收到“托管调试助手'FatalExecutionEngineError'”异常。
这是我当前的代码:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CREATESTRUCT
{
public IntPtr lpCreateParams;
public IntPtr hInstance;
public IntPtr hMenu;
public IntPtr hwndParent;
public int cy;
public int cx;
public int y;
public int x;
public int style;
public string lpszName;
public string lpszClass;
public int dwExStyle;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CBT_CREATEWND
{
public IntPtr lpcs;
public IntPtr hwndInsertAfter;
}
private static IntPtr MessageLoopFuctnion(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
{
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
if(code == 3)
{
CBT_CREATEWND info;
info = (CBT_CREATEWND)Marshal.PtrToStructure(lParam, typeof(CBT_CREATEWND));
CREATESTRUCT info1;
info1 = (CREATESTRUCT)Marshal.PtrToStructure(info.lpcs, typeof(CREATESTRUCT)); //here exception is throwing
if (info1.lpszName != null && info1.lpszName.Contains("File Download")))
SendMessage(wParam, 0x0010, IntPtr.Zero, IntPtr.Zero); //close popup
//Marshal.FreeHGlobal(info.lpcs); //error, why?
//Marshal.FreeHGlobal((IntPtr)lParam.ToUInt64());
}
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
//set hook
IntPtr hWinEventHook = SetWindowsHookEx(5, myCallbackDelegate, user32DLL, 0);
//编辑2
这是我的定义:
private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
private static HookProc myCallbackDelegate = new HookProc(MessageLoopFuctnion);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
我的 myCallbackDelegate 是一个静态字段,所以它肯定不会被 GC 收集。 临时我每 500 毫秒枚举所有窗口并查找包含文本“文件下载”的对话框。但这是一个丑陋的解决方案。
【问题讨论】:
-
我不是 100% 确定,但是调用可能被阻塞的原因可能是在钩子拦截调用的阶段,窗口即将被创建,所以没有窗口文本可检索呢。也许如果你钩到
CBT_ACTIVATE事件而不是HCBT_CREATEWND,你仍然可以完成你想要的(钩子会被调用很多次,但至少在那个时候窗口被保证已经被创建)。祝你好运! -
@sgorozco,如果您将评论作为答案发表,我会投票赞成。 OP 仍然可以通过
CBTProc内的CBT_CREATEWND/CREATESTRUCT访问窗口文本,无需为此调用GetText。 -
@Yozer。这很奇怪 - 我在代码中看不到任何明显的问题,结构定义似乎是正确的,就像
Marshal.PtrToStructure()调用一样。您能否发布myCallbackDelegate的完整声明(包括委托定义)以及将MessageLoopFunction()链接到myCallbackDelegate参数的代码?我怀疑委托声明缺少一些 Interop 装饰,这可能是lparam首先没有收到有效指针的原因。 -
@Yozer,确保在类的字段中保留对
myCallbackDelegate的引用(即this.myCallbackDelegate),否则它很可能在SetWindowsHookEx调用后被GC 释放。 -
@sgorozco 看看我的编辑。
标签: c# download popup webbrowser-control message-loop