【问题标题】:NPAPI Plugin for Chrome doesn't get past NP_InitializeChrome 的 NPAPI 插件无法通过 NP_Initialize
【发布时间】:2011-10-22 17:46:16
【问题描述】:

我一直在尝试为使用 NPAPI 插件的 Chrome 编写扩展程序。我正在使用 mingw 来编译它。我最初很难让 Chrome 加载插件,但现在我遇到了不同的问题。

我已经设法让 Chrome 调用 NP_GetEntryPoints 和 NP_Initialize,但之后它就崩溃了。到目前为止,这是我的代码...

ma​​in.cpp

#include <iostream>
#include <cstdlib>
#include <Windows.h>
#include <npapi.h>
#include <npfunctions.h>
#define Exported extern "C" __declspec(dllexport)

NPNetscapeFuncs NPNFuncs;

Exported NPError NP_Initialize(NPNetscapeFuncs* pFuncs) {

    if (pFuncs == NULL)
        return NPERR_INVALID_FUNCTABLE_ERROR;

    if (HIBYTE(pFuncs->version) > NP_VERSION_MAJOR)
        return NPERR_INCOMPATIBLE_VERSION_ERROR;

    if (pFuncs->size < sizeof(NPNetscapeFuncs))
        return NPERR_INVALID_FUNCTABLE_ERROR;

    // Save functions
    NPNFuncs.size             = pFuncs->size;
    NPNFuncs.version          = pFuncs->version;
    NPNFuncs.geturlnotify     = pFuncs->geturlnotify;
    NPNFuncs.geturl           = pFuncs->geturl;
    NPNFuncs.posturlnotify    = pFuncs->posturlnotify;
    NPNFuncs.posturl          = pFuncs->posturl;
    NPNFuncs.requestread      = pFuncs->requestread;
    NPNFuncs.newstream        = pFuncs->newstream;
    NPNFuncs.write            = pFuncs->write;
    NPNFuncs.destroystream    = pFuncs->destroystream;
    NPNFuncs.status           = pFuncs->status;
    NPNFuncs.uagent           = pFuncs->uagent;
    NPNFuncs.memalloc         = pFuncs->memalloc;
    NPNFuncs.memfree          = pFuncs->memfree;
    NPNFuncs.memflush         = pFuncs->memflush;
    NPNFuncs.reloadplugins    = pFuncs->reloadplugins;
    NPNFuncs.getJavaEnv       = pFuncs->getJavaEnv;
    NPNFuncs.getJavaPeer      = pFuncs->getJavaPeer;
    NPNFuncs.getvalue         = pFuncs->getvalue;
    NPNFuncs.setvalue         = pFuncs->setvalue;
    NPNFuncs.invalidaterect   = pFuncs->invalidaterect;
    NPNFuncs.invalidateregion = pFuncs->invalidateregion;
    NPNFuncs.forceredraw      = pFuncs->forceredraw;*/

    // Success
    MessageBoxA(0, "NP_Initialize", "Log", 0);
    return NPERR_NO_ERROR;

}

Exported void NP_Shutdown() {

    MessageBoxA(0, "NP_Shutdown", "Log", 0);

}

    /* Entry points */
    NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* savedData) {

        MessageBoxA(0, "NPP_New", "Log", 0);
        return NPERR_NO_ERROR;

    }

    NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {

        MessageBoxA(0, "NPP_GetValue", "Log", 0);
        return NPERR_NO_ERROR;

    }

    /*** Omitted... All the other functions are here, with just a MessageBox call in them ***/

Exported NPError NP_GetEntryPoints(NPPluginFuncs* pFuncs) {

    if (pFuncs == NULL)
        return NPERR_INVALID_FUNCTABLE_ERROR;

    if (pFuncs->size < sizeof(NPPluginFuncs))
        return NPERR_INVALID_FUNCTABLE_ERROR;

    pFuncs->size                = sizeof(NPPluginFuncs);
    pFuncs->version             = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
    pFuncs->newp                = &NPP_New;
    pFuncs->destroy             = &NPP_Destroy;
    pFuncs->setwindow           = &NPP_SetWindow;
    pFuncs->newstream           = &NPP_NewStream;
    pFuncs->destroystream       = &NPP_DestroyStream;
    pFuncs->asfile              = &NPP_StreamAsFile;
    pFuncs->writeready          = &NPP_WriteReady;
    pFuncs->write               = &NPP_Write;
    pFuncs->print               = &NPP_Print;
    pFuncs->event               = &NPP_HandleEvent;
    pFuncs->urlnotify           = &NPP_URLNotify;
    pFuncs->getvalue            = &NPP_GetValue;
    pFuncs->setvalue            = &NPP_SetValue;
    pFuncs->javaClass           = NULL;
    pFuncs->gotfocus            = &NPP_GotFocus;
    pFuncs->lostfocus           = &NPP_LostFocus;
    pFuncs->urlredirectnotify   = &NPP_URLRedirectNotify;
    pFuncs->clearsitedata       = &NPP_ClearSiteData;
    pFuncs->getsiteswithdata    = &NPP_GetSitesWithData;

    MessageBoxA(0, "NP_GetEntryPoints", "Log", 0);
    return NPERR_NO_ERROR;

}

我为每个函数添加了 MessageBox 调用,因此我可以查看是否调用了正确的函数。当我运行我的测试页面时,这是一个带有&lt;embed&gt; 标签的空白页面,我收到一条消息说NP_GetEntryPoints,然后是一条说NP_Initialize,然后Chrome 会弹出一个栏说我的插件已经崩溃。我认为问题出在我的NP_GetEntryPoints 上,但我就是看不到它……有什么我做错了,或者忘记做什么了吗?

我编译:

g++.exe -DWIN32 -D_WIN32 -D_WINDOWS -D_WIN32_WINNT=0x0600 -D_WIN32_IE=0x0600 -D_UNICODE -DUNICODE -static-libgcc -static-libstdc++ -c "main.cpp" -o main.o

windres.exe "resource.rc" "resource.o"

然后我用 :

链接到一个 .DLL
g++.exe -Wl,--subsystem,windows -o "npplugin.dll" -s -shared main.o resource.o -lcomctl32 -lws2_32 -luxtheme -lgdi32 -lshell32 -lshlwapi

【问题讨论】:

  • 有一点,虽然我怀疑这是问题所在,但这些都应该是 &NPP_New 等;在这种情况下,& 运算符在某些编译器中是可选的,但为了正确起见,您应该拥有它。
  • @Taxilian 谢谢,我忘记了。不幸的是,它对崩溃没有帮助:(。
  • 你导出的函数可能需要是__stdcall。
  • @Luke 他们是,它在npfunctions.h 的声明中设置。我在正确导出它们时遇到了一些麻烦,但我已经解决了这个问题......
  • 是吗?我很确定您需要在函数声明和定义中包含(相同的)调用约定。由于您的定义不包括它并且(大概)编译器没有抱怨它,我不确定。据我所知,npfunctions.h 似乎是一个标准头文件,它只定义函数签名而没有实际声明任何函数(除非你的函数被修改),所以那里指定的任何调用约定都不适用于你的函数。

标签: c++ windows google-chrome-extension npapi


【解决方案1】:

函数表之间的大小因浏览器和浏览器版本而异。

你检查你硬编译的库头文件的大小:

if (pFuncs->size < sizeof(NPNetscapeFuncs))
    return NPERR_INVALID_FUNCTABLE_ERROR;

这可能是问题所在。 例如最新的(在编写 gecko xulrunner SDK 时包含一个 84 字节大小的结构:

typedef struct _NPPluginFuncs {
  uint16_t size;
  uint16_t version;
  NPP_NewProcPtr newp;
  NPP_DestroyProcPtr destroy;
  NPP_SetWindowProcPtr setwindow;
  NPP_NewStreamProcPtr newstream;
  NPP_DestroyStreamProcPtr destroystream;
  NPP_StreamAsFileProcPtr asfile;
  NPP_WriteReadyProcPtr writeready;
  NPP_WriteProcPtr write;
  NPP_PrintProcPtr print;
  NPP_HandleEventProcPtr event;
  NPP_URLNotifyProcPtr urlnotify;
  void* javaClass;
  NPP_GetValueProcPtr getvalue;
  NPP_SetValueProcPtr setvalue;
  NPP_GotFocusPtr gotfocus;
  NPP_LostFocusPtr lostfocus;
  NPP_URLRedirectNotifyPtr urlredirectnotify;
  NPP_ClearSiteDataPtr clearsitedata;
  NPP_GetSitesWithDataPtr getsiteswithdata;
  NPP_DidCompositePtr didComposite;
} NPPluginFuncs;

Chrome 发送一个 80 字节的结构体。

所以我猜最后一个函数指针不在chrome使用的结构中。

【讨论】:

  • 您粘贴了 NPPluginFuncs,而您可能打算粘贴 NPNetscapeFuncs,请注意。对于任何感兴趣的人,他们都在 npapi-sdk 的 npfunctions.h 中
【解决方案2】:

我建议使用某种形式的日志记录而不是消息框;您是否尝试过删除被击中的消息框并查看是否进一步? Chrome 会在进程外启动插件,因此它会期望这些入口点及时完成,否则它可能会杀死插件。

此外,--plugin-startup-dialog 选项在某些情况下可能很有用,这样您就可以确定插件何时启动;此外,如果您想附加调试器并查看是否可以通过这种方式找到更多信息,它可能会很有用。仅供参考。我也会尝试将它加载到 Firefox 中;有时在另一个浏览器中加载插件会为您提供不同的信息。如果它适用于一个而不是另一个,那也可以告诉你一些事情。

【讨论】:

  • 我删除了所有的 MessageBox,但发生了完全相同的事情。我还尝试了 --plugin-startup-dialog,它会弹出一个带有进程 ID 的窗口。不过,我对 mingw 有点陌生,那么我将如何附加调试器?另外,我应该把我的 npplugin.dll 放在哪里以便 Firefox 找到它?我正在使用 manifest.json 让 Chrome 加载它...
  • 我不知道;我使用 Visual Studio 在 Windows 上构建插件,因为它更易于使用。您还可以查看 FireBreath (firebreath.org),因为它使这一切变得容易得多。免责声明:我写了 FireBreath。
  • 稍后我将尝试gdb 尝试看看问题所在。我想了解 NPAPI 和 NPRuntime,这就是我决定不使用 FireBreath 的原因,但如果我不能继续使用它,我会开始使用它。
【解决方案3】:

mm 尝试更改NP_GetEntryPoints()

  pFuncs->newp                = &NPP_New;
  pFuncs->destroy             = &NPP_Destroy;

(...)

  pFuncs->newp                = NPP_New;
  pFuncs->destroy             = NPP_Destroy;

【讨论】:

    猜你喜欢
    • 2019-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多