Clone wiki

cef / UsingTheCAPI

This Wiki page provides information on how to use the CEF C API in a client application.

Note to Editors: Changes made to this Wiki page without prior approval via the CEF Forum or Issue Tracker may be lost or reverted.


Introduction

The CEF C API is a C-based interface exported by the libcef DLL. The cef_capi.h header file which defines the interface is automatically generated by the CEF translator tool and mirrors the CEF C++ API structure.

An example client application using the C API is available here: https://github.com/CzarekTomczak/cefcapi

Reference Counting

Understanding reference counting is likely the most difficult part of working with the CEF C API. The reference counting concept used by CEF is very similar to the concept used by COM. Here are some general rules to follow to make your usage of reference counting as painless as possible.

1. Do not increment/decrement the reference count when passing a structure to its own member function:

struct->call_func(struct,...); // no reference counting change on 'struct'

2. Increment the reference count on a struct before passing it as an argument to another struct:

// Should have already added a reference to 'some_other_struct'
struct->call_func(...,some_other_struct,...);

3. Decrement the reference count on a struct when receiving it as an argument from somewhere else after you're done using it:

void my_func(...,some_other_struct,...)
{
  // remove a reference from 'some_other_struct' after you're done using it
}

4. Add a reference to a handler before passing it into, for instance, cef_create_browser(). The API will remove a reference from the handler when the handler is no longer needed.

5. Use an atomic reference counting implementation because add_ref and release may be called from multiple threads. The WinAPI InterlockedIncrement() and InterlockedDecrement() functions can be used for this purpose.

6. The handler should delete itself when the reference count reaches zero in the release() callback function that you've assigned for your structure.

// custom data structure that extends cef_handler_t
typedef struct _my_handler_t {
  cef_handler_t handler;  // cef_handler_t member comes first
  // custom members here, including the reference count variable
} my_handler_t;

// allocate the custom data structure (already initialized to zero)
my_handler_t* my_handler = (my_handler_t*)calloc(1, sizeof(my_handler_t));
// set the size member of cef_base_t appropriately
my_handler->handler.base.size = sizeof(cef_handler_t);
// assign the release callback function (and the other callback functions)
my_handler->handler.base = my_release;
...

// release callback function implementation for my_handler_t
int CEF_CALLBACK my_release(struct _cef_base_t* base) {
  // this cast works because cef_base_t is the first member of
  // cef_handler_t and cef_handler_t is the first member of my_handler_t
  my_handler_t* my_handler = (my_handler_t*)base;

  // decrement the reference count (stored as a custom member of my_handler_t)
  // free the my_handler_t structure when the reference count reaches zero
  if(reference_count_is_zero)
    free(my_handler);
}

7. Reverse any additional references that your code adds to a struct (for instance, if you keep a reference to the cef_browser_t pointer in your handler implementation). The last opportunity to release references is in cef_handler_t::handle_before_window_closed().

8. You'll know you're handling the reference counting correctly when nothing crashes and you no longer hit the DebugObjCt asserts on shutdown.

Updated