2

我认为即使在渲染页面之后,删除脚本标签和标签中的相关属性也会起作用,但没有。

以下代码删除了 script 标签和 onclick 属性,但没有任何效果。

任何想法?

我想避免:

  • 编辑注册表,因为它需要管理员权限。
  • 单独获取网页内容并使用 doc.write() 因为它使代码复杂。

文件:

  • javascript.html
  • 测试.ahk

javascript.html

<!DOCTYPE html>
<html>
    <head>
        <script> function displayDate() { document.getElementById("demo").innerHTML=Date(); }</script>
    </head>
    <body>
        <p id="demo" onclick="displayDate()">This is a paragraph. Click here.</p>
    </body>
</html> 

测试.ahk

    Gui, Add, ActiveX, vWB w400 h300, Shell.Explorer  
    Gui, Show, w420 h320
    WB.Navigate("file:///" A_ScriptDir "/javascript.html")
    Loop
       Sleep 10
    Until (WB.readyState=4 && WB.document.readyState="complete" && !WB.busy)        

    doc := WB.document
    nodeScript := doc.getElementsByTagName("script")[0]
    nodeScript.parentNode.removeChild(nodeScript)
    nodeP := doc.getElementsByTagName("p")[0]
    nodeP.removeAttribute("onclick") 

    msgbox % doc.documentElement.outerHTML
    Return
4

1 回答 1

0

通过实现三个特定的 COM 接口(和)并调用控件的 IOleObject 接口的 SetClientSite 方法,IOleClientSite可以强制为给定的 WebBrowser 控件启用/禁用脚本。IServiceProviderIInternetSecurityManager

最终,您需要实现该IInternetSecurityManager::ProcessUrlAction方法。当 WebBrowser 调用它并将dwAction参数设置为 时URLACTION_SCRIPT_RUN,您可以设置*pPolicyURLPOLICY_DISALLOW以阻止脚本或URLPOLICY_ALLOW启用脚本,并返回S_OK(零)以强制执行策略。

必要的代码如下所示,可以SetWBClientSite()在创建控件之后导航之前简单地调用来实现。全局变量WB必须包含对 WebBrowser 控件的引用。

/*  Complex workaround to override "Active scripting" setting
 *  and ensure scripts can't run within the WebBrowser control.
 */

global WBClientSite

SetWBClientSite()
{
    interfaces := {
    (Join,
        IOleClientSite: [0,3,1,0,1,0]
        IServiceProvider: [3]
        IInternetSecurityManager: [1,1,3,4,8,7,3,3]
    )}
    unkQI      := RegisterCallback("WBClientSite_QI", "Fast")
    unkAddRef  := RegisterCallback("WBClientSite_AddRef", "Fast")
    unkRelease := RegisterCallback("WBClientSite_Release", "Fast")
    WBClientSite := {_buffers: bufs := {}}, bufn := 0, 
    for name, prms in interfaces
    {
        bufn += 1
        bufs.SetCapacity(bufn, (4 + prms.MaxIndex()) * A_PtrSize)
        buf := bufs.GetAddress(bufn)
        NumPut(unkQI,       buf + 1*A_PtrSize)
        NumPut(unkAddRef,   buf + 2*A_PtrSize)
        NumPut(unkRelease,  buf + 3*A_PtrSize)
        for i, prmc in prms
            NumPut(RegisterCallback("WBClientSite_" name, "Fast", prmc+1, i), buf + (3+i)*A_PtrSize)
        NumPut(buf + A_PtrSize, buf + 0)
        WBClientSite[name] := buf
    }
    global wb
    if pOleObject := ComObjQuery(wb, "{00000112-0000-0000-C000-000000000046}")
    {   ; IOleObject::SetClientSite
        DllCall(NumGet(NumGet(pOleObject+0)+3*A_PtrSize), "ptr"
            , pOleObject, "ptr", WBClientSite.IOleClientSite, "uint")
        ObjRelease(pOleObject)
    }
}

WBClientSite_QI(p, piid, ppvObject)
{
    static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
    static IID_IOleClientSite := "{00000118-0000-0000-C000-000000000046}"
    static IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}"
    iid := _String4GUID(piid)
    if (iid = IID_IOleClientSite || iid = IID_IUnknown)
    {
        NumPut(WBClientSite.IOleClientSite, ppvObject+0)
        return 0 ; S_OK
    }
    if (iid = IID_IServiceProvider)
    {
        NumPut(WBClientSite.IServiceProvider, ppvObject+0)
        return 0 ; S_OK
    }
    NumPut(0, ppvObject+0)
    return 0x80004002 ; E_NOINTERFACE
}

WBClientSite_AddRef(p)
{
    return 1
}

WBClientSite_Release(p)
{
    return 1
}

WBClientSite_IOleClientSite(p, p1="", p2="", p3="")
{
    if (A_EventInfo = 3) ; GetContainer
    {
        NumPut(0, p1+0) ; *ppContainer := NULL
        return 0x80004002 ; E_NOINTERFACE
    }
    return 0x80004001 ; E_NOTIMPL
}

WBClientSite_IServiceProvider(p, pguidService, piid, ppvObject)
{
    static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
    static IID_IInternetSecurityManager := "{79eac9ee-baf9-11ce-8c82-00aa004ba90b}"
    if (_String4GUID(pguidService) = IID_IInternetSecurityManager)
    {
        iid := _String4GUID(piid)
        if (iid = IID_IInternetSecurityManager || iid = IID_IUnknown)
        {
            NumPut(WBClientSite.IInternetSecurityManager, ppvObject+0)
            return 0 ; S_OK
        }
        NumPut(0, ppvObject+0)
        return 0x80004002 ; E_NOINTERFACE
    }
    NumPut(0, ppvObject+0)
    return 0x80004001 ; E_NOTIMPL
}

WBClientSite_IInternetSecurityManager(p, p1="", p2="", p3="", p4="", p5="", p6="", p7="", p8="")
{
    if (A_EventInfo = 5) ; ProcessUrlAction
    {
        if (p2 = 0x1400) ; dwAction = URLACTION_SCRIPT_RUN
        {
            NumPut((URLPOLICY_DISALLOW := 3), p3+0)  ; *pPolicy := URLPOLICY_DISALLOW
            return 0 ; S_OK
        }
    }
    return 0x800C0011 ; INET_E_DEFAULT_ACTION
}

_String4GUID(pGUID)
{
    VarSetCapacity(String,38*2)
    DllCall("ole32\StringFromGUID2", "ptr", pGUID, "str", String, "int", 39)
    Return  String
}

当前的 AutoHotkey 安装程序包含与此相同的代码,不同之处在于它设置为URLPOLICY_ALLOW(0) 而不是URLPOLICY_DISALLOW(3)。这对于允许安装程序在禁用脚本的系统上工作是必要的。

如您所见,直接在 AutoHotkey 脚本中实现 COM 接口并非易事。在普通 C 中要容易一些(参见普通 C 中的 COM),而在 C++ 中要容易得多。

于 2013-03-02T08:43:40.423 回答