PNaCl - 如何将消息从index.html发布到PNaCl?

时间:2015-01-21 03:51:43

标签: javascript html google-nativeclient ppapi

我运行nacl_sdk(pepper_39)的hello_nacl示例,一切都很好。 但我尝试在index.html上添加一些东西来发布消息到PNaCl,它不起作用并得到像这样的“NativeClient:NaCl模块崩溃”的错误。 这是我的index.html,任何人都可以告诉我出了什么问题?

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<script type="text/javascript">
var HelloTutorialModule = null;
function pageDidLoad() {
    appendStatus('Page loaded');
    HelloTutorialModule = document.getElementById('nacl_module');
    HelloTutorialModule.postMessage('hello from HTML!!');
}
function appendStatus(opt_message) {
    var statusField = document.getElementById('statusField');
    if (statusField) {
        var newElt = document.createElement("opt_message");
        newElt.innerHTML = "<br>" + opt_message;
        statusField.appendChild(newElt);
    }
}
function handleMessage(message_event) {
    appendStatus(message_event.data);
}
</script>
</head>
<body>
<div id="listener">
<script type="text/javascript">
    var listener = document.getElementById('listener');
    listener.addEventListener('message', handleMessage, true);
    listener.addEventListener('load', pageDidLoad, true);
</script>
<h2>NaCl Module</h2>
<embed name="nacl_module"
    id="nacl_module"
    style="border-style: solid;"
    width=200
    height=200
    src="newlib/hello_nacl.nmf"
    type="application/x-nacl"/>
</div>

谢谢。

以下代码是我的hello_nacl.c

/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/

// This project demonstrates how to migrate a Windows desktop app to Native
// Client, running first as a Win32 application (define STEP1), then as a PPAPI
// plugin (define STEP2 through STEP6), and finally as a Native Client module.

// Start with STEP1 defined and the defines for STEP2 through STEP6 commented
// out.  For each step in the process, un-comment the next     #define, leaving the
// previous ones on.  Ready, set, port!

// *** SELECT THE WIN32 PLATFORM AND RUN WITH     #define STEP1 ONLY ***

//    #define STEP1
// Launches the original Windows desktop application, Hello World, which runs
// as WinMain.  STEP1 encloses Windows-specific functions that are used with
// the WIN32 and PPAPI platforms.  These will be removed when the full PPAPI
// port is finished (STEP6)

// *** SELECT THE PPAPI PLATFORM ***

#define STEP2
// What Changed: The platform launches Chrome, which will then load a Native
// Client Module. STEP2 encloses the Native Client module APIs needed to link
// any app to the browser. The module does nothing except report
// starting/ending the function Instance_DidCreate. The Windows app does not
// run because it is not being called.

#define STEP3
// What changed: Replace WinMain with WndProc, and call it from
// Instance_DidCreate, launching hello_nacl in its own window.
// Since WndProc spins in its message loop, the call to Instance_DidCreate
// never returns.
// Close the hello_nacl window and the module initialization will finish.

#define STEP4
// What changed: In WndProc replace the message loop with a callback function.
// Now the app window and the Native Client module are running concurrently.

#define STEP5
// What changed: Instance_DidCreate calls InitInstanceInBrowserWindow rather
// than InitInstanceInPCWindow.
// The InitInstanceInBrowserWindow uses postMessage to place text (now "Hello,
// Native Client") in the web page instead of opening and writing to a window.

#define STEP6
// What changed: All the Windows code is def'd out, to prove we are
// PPAPI-compliant.  The functional code that is running is the same as STEP5.

// *** SELECT THE NACL64 PLATFORM AND RUN ***

// What changed: The code is the same as STEP6, but you are using the SDK
// toolchain to compile it into a nexe.  The module is now running as a real
// Native Client executable in a NaCl sandbox, with nacl-gdb attached.

// *** RUN YOUR MODULE IN THE WILD ***
// You can run your nexe outside of Visual Studio, directly from Chrome by
// following these steps:
// - Build STEP6 and verify the file
//   <project directory>/NaCl64/newlib/Debug/hello_nacl_64.nexe exists
// - Copy the folder <project directory> into your NaCl SDK's example
//   directory.
// - Go to the NaCl SDK directory and launch the httpd.py server.
// - Launch Chrome, go to about:flags and enable the Native Client flag and
//   relaunch Chrome
// - Point Chrome at http:    //localhost:5103/hello_nacl


#ifdef STEP6
// remove Windows-dependent code.
#undef STEP1
#undef STEP3
#undef STEP4
#define NULL 0
#else
// includes for Windows APIs.
#include <windows.h>
#include <stdlib.h>
#include <tchar.h>
#endif


#ifdef STEP2
// includes for PPAPI
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb.h"
#include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppb_messaging.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/c/ppb_core.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppp_messaging.h"
#include <string.h>
#include <stdio.h>
#include <time.h>


// Native Client APIs
static PPB_Messaging* ppb_messaging_interface = NULL;
static PPB_Var* ppb_var_interface = NULL;
static PPB_Core* ppb_core_interface = NULL;
PP_Instance myInstance;

int InitInstanceInPCWindow();
void InitInstanceInBrowserWindow();

#endif


#ifdef STEP4
// Implements message handling in a callback function.
void HelloWorldCallbackFun(void* user_data, int32_t result);
struct PP_CompletionCallback HelloWorldCallback = {
    HelloWorldCallbackFun, NULL };
    void HelloWorldCallbackFun(void* user_data, int32_t result) {
        MSG uMsg;
        if (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&uMsg);
            DispatchMessage(&uMsg);
        }
        ppb_core_interface->CallOnMainThread(100, HelloWorldCallback, 0);
    }
#endif

#ifdef STEP2
// The basic framework needed for all Native Client Modules.  Handles creation
// of the module instance and initial handshake with the browser.
/**
 * Creates new string PP_Var from C string. Useful utility for
 * message-handling.
 */
static struct PP_Var CStrToVar(const char* str) { if (ppb_var_interface !=
NULL) { return ppb_var_interface->VarFromUtf8(str, strlen(str)); } return
PP_MakeUndefined(); }


void InitInstanceInBrowserWindow() {
    // Pass the text to the browser page, there is no separate app window
    // anymore.  The text is added as a new element to the page, it does not
    // appear in the module's embed view.
    ppb_messaging_interface->PostMessage(myInstance, CStrToVar("Hello, Native Client! XDDXDXD"));  
}

/**
 * Called when the NaCl module is instantiated on the web page.
 */
static PP_Bool Instance_DidCreate(PP_Instance instance,
                              uint32_t argc,
                              const char* argn[],
                              const char* argv[]) {
myInstance = instance;
ppb_messaging_interface->PostMessage(instance,
                                   CStrToVar("Start Instance_DidCreate"));
#ifdef STEP5
  // Will be included in STEP5 and STEP6
  // Uses messaging to relay text to the module's view on the web page
InitInstanceInBrowserWindow();
#else
#ifdef STEP3
  // Will be included in STEP3 and STEP4 only
  // Uses WndProc to place text in a window separate from the browser.
InitInstanceInPCWindow();
#endif
#endif
ppb_messaging_interface->PostMessage(instance,
                                   CStrToVar("End Instance_DidCreate"));
return PP_TRUE;
}

/**
 * Called when the NaCl module is destroyed.
 */
static void Instance_DidDestroy(PP_Instance instance) {
ppb_messaging_interface->PostMessage(instance,
                                   CStrToVar("Instance_DidDestroy"));
}

/**
 * Called when the position, the size, or the clip rect of the element in the
 * browser that corresponds to this NaCl module has changed.
*/
static void Instance_DidChangeView(PP_Instance instance,
                               PP_Resource view_resource) {
ppb_messaging_interface->PostMessage(instance,
                                   CStrToVar("Instance_DidChangeView"));
}

/**
* Notification that the given NaCl module has gained or lost focus.
*/
static void Instance_DidChangeFocus(PP_Instance instance,
                                PP_Bool has_focus) {
ppb_messaging_interface->PostMessage(instance,
                                   CStrToVar("Instance_DidChangeFocus"));
}

/**
 * Handler that gets called after a full-frame module is instantiated based on
 * registered MIME types.  This function is not called on NaCl modules.  This
 * function is essentially a place-holder for the required function pointer in
 * the PPP_Instance structure.
  */
static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
                                       PP_Resource url_loader) {
/* NaCl modules do not need to handle the document load function. */
ppb_messaging_interface->PostMessage(instance,
                                   CStrToVar("Instance_HandleDocumentLoad...."));
return PP_FALSE;
}

static void HandleMessage(PP_Instance instance, struct PP_Var message){         
            //ppb_messaging_interface->PostMessage(instance, CStrToVar("Get Message From HTML"));
}

/**
* Entry points for the module.
* Initialize needed interfaces: PPB_Core, PPB_Messaging and PPB_Var.
*/
PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
                                   PPB_GetInterface get_browser) {

ppb_messaging_interface = (PPB_Messaging*)
                        get_browser(PPB_MESSAGING_INTERFACE);
ppb_var_interface = (PPB_Var*)get_browser(PPB_VAR_INTERFACE);
ppb_core_interface = (PPB_Core*)get_browser(PPB_CORE_INTERFACE);
return PP_OK;
}

/**
 * Returns an interface pointer for the interface of the given name, or NULL
 * if the interface is not supported.
  */
PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {

if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
static PPP_Instance instance_interface = {
  &Instance_DidCreate,
  &Instance_DidDestroy,
  &Instance_DidChangeView,
  &Instance_DidChangeFocus,
  &Instance_HandleDocumentLoad,
      //&HandleMessage,
};
return &instance_interface;
}
return NULL;
}


/**
 * Called before the plugin module is unloaded.
 */
PP_EXPORT void PPP_ShutdownModule() {
}
#endif

// **** Application Code ****

#ifdef STEP1
// Desktop Windows Hello World app. Native Client agnostic.

static TCHAR szWindowClass[] = _T("win32app");
static TCHAR szTitle[] = _T("hello_nacl");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// WinMain
int WINAPI WinMain(HINSTANCE hInstance,
               HINSTANCE hPrevInstance,
               LPSTR lpCmdLine,
               int nCmdShow) {
WNDCLASSEX wcex;
HWND hWnd;
MSG msg;

wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style          = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc    = WndProc;
wcex.cbClsExtra     = 0;
wcex.cbWndExtra     = 0;
wcex.hInstance      = hInstance;
wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName   = NULL;
wcex.lpszClassName  = szWindowClass;
wcex.hIconSm        = LoadIcon(wcex.hInstance,
                             MAKEINTRESOURCE(IDI_APPLICATION));

if (!RegisterClassEx(&wcex)) {
MessageBox(NULL,
           _T("Call to RegisterClassEx failed!"),
           _T("hello_nacl"),
           0);

return 1;
}

hInst = hInstance;

hWnd = CreateWindow(
  szWindowClass,
  szTitle,
  WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, CW_USEDEFAULT,
  500, 100,
  NULL,
  NULL,
  hInstance,
  NULL);

if (!hWnd) {
MessageBox(NULL,
           _T("Call to CreateWindow failed!"),
           _T("hello_nacl"),
           0);

return 1;
  }

  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);

  // Main message loop:

  while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
  }

  return (int) msg.wParam;
}

// WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
                     WPARAM wParam, LPARAM lParam) {
  PAINTSTRUCT ps;
  HDC hdc;
  TCHAR greeting[] = _T("Hello, World!");

  switch (message) {
    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
      EndPaint(hWnd, &ps);
      break;
    case WM_DESTROY:
  PostQuitMessage(0);
  break;
    default:
  return DefWindowProc(hWnd, message, wParam, lParam);
  break;
  }

  return 0;
}
#endif

#ifdef STEP3
// Replace WinMain with InitInstanceInPCWindow so the Native Client Module can
// launch the original application.  Note the inclusion of a message-handling
// loop. STEP4 will replace the loop with a callback.
HINSTANCE g_hInstance = NULL;
HWND g_hWnd = NULL;

int InitInstanceInPCWindow() {
  WNDCLASSEX winClass; MSG        uMsg;

  memset(&uMsg,0,sizeof(uMsg));

  winClass.lpszClassName = _T("MY_WINDOWS_CLASS");
  winClass.cbSize        = sizeof(WNDCLASSEX);
  winClass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  winClass.lpfnWndProc   = WndProc;
  winClass.hInstance     = g_hInstance;
  winClass.hIcon         = NULL;
  winClass.hIconSm       =  NULL;
  winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  winClass.lpszMenuName  = NULL;
  winClass.cbClsExtra    = 0;
  winClass.cbWndExtra    = 0;

  if (!RegisterClassEx(&winClass))
    return E_FAIL;

g_hWnd = CreateWindowEx(
  0, _T("MY_WINDOWS_CLASS"),
  _T("hello_nacl"), WS_OVERLAPPEDWINDOW,
  0, 0, 640, 480, NULL, NULL, g_hInstance, NULL);

  if (g_hWnd == NULL)
    return E_FAIL;

  ShowWindow(g_hWnd, 1);

  UpdateWindow(g_hWnd);

    #ifdef STEP4
  // Skip the message loop, schedule a callback instead to periodically check
  // for messages. Here we schedule at 100ms intervals.
  ppb_core_interface->CallOnMainThread(100, HelloWorldCallback, 0);
  return 0;
    #else
  // Main message loop, Windows style.
  while(uMsg.message != WM_QUIT) {
    if (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) {
      TranslateMessage( &uMsg );
      DispatchMessage( &uMsg );
    }
  }
  return uMsg.wParam;
    #endif

}
    #endif

1 个答案:

答案 0 :(得分:1)

此示例中有许多额外的代码,但问题出在此处:

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {

if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
  static PPP_Instance instance_interface = {
    &Instance_DidCreate,
    &Instance_DidDestroy,
    &Instance_DidChangeView,
    &Instance_DidChangeFocus,
    &Instance_HandleDocumentLoad,
      //&HandleMessage,
  };
  return &instance_interface;
  }
return NULL;
}

当您向模块发布消息时,此函数被称为请求PPP_Messaging;1.0接口。此代码不处理这种情况,因此它会向调用者返回NULL,然后崩溃。

这不是理想的行为(它应该会产生错误),但这并不奇怪。

要修复此错误,您需要在请求PPP_MESSAGING_INTERFACE时返回界面:

  ...
  } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
    static PPP_Messaging messaging_interface = {
        &HandleMessage,
    };
    return &messaging_interface;
  }