如何在Duktape中创建C ++对象

时间:2018-06-06 06:36:00

标签: javascript c++ duktape

基于http://wiki.duktape.org/HowtoNativeConstructor.html,我可以创建一个c ++类并导出到JavaScript,JavaScript代码也可以创建对象

但是。当我用c ++本机代码创建一个对象时,它无法工作,JavaScript代码无法看到对象

我从Duktape收到错误消息: “TypeError:无法读取属性”

我的代码是:

class Btn
{
public:
  void test()
  {
    printf("%s\r\n", __PRETTY_FUNCTION__);
  }
};

Btn btn;

/* btn.prototype.test */
duk_ret_t btn_test(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);

  duk_push_this(ctx);
  duk_get_prop_string(ctx, -1, "\xff""\xff""Btn");
  Btn *x = static_cast<Btn *>(duk_to_pointer(ctx, -1));
  if (x)
  {
    x->test();
  }
  printf("Btn Addr 0x%08x\r\n", x);
  duk_pop(ctx);

  return 0;
}

duk_ret_t btn_destructor(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);
  return 0;
}

/* btn */
duk_ret_t btn_constructor(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);

  if (!duk_is_constructor_call(ctx))
  {
    return DUK_RET_TYPE_ERROR;
  }

  duk_push_this(ctx);

  printf("Btn Addr 0x%08x\r\n", &btn);
  duk_push_pointer(ctx, &btn);
  duk_put_prop_string(ctx, -2, "\xff""\xff""Btn");

  duk_push_c_function(ctx, btn_destructor, 1);
  duk_set_finalizer(ctx, -2);

  return 0;
}

void btn_init(duk_context *ctx)
{
  duk_push_c_function(ctx, btn_constructor, 0);
  duk_push_object(ctx);
  duk_push_c_function(ctx, btn_test, 0);
  duk_put_prop_string(ctx, -2, "test");
  duk_put_prop_string(ctx, -2, "prototype");
  duk_put_global_string(ctx, "Btn");
}

duk_ret_t getBtn(duk_context *ctx)
{
  printf("%s\r\n", __PRETTY_FUNCTION__);

  int n = duk_get_top(ctx);
  if (n != 1)
  {
    return DUK_EXEC_ERROR;
  }

  // get "MyButton"
  std::string str(duk_to_string(ctx, 0));

  // create Btn object
  duk_get_global_string(ctx, "Btn");
  duk_new(ctx, 0);

  duk_push_object(ctx);

  return DUK_EXEC_SUCCESS;
}

static duk_ret_t duk__print(duk_context *ctx) {
  duk_push_string(ctx, " ");
  duk_insert(ctx, 0);
  duk_join(ctx, duk_get_top(ctx) - 1);
  printf("%s\n", duk_safe_to_string(ctx, -1));
  return 0;
}

int main(int argc, char *argv[]) {

  duk_context *ctx = duk_create_heap_default();

  duk_push_c_function(ctx, duk__print, DUK_VARARGS);
  duk_put_global_string(ctx, "print");

  btn_init(ctx);

  duk_push_global_object(ctx);
  duk_push_c_function(ctx, getBtn, 1);
  duk_put_prop_string(ctx, -2, "getBtn");
  duk_pop(ctx);

  printf("------- Script 1 -------\r\n");
  {
    std::string script1 = "btn = getBtn(\"MyButton\");" \
        "print(btn);" \
        "btn.test()";

    duk_push_string(ctx, script1.c_str());
    if (duk_peval(ctx) != 0)
    {
      printf("eval failed: %s\n", duk_safe_to_string(ctx, -1));
    }

    duk_pop(ctx);
  }

  printf("------- Script 2 -------\r\n");
  {
    std::string script2 = "btn = new Btn();" \
          "print(btn);" \
          "btn.test();";

    duk_push_string(ctx, script2.c_str());
    if (duk_peval(ctx) != 0)
    {
      printf("eval failed: %s\n", duk_safe_to_string(ctx, -1));
    }

    duk_pop(ctx);
  }

  duk_destroy_heap(ctx);

  return 0;
}

输出结果:

------- Script 1 -------
duk_ret_t getBtn(duk_context*)
duk_ret_t btn_constructor(duk_context*)
Btn Addr 0x00476030
duk_ret_t btn_destructor(duk_context*)
undefined
eval failed: TypeError: cannot read property 'test' of undefined
------- Script 2 -------
duk_ret_t btn_constructor(duk_context*)
Btn Addr 0x00476030
[object Object]
duk_ret_t btn_test(duk_context*)
void Btn::test()
Btn Addr 0x00476030
duk_ret_t btn_destructor(duk_context*)

如何在 getBtn (C ++本机代码)函数中创建JavaScript对象,并将对象返回到JavaScript代码?

1 个答案:

答案 0 :(得分:0)

使用duk_new从C ++代码生成JS类的实例。这个调用需要一个构造函数和duk堆栈上的参数。

/* Assume target function is already on stack at func_idx.
 * Equivalent to Ecmascript 'new func("foo", 123)'.
 */
duk_idx_t func_idx = /* ... */;

duk_dup(ctx, func_idx);
duk_push_string(ctx, "foo");
duk_push_int(ctx, 123);
duk_new(ctx, 2);  /* [ ... func "foo" 123 ] -> [ ... res ] */
printf("result is object: %d\n", (int) duk_is_object(ctx, -1));
duk_pop(ctx);