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

来源:互联网 发布:plc虚拟仿真软件 编辑:程序博客网 时间:2024/05/18 12:38

本文探讨在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获取完毕。我们的测试网页,在我的电脑上显示结果如下:

 

原创粉丝点击