2

I need to close a download popup in web browser control (disallow user to downloading file). How i can achieve this?

I found this: How to block downloads in .NET WebBrowser control?

And i used second answer. It's working but i have problem with it. It's seems that calling GetText of the created object is blocking a whole thread. I don't have any solution for it.

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

//edit

Ok, thanks @sgorozco for suggestion. Now i'm using SetWindowsHookEx and WH_CBT. Then in message loop i'm catching HCBT_CREATEWND events. But i have problem with getting CBT_CREATEWND from lparm. I'm getting "Managed Debugging Assistant 'FatalExecutionEngineError'" exception.

Here is my current code:

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

//edit 2

Here are my definitions:

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

My myCallbackDelegate is a static field so it's not GC collected for sure. Temporary i'm enumerating all windows every 500ms and look for dialog which contains text "File Download". But it is an ugly solution.

Community
  • 1
  • 1
Yozer
  • 648
  • 1
  • 11
  • 26
  • I am not 100% sure, but the reason the call may be blocking could be that at the stage that the hook intercepts the call, the window is about to be created, so there's no window text to retrieve yet. Maybe if you hook to the `CBT_ACTIVATE` event rather than `HCBT_CREATEWND`, you could still accomplish what you desire (the hook will be called many more times, but at least at that point the windows are guaranteed to have been created). Good Luck! –  Jan 28 '14 at 01:51
  • 1
    @sgorozco, if you posted your comment as an answer, I'd up-vote it. The OP still can access the window text via `CBT_CREATEWND`/`CREATESTRUCT` inside `CBTProc`, no need to call `GetText` for that. – noseratio Jan 28 '14 at 05:15
  • @Yozer. It's strange - I don't see any evident problems in the code, the struct definitions seem to be right as well as the `Marshal.PtrToStructure()` calls. Can you post the complete declaration of `myCallbackDelegate` (including the delegate definition) as well as the code that links the `MessageLoopFunction()` to the `myCallbackDelegate` parameter? I suspect some Interop decorations are missing for the delegate declaration and maybe that could be the reason why the `lparam` is not receiving a valid pointer in the first place. –  Jan 28 '14 at 18:03
  • @Yozer, make sure you keep the reference to `myCallbackDelegate` in the field of the class (i.e., `this.myCallbackDelegate`), otherwise it most likely gets freed by GC after the `SetWindowsHookEx` call. – noseratio Jan 29 '14 at 02:40
  • @Yozer, Hi! Could you please try adding the following attribute to your HookProc delegate and try again? –  Jan 29 '14 at 19:45
  • `[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);` –  Jan 29 '14 at 19:50
  • @sgorozco Hi! Unfortunately problem still occurs - Managed Debugging Assistant 'FatalExecutionEngineError'. I don't any have idea why. Maybe my Windows 8 is a problem? Diffrent API? I will try my program on virtual machine. – Yozer Jan 30 '14 at 14:51
  • :( How about CallingConvention.StdCall ? sorry if I'm guessing, but I've been bitten before with callbacks having incompatible calling conventions. –  Jan 30 '14 at 17:27
  • Still the same problem. On my machine with win8 and on virtual machine with win7. – Yozer Jan 30 '14 at 19:04

1 Answers1

0

The reason for the FatalExecutionEngineError are the strings in CREATESTRUCT. Replace these with a IntPtr and you will get no exception.

[StructLayout(LayoutKind.Sequential)]
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 IntPtr lpszName;
   public IntPtr lpszClass;
   public int dwExStyle;
}

(Maybe you can use GetClassName and GetWindowText instead as workaround. not tested)

Kux
  • 1,362
  • 1
  • 16
  • 31