Как создать объект C ++ в Duktape - PullRequest
0 голосов
/ 06 июня 2018

На основе 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*)

Как создать объект JavaScript в функции getBtn (собственный код C ++) и вернуть объект вКод JavaScript?

1 Ответ

0 голосов
/ 07 июня 2018

Используйте duk_new , чтобы сгенерировать экземпляр класса JS из кода C ++.Этот вызов ожидает функцию конструктора и аргументы в стеке 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);
...