适用于Chrome的NPAPI插件无法通过NP_Initialize

NPAPI Plugin for Chrome doesn't get past NP_Initialize

本文关键字:NP Initialize Chrome NPAPI 插件 适用于      更新时间:2023-10-16

我一直在尝试为Chrome编写一个使用NPAPI插件的扩展。我使用mingw来编译它。我最初挣扎着让Chrome加载插件,但现在我有一个不同的问题。

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

main.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调用,这样我就可以看到是否调用了正确的函数。当我运行我的测试页面时,这是一个带有<embed>标签的空白页面,我得到一条消息说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"

和I链接到.DLL中:

g++.exe -Wl,--subsystem,windows -o "npplugin.dll" -s -shared main.o resource.o -lcomctl32 -lws2_32 -luxtheme -lgdi32 -lshell32 -lshlwapi

函数表之间的大小根据浏览器和浏览器版本的不同而不同。

根据硬编译库头文件检查大小:

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使用的结构中。

我建议使用某种形式的日志记录而不是消息框;你有没有试过移除被击中的消息框,看看你是否能走得更远?Chrome启动插件的进程,所以它会期望这些入口点及时完成,否则它可能会杀死插件。

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

mm尝试更改NP_GetEntryPoints()

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

(…)

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