Calling a C Function From JS

Let's say that we have a page with the following HTML/JS on it:

    <button onclick="OnButtonClick();">Click Me</button>
    <div id="result"></div>

Our goal is to call a C function bound to OnButtonClick() when a user clicks the button and display a message in <div id="result"></div>.

Let's dive in.

About JSObjectMakeFunctionWithCallback()

JavaScriptCore provides a method to bind static C callbacks to JavaScript via JSObjectMakeFunctionWithCallback.

You can use this method to create JS Function Objects that will call a C function when invoked.

Function Signature

We can only bind static C functions with a certain function signature (typedef'd in JavaScriptCore as JSObjectCallAsFunctionCallback).


See the API declaration for JSObjectCallAsFunctionCallback here for a deeper description of each of the callback parameters.

JSValueRef MyCallback(JSContextRef ctx, JSObjectRef function,
  JSObjectRef thisObject, size_t argumentCount, 
  const JSValueRef arguments[], JSValueRef* exception) {
  // Handle JavaScript arguments in our C callback here...
  // Optionally return a value back to JavaScript
  return JSValueMakeNull(ctx);

Using JSObjectMakeFunctionWithCallback()

We will create a function object named OnButtonClick using our C callback and bind it to the global object to expose it to the page.


See the API declaration for JSObjectMakeFunctionWithCallback() here.

// This callback will be bound to 'OnButtonClick()' on the page.
JSValueRef OnButtonClick(JSContextRef ctx, JSObjectRef function,
  JSObjectRef thisObject, size_t argumentCount, 
  const JSValueRef arguments[], JSValueRef* exception) {

  const char* str = 
    "document.getElementById('result').innerText = 'Ultralight rocks!'";
  // Create our string of JavaScript
  JSStringRef script = JSStringCreateWithUTF8CString(str);

  // Execute it with JSEvaluateScript, ignoring other parameters for now
  JSEvaluateScript(ctx, script, 0, 0, 0, 0);

  // Release our string (we only Release what we Create)

  return JSValueMakeNull(ctx);

// Use LoadListener::OnDOMReady to wait for the DOM to load.
void MyApp::OnDOMReady(View* caller,
                       uint64_t frame_id,
                       bool is_main_frame,
                       const String& url) {

  // Acquire the JS execution context for the current page.
  // This call will lock the execution context for the current
  // thread as long as the Ref<> is alive.
  Ref<JSContext> context = caller->LockJSContext();
  // Get the underlying JSContextRef for use with the
  // JavaScriptCore C API.
  JSContextRef ctx = context.get();
  // Create a JavaScript String containing the name of our callback.
  JSStringRef name = JSStringCreateWithUTF8CString("OnButtonClick");

  // Create a garbage-collected JavaScript function that is bound to our
  // native C callback 'OnButtonClick()'.
  JSObjectRef func = JSObjectMakeFunctionWithCallback(ctx, name, 
  // Get the global JavaScript object (aka 'window')
  JSObjectRef globalObj = JSContextGetGlobalObject(ctx);

  // Store our function in the page's global JavaScript object so that it
  // accessible from the page as 'OnButtonClick()'.
  JSObjectSetProperty(ctx, globalObj, name, func, 0, 0);

  // Release the JavaScript String we created earlier.