Tuesday, January 15, 2008

Using WebKit on Windows

Since I research WebKit, I try writing how to use WebKit in your application.

WebKit has COM interface, so you need use it via COM interface. This way is same as Trident (MSHTML Web Browser Control) of Internet Explorer.

Initialize

At first, you get IWebView interface using CoCreateInstance(). Then, when you call IWebView::initWithFrame() with window handle of parent window, so you can create WebKit window.

IWebView *pWebView;
HRESULT hr;

hr = ::CoCreateInstance(CLSID_WebView,
                        0,
                        CLSCTX_ALL,
                        IID_IWebView,
                        (void**)&pWebView);
if(hr != S_OK)
    goto error;

hr = pWebView->setHostWindow((OLE_HANDLE) hWnd);
if(hr != S_OK)
    goto error;

::GetClientRect(hWnd,&clientRect);
hr = pWebView->initWithFrame(clientRect, NULL, NULL);
if(hr != S_OK)
    goto error;

Loading URL...

You cannot use takeStringURL like MacOS X sample. This method will return E_NOTIMPL.

If you want to use WebKit on Windows, you get IWebURLRequest object via CoCreateInstance(), then, you call IWebFrame::loadRequest(). If you want to open HTML stirng, you can use other method of IWebView.

HRESULT hr;
BSTR str;
IWebFrame* pWebFrame;
IWebURLRequest * pWebURLRequest;
IWebView* pWebView;

hr = ::CoCreateInstance(CLSID_WebURLRequest,
                        0,
                        CLSCTX_ALL,
                        IID_IWebURLRequest,
                        (void**)&pWebURLRequest);
if(hr != S_OK)
    goto error;

str = ::SysAllocString(L"http://www.apple.com/");
hr = pWebURLRequest->initWithURL(str,
                                 WebURLRequestUseProtocolCachePolicy,
                                 60);
if(hr != S_OK)
    goto error;

hr = pWebView->mainFrame(&pWebFrame);
if(hr != S_OK)
    goto error;

hr = pWebFrame->loadRequest(pWebURLRequest);
if(hr != S_OK)
    goto error;

pWebURLRequest->Release();
pWebFrame->Release();

Thursday, January 10, 2008

How to Handle Back Key on .NET Compact Framework 2.0

When you start to develop Windows Mobile 6.0 Standard using C# (.NET Compact Framework 2.0), you will hit a trouble of Back key handling.

When I am looking for the resolution of this, I found the following document in MSDN./

How to: Override the Smartphone Back Key

BUT, although I add code for "Keys.Escape" and "Keys.Back", I cannot handle back key. This docuemnt is for .NET Compact framework 3.5???. So I am looking for it again, I found the following posts.

Capture Back Key - MSDN Forum

Mauricio,

This is a bug in CF. Setting the form's KeyPreview property to true should allow you to handle the Back key in the form's KeyPress event handler. However, I've discovered that the KeyPress event is only fired if the focused control is a container control (form, tab page, panel, etc.).

I'm investigating a couple of possible workarounds. I'll let you know if I find one.

Dan

This post says that it is no way to use C#. So although I try using sub class, .NET Comapct Framework has no method of WndProc. So, to call Win32 API directly, I can handle back key. I believe that a true way is to use SHCMBM_OVERRIDEKEY.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowProc
{
    public partial class Form1 : Form
    {
        #region P/Invoke
        public const int GWL_WNDPROC = -4;
        public const uint WM_HOTKEY = 0x0312;

        [DllImport("coredll.dll")]
        public extern static IntPtr SetWindowLong(IntPtr hwnd,
                                                  int nIndex,
                                                  IntPtr dwNewLong);

        [DllImport("coredll.dll")]
        public extern static int CallWindowProc(IntPtr lpPrevWndFunc,
                                                IntPtr hwnd,
                                                uint msg,
                                                uint wParam,
                                                int lParam);

        [DllImport("coredll.dll")]
        public extern static int PostMessage(IntPtr hwnd,
                                             uint msg,
                                             uint wParam,
                                             uint lParam);
        #endregion

        public delegate int WndProcDelegate(IntPtr hwnd, uint msg, uint wParam, int lParam);

        IntPtr mOldWndProc;
        WndProcDelegate mProc;

        public Form1()
        {
            InitializeComponent();

            mProc = new WndProcDelegate(WndProc);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetHook();
        }

        private void SetHook()
        {
            IntPtr hwnd = this.Handle;
            if (hwnd == IntPtr.Zero)
            {
                throw new InvalidOperationException("hWnd is null");
            }

            mOldWndProc = SetWindowLong(hwnd,
                                        GWL_WNDPROC,
                                        Marshal.GetFunctionPointerForDelegate(mProc));
        }

        // Restores the original window procedure for the control.
        private void Unhook()
        {
            IntPtr hwnd = this.Handle;
            if (hwnd == IntPtr.Zero)
            {
                throw new InvalidOperationException("hWnd is null");
            }

            SetWindowLong(hwnd, GWL_WNDPROC, mOldWndProc);
        }

        protected virtual int WndProc(IntPtr hwnd, uint msg, uint wParam, int lParam)
        {
            if (msg == WM_HOTKEY && (lParam & 0xffff0000) == 0x1b0000)
            {
                if ((lParam & 0x1000) == 0)
                {
                    //
                    // This is key down message of [Back] key
                    //
                }
                else
                {
                    //
                    // This is key up message of [Back] key
                    //
                }
                return 1;
            }

            return CallWindowProc(mOldWndProc, hwnd, msg, wParam, lParam);
        }
    }
}