65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Internet Explorer 窗口中添加状态栏窗格并在原地取消网页密码的显示

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (12投票s)

2007年12月15日

CPOL

2分钟阅读

viewsIcon

60967

downloadIcon

817

本文演示了如何向 Internet Explorer 窗口添加状态栏窗格,以及如何使用它来管理网页密码字段。

Screenshot - Added status bar pane

引言

在浏览网页时,Internet Explorer 状态栏指示器非常有用,并允许访问几个内置应用程序,例如弹出窗口阻止程序、网络钓鱼过滤器或安全小程序。与 IE 工具栏按钮不同,微软并未向开发者说明如何向 Internet Explorer 窗口添加状态栏窗格。

本文展示了如何使用子类化技巧添加状态栏窗格。

首先,找到并子类化状态栏窗口,然后创建一个窗格窗口(作为 STATIC 控件)。接下来,选择任何现有的窗格,调整其大小以插入一个新的窗格,并将窗格窗口放置在所需的现有窗格上方。
新的状态窗格应与任何典型的窗格完全相同地绘制和主题化(适用于 XP 或 Vista),并且应处理鼠标单击以防止来自其后方原生窗格的通知。

通用步骤

  1. 创建一个从 Internet Explorer 内部启动的浏览器助手对象
    extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, 
        LPVOID /*lpReserved*/)
    {
        if (dwReason == DLL_PROCESS_ATTACH)
        {
            TCHAR szLoader[MAX_PATH];
            memset(szLoader,0,MAX_PATH);
            GetModuleFileName(NULL, szLoader, MAX_PATH);
            _tcslwr(szLoader);
            if (_tcsstr(szLoader,_T("iexplore.exe")) == 0 && 
                _tcsstr(szLoader,_T("regsvr32.exe")) == 0)
                return FALSE;
  2. 找到状态栏窗口并子类化它
    LONG nBrowser = NULL;
    m_pWebBrowser2->get_HWND(&nBrowser);
    
    if(nBrowser)
    {
        g_hIcon = LoadIcon(_Module.m_hInst, MAKEINTRESOURCE(IDI_ICON_START));
    
        TCHAR szClassName[MAX_PATH];
        HWND hWndStatusBar = NULL;
    
        // looking for a TabWindowClass window in IE7
        // the last one should be parent for statusbar
        HWND hTabWnd = GetWindow((HWND)nBrowser, GW_CHILD);
        if(hTabWnd)
        {
            while(hTabWnd)
            {
                memset(szClassName,0,MAX_PATH);
                GetClassName(hTabWnd, szClassName, MAX_PATH);
                if(_tcscmp(szClassName, _T("TabWindowClass")) == 0)
                    nBrowser = (LONG)hTabWnd;
    
                hTabWnd = GetWindow(hTabWnd, GW_HWNDNEXT);
            }
        }
    
        HWND hWnd = GetWindow((HWND)nBrowser, GW_CHILD);
        if(hWnd)
        {
            while(hWnd)
            {
                memset(szClassName,0,MAX_PATH);
                GetClassName(hWnd, szClassName, MAX_PATH);
                if(_tcscmp(szClassName,_T("msctls_statusbar32")) == 0)
                {
                    if(hWnd)
                        hWndStatusBar = hWnd;
                    break;
                }
    
                hWnd = GetWindow(hWnd, GW_HWNDNEXT);
            }
        }
    
        if(hWndStatusBar)
        {
            g_pWndProcStatus = (WNDPROC)SetWindowLong(hWndStatusBar, 
                GWL_WNDPROC, (LPARAM)(WNDPROC)NewStatusProc);
        ...
  3. 创建一个窗格窗口作为 STATIC 控件并子类化它
    HWND hWndNewPane = CreateWindowEx(NULL, _T("static"),_T(""),WS_CHILD | 
        WS_VISIBLE,0,0,0,0,hWndStatusBar,(HMENU)3333,_Module.m_hInst,NULL);
    
    if(hWndNewPane && IsWindow(hWndNewPane))
    {
        HFONT hFont = (HFONT)SendMessage(hWndStatusBar, WM_GETFONT, 0, 0);
        SendMessage(hWndNewPane, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
    
        GetUxtheme(hWndNewPane);
    
        g_pWndProcPane = (WNDPROC)SetWindowLong(hWndNewPane, GWL_WNDPROC, 
            (LPARAM)(WNDPROC)PaneWindowProc);
        ...
  4. 处理状态栏的重要消息
    static LRESULT CALLBACK NewStatusProc
        (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        ...
        switch (message)
        {
            case SB_SIMPLE: // hide the pane when the user scrolls the menu
                ::ShowWindow(g_hWndNewPane, !(BOOL)wParam);
                break;
            case WM_SYSCOLORCHANGE: // query updated XP theme
                GetUxtheme(g_hWndNewPane);
                break;
            ...
            case SB_SETPARTS: // resize the existing pane and move the new pane over
            {
                if(lParam && wParam)
                {
                    unsigned int nParts = wParam;
    
                    HLOCAL hLocal = LocalAlloc(LHND, sizeof(int) * (nParts+1));
                    LPINT lpParts = (LPINT)LocalLock(hLocal);
                    memcpy(lpParts, (void*)lParam, wParam*sizeof(int));
    
                    g_nNewPaneWidth = 32;
                    unsigned nCurWidth = 0;
    
                    for(unsigned j=0;j<nParts-1;j++)
                    {
                        nCurWidth = lpParts[j+1]-lpParts[j];
                        if(g_nNewPaneWidth > nCurWidth && nCurWidth>1)
                            g_nNewPaneWidth = nCurWidth;
                    }
    
                    g_nNewPaneWidth += 2;
                    if(g_nNewPanePosition<nParts)
                    {
                        for(unsigned i=0;i<g_nNewPanePosition;i++)
                            lpParts[i] -= g_nNewPaneWidth;
                    }
    
                    LRESULT hRet = CallWindowProc(g_pWndProcStatus, hWnd, 
                    message, wParam, (LPARAM)lpParts);
    
                    CRect rcPane;
                    SendMessage(hWnd, SB_GETRECT, g_nNewPanePosition, (LPARAM)&rcPane);
    
                    if(IsWindow(g_hWndNewPane))
                        MoveWindow(g_hWndNewPane, lpParts[g_nNewPanePosition] - 
                            g_nNewPaneWidth, rcPane.top, g_nNewPaneWidth, 
                            rcPane.Height(), TRUE);
    
                    LocalFree(hLocal);
    
                    return hRet;
                }
            }
                break;
            default:
                break;
    }
  5. 处理新窗格的 WM_PAINT 消息
    static LRESULT CALLBACK PaneWindowProc(HWND hWnd, UINT message, 
        WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
            case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hDC = BeginPaint(hWnd, &ps);
    
                CRect rcClient;
                GetClientRect(hWnd, &rcClient);
    
                int nDrawEdge = 0;
                // not themed
                if(g_hTheme == NULL)
                {
                    FillRect(hDC, &rcClient, (HBRUSH)(COLOR_BTNFACE+1));
    
                    DrawEdge(hDC,&rcClient,BDR_RAISEDINNER,BF_LEFT);
    
                    rcClient.left += 3;
                    nDrawEdge = 3;
                    DrawEdge(hDC,&rcClient,BDR_SUNKENOUTER,BF_RECT);
                }
                else
                {
                    DRAWTHEMEBACKGROUND pfnDrawThemeBackground = 
                        (DRAWTHEMEBACKGROUND)::GetProcAddress
                        (g_hUxtheme, "DrawThemeBackground");
                    if(pfnDrawThemeBackground)
                        pfnDrawThemeBackground(g_hTheme, hDC, SP_PANE, NULL, 
                        &rcClient, NULL);
    
                    // copy separator picture from right to left
                    int nHeight = rcClient.Height();
                    int nWidth = rcClient.Width() - 2;
                    for(int i=0;i<2;i++)
                    {
                        for(int j=0;j<nHeight;j++)
                            SetPixel(hDC,i,j,GetPixel(hDC,i+nWidth,j));
                    }
                }
    
                if(g_hIcon)
                    DrawIconEx(hDC,(rcClient.Width() - 16)/2 + nDrawEdge, 
                        (rcClient.Height() - 16)/2, g_hIcon,16,16,NULL,NULL,DI_NORMAL);
    
                EndPaint(hWnd, &ps);
    
                return 0;
            }
            ...

默认情况下,Internet Explorer 状态栏包含几个窗格。第一个窗格(左侧)是一个分隔符,可以显示菜单提示和已访问的网页通知。第二个窗格通常是不可见的,包含一个进度控件。当 Web 导航开始时,此窗格变为可见并可以显示下载进度。接下来的窗格可以被 Internet Explorer 的内置工具占用,例如弹出窗口阻止程序或网络钓鱼过滤器。

例如,我决定将新窗格放置在第三个位置,并保留足够的空间来显示一个小图标

UINT      g_nNewPaneWidth = 20;
UINT      g_nNewPanePosition = 2;

因此,现在窗格已完成并准备好使用。

在附带本文的示例代码中,有一个新创建的窗格用于访问名为 Asterisk Master 的密码显示应用程序,该应用程序已发布在 我的网站上。

Added status bar pane

当 Internet Explorer 完成打开任何网页后,Asterisk Master 开始搜索密码输入框,并将其替换为普通的文本输入框,因此所有隐藏字符都变得可读。

密码输入框可以在 HTML 中通过 type=password 属性定义。

<INPUT id=inputPassword type=password value="" name=passwd>

如果在运行时将 type=password 属性替换为 type=text ,所有星号遮蔽的字符都将变得可读。

因此,订阅 IWebBrowser2 事件,并在触发 DISPID_DOWNLOADCOMPLETE 时处理已访问的网页

STDMETHODIMP CFieldManager::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, 
        WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, 
        EXCEPINFO*  pExcepInfo,  UINT* puArgErr)
{
    if (!pDispParams)
        return E_INVALIDARG;

    switch (dispidMember)
    {
    case DISPID_DOWNLOADBEGIN:
        g_hIcon = LoadIcon(_Module.m_hInst, MAKEINTRESOURCE(IDI_ICON_START));
        RedrawWindow(g_hWndNewPane,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW);
        break;
    case DISPID_DOWNLOADCOMPLETE:
        m_bPasswordsFound = FALSE;
        ShowPasswords();
        if(m_bPasswordsFound)
        {
            if(g_bUnmaskNeeded)
                g_hIcon = LoadIcon(_Module.m_hInst, MAKEINTRESOURCE(IDI_ICON_UNLOCK));
            else
                g_hIcon = LoadIcon(_Module.m_hInst, MAKEINTRESOURCE(IDI_ICON_LOCK));
        }
        else
            g_hIcon = LoadIcon(_Module.m_hInst, MAKEINTRESOURCE(IDI_ICON_START));

        RedrawWindow(g_hWndNewPane,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW);
        break;
    default:
        break;
}

接下来,ShowPassword() 函数扫描网页中的密码字段,并在需要时替换 type 属性。

请随时发布错误、问题或请求。

© . All rights reserved.