Windows平台WebKit的Plugin机制(一)——搜索插件

6 篇文章 0 订阅
3 篇文章 0 订阅

本文探讨在Windows平台下,WebKit如何搜索插件。

用于测试的网页代码如下:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    </head>
    <body>
        <script language=javascript>
            var len = navigator.plugins.length;
            document.write("你的浏览器共支持" + len + "种plug-in:<BR>");
            document.write("<TABLE BORDER>");
            document.write("<CAPTION>PLUG-IN 清单</CAPTION>");
            document.write("<TR><TH>编号</TH><TH>名称</TH><TH>描述</TH><TH>文件名</TH></TR>");
            for (var i=0; i<len; i++){
                document.write("<TR><TD>" + i + "</TD>" + 
                    "<TD>" + navigator.plugins[i].name + "</TD>" + 
                    "<TD>" + navigator.plugins[i].description + "</TD>" + 
                    "<TD>" + navigator.plugins[i].filename) + "</TD></TR>"; 
            }
            document.write("</TABLE>");
        </script>
    </body>
</html>

这个网页的作用是列出当前浏览器支持的插件名称、描述和对应的文件。 

WebKit的插件是延迟加载,并非一打开浏览器就加载所有插件。这个例子中,当JS执行到navigator.plugins.length时,才开始初始化插件信息,此刻的调用栈截图如下:

 PluginDatabase对象构造完后,将会到几个特定的目录下寻找插件,这部分代码片段如下:

Vector<String> PluginDatabase::defaultPluginDirectories()
{
    Vector<String> directories;
    String ourDirectory = safariPluginsDirectory();

    if (!ourDirectory.isNull())
        directories.append(ourDirectory);
    addQuickTimePluginDirectory(directories);
    addAdobeAcrobatPluginDirectory(directories);
    addMozillaPluginDirectories(directories);
    addWindowsMediaPlayerPluginDirectory(directories);
    addMacromediaPluginDirectories(directories);
#if PLATFORM(QT)
    addJavaPluginDirectory(directories);
#endif

    return directories;
}

 其中:

sarariPluginsDirectory()返回的是WebKit当前目录(exe文件所在的目录)下的Plugins子目录;

addQuickTimePluginDirectory()到注册表HKEY_LOCAL_MACHINE\Software\AppleComputer, Inc.\QuickTime下寻找InstallDir键,取它的值;

addAdobeAcrobatPluginDirectory()到注册表HKEY_LOCAL_MACHINE\Software\Adobe\AcrobatReader下寻找InstallPath键,取它的值(同时也会记录Adobe的版本号);

addMozillaPluginDirectories()到注册表HKEY_LOCAL_MACHINE\Software\Mozilla,遍历其子目录,寻找Plugins键,取它的值;

addWindowsMediaPlayerPluginDirectory()首先加入“C:\PFiles\Plugins”这个路径,再加入注册表HKEY_LOCAL_MACHINE\Software\Microsoft\MediaPlayer下Installation Directory的值;

addMacromediaPluginDirectories()加入了“C:\Windows\system32\macromed\Flash”和“C:\Windows\system32\macromed\Shockwave10”目录。

 

接下来,WebKit会遍历加入的这些目录,寻找np打头的dll文件,或者,如果遍历的目录是以“Shockwave 10”结尾,则寻找Plugin.dll,记录其路径。做完这些之后,WebKit还会到注册表HKEY_LOCAL_MACHINE\Software\MozillaPlugins和HKEY_CURRENT_USER\Software\MozillaPlugins下,遍历子目录,寻找Path键,将值记录下来。

经过以上步骤,WebKit会得到Windows下可用作插件的dll文件路径的集合。WebKit还会记录这些文件的最后修改时间,将来如果要重新加载插件,而dll文件最后修改时间有更新,则可能要重新获取dll文件的信息和加载新的dll文件。

WebKit获取dll文件信息的逻辑实现在PluginPackageWin.cpp的PluginPackage::fetchInfo()里,代码如下:

bool PluginPackage::fetchInfo()
{
    DWORD versionInfoSize, zeroHandle;
    versionInfoSize = GetFileVersionInfoSizeW(const_cast<UChar*>(m_path.charactersWithNullTermination()), &zeroHandle);
    if (versionInfoSize == 0)
        return false;

    OwnArrayPtr<char> versionInfoData = adoptArrayPtr(new char[versionInfoSize]);

    if (!GetFileVersionInfoW(const_cast<UChar*>(m_path.charactersWithNullTermination()),
            0, versionInfoSize, versionInfoData.get()))
        return false;

    m_name = getVersionInfo(versionInfoData.get(), "ProductName");
    m_description = getVersionInfo(versionInfoData.get(), "FileDescription");
    if (m_name.isNull() || m_description.isNull())
        return false;

    VS_FIXEDFILEINFO* info;
    UINT infoSize;
    if (!VerQueryValueW(versionInfoData.get(), L"\\", (LPVOID*) &info, &infoSize) || infoSize < sizeof(VS_FIXEDFILEINFO))
        return false;
    m_moduleVersion.leastSig = info->dwFileVersionLS;
    m_moduleVersion.mostSig = info->dwFileVersionMS;

    if (isPluginBlacklisted())
        return false;

    Vector<String> types;
    getVersionInfo(versionInfoData.get(), "MIMEType").split('|', types);
    Vector<String> extensionLists;
    getVersionInfo(versionInfoData.get(), "FileExtents").split('|', extensionLists);
    Vector<String> descriptions;
    getVersionInfo(versionInfoData.get(), "FileOpenName").split('|', descriptions);

    for (unsigned i = 0; i < types.size(); i++) {
        String type = types[i].lower();
        String description = i < descriptions.size() ? descriptions[i] : "";
        String extensionList = i < extensionLists.size() ? extensionLists[i] : "";

        Vector<String> extensionsVector;
        extensionList.split(',', extensionsVector);

        // Get rid of the extension list that may be at the end of the description string.
        int pos = description.find("(*");
        if (pos != -1) {
            // There might be a space that we need to get rid of.
            if (pos > 1 && description[pos - 1] == ' ')
                pos--;
            description = description.left(pos);
        }

        // Determine the quirks for the MIME types this plug-in supports
        determineQuirks(type);

        m_mimeToExtensions.add(type, extensionsVector);
        m_mimeToDescriptions.add(type, description);
    }

    return true;
}

这个方法使用Wndows API,获取dll文件的ProductName、FileDescription、Version、MIMEType、FileExtents、FileOpenName等信息(GetFileVersionInfoW(const_cast<UChar*>(m_path.charactersWithNullTermination()), 0, versionInfoSize, versionInfoData.get()),其中m_path存储了dll文件的路径)。我们测试网页中列出的插件名称和描述,就是在这个方法中获得的。这个方法还调用了另一个有意思的方法PluginPackage::isPluginBlacklisted()来判断插件是否被禁止。具体哪些插件被禁止以及为什么被禁止,想了解的人可以去看看这个方法。

通过以上步骤,PluginInfo获取完毕。我们的测试网页,在我的电脑上显示结果如下:

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值