DEV Community

Cover image for C/C++ Experience with WebForms Core from Elanat
Elanat Framework
Elanat Framework

Posted on

C/C++ Experience with WebForms Core from Elanat

WebAssembly makes it possible to bring languages such as C and C++ into web applications without rewriting their core logic in JavaScript.

In this article, I explore using C and C++ with WebForms Core, a server-side UI manipulation technology from Elanat. The goal is not to use C or C++ to manipulate the browser DOM directly. Instead, the C or C++ code uses the WebForms Core API to generate WebForms Core responses, which are then executed in the browser by WebFormsJS.

The resulting architecture is:

C / C++
   ↓
Emscripten
   ↓
WebAssembly
   ↓
WebForms Core
   ↓
WebFormsJS
   ↓
HTML DOM
Enter fullscreen mode Exit fullscreen mode

This approach allows C and C++ code to participate in the WebForms Core Commander architecture while keeping DOM execution on the client side.

WebForms Core and WebAssembly

WebForms Core separates UI command generation from UI execution.

The application generates WebForms Core commands, while WebFormsJS executes those commands against the HTML DOM.

A WebAssembly module can therefore act as a WebForms Core Commander.

Instead of calling JavaScript APIs such as:

document.getElementById("result").textContent = "Hello";
Enter fullscreen mode Exit fullscreen mode

the C or C++ code can generate a WebForms Core response such as a command that changes the text of an HTML element.

The browser then receives and executes that response through WebFormsJS.

This distinction is important because the WebAssembly module does not need to know how the DOM is implemented or manipulate it directly.

WebForms Core Implementations

WebForms Core provides implementations for multiple programming languages.

The installation method depends on the language.

C in GitHub

WebForms Core C implementation

The C implementation is provided as a single WebForms.h file.

Get the file directly from the c directory and include it in the project:

#include "WebForms.h"
Enter fullscreen mode Exit fullscreen mode

C++ in GitHub

WebForms Core C++ implementation

The C++ implementation is also provided as a single WebForms.h file.

Get the file directly from the cpp directory and include it in the project:

#include "WebForms.h"
Enter fullscreen mode Exit fullscreen mode

The WebForms.h File

For C and C++, WebForms.h is the main WebForms Core interface.

It provides the functions and classes required to create WebForms Core responses.

The important point is that WebForms.h is not a browser-side DOM library. It does not provide functions such as document.querySelector() or element.innerHTML.

Instead, it provides the WebForms Core programming interface for generating commands.

For example, the C API can create a WebForms instance:

WebForms* form = webforms_create();
Enter fullscreen mode Exit fullscreen mode

Commands can then be added to the response:

webforms_set_text(form, inputPlace, text);
webforms_set_background_color(form, "-", backgroundColor);
webforms_set_font_size(form, "-", fontSize);
Enter fullscreen mode Exit fullscreen mode

Finally, the generated response is obtained:

char* response = webforms_response(form);
Enter fullscreen mode Exit fullscreen mode

After the response has been generated, the WebForms instance can be cleaned up:

webforms_clean(form);
webforms_free(form);
Enter fullscreen mode Exit fullscreen mode

The C++ API provides the same WebForms Core concept through a native C++ class:

WebForms form;

form.SetText(inputPlace, text);
form.SetBackgroundColor("-", backgroundColor);
form.SetFontSize("-", fontSize);

string response = form.Response();
Enter fullscreen mode Exit fullscreen mode

Therefore, the role of WebForms.h can be summarized as:

C / C++
   ↓
WebForms.h
   ↓
WebForms Core Response
   ↓
WebFormsJS
   ↓
HTML DOM
Enter fullscreen mode Exit fullscreen mode

C with WebForms Core

The first experiment uses C.

The following example exports three functions:

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#include <emscripten/emscripten.h>

#include "WebForms.h"

EMSCRIPTEN_KEEPALIVE
int add(int a, int b)
{
    return a + b;
}

EMSCRIPTEN_KEEPALIVE
const char* set_data(
    const char* inputPlace,
    const char* text,
    const char* backgroundColor,
    const char* fontSize)
{
    static char* response = NULL;

    WebForms* form = webforms_create();

    if (!form)
        return NULL;

    webforms_set_text(form, inputPlace, text);
    webforms_set_background_color(form, "-", backgroundColor);
    webforms_set_font_size(form, "-", fontSize);

    if (response)
        free(response);

    response = webforms_response(form);

    webforms_clean(form);
    webforms_free(form);

    return response;
}

EMSCRIPTEN_KEEPALIVE
const char* get_html()
{
    return "<marquee>Tag From Wasm!</marquee>";
}
Enter fullscreen mode Exit fullscreen mode

The add function is a simple numeric function.

The set_data function demonstrates the more interesting WebForms Core scenario. It receives data from JavaScript, creates a WebForms Core instance, generates several UI commands, and returns the resulting WebForms Core response.

The get_html function demonstrates that a WebAssembly method can also return HTML when that is appropriate for the application.

Compiling the C Code

Emscripten can compile the C source into WebAssembly:

upstream\emscripten\emcc.exe main.c -o main.html -sEXPORTED_RUNTIME_METHODS=ccall
Enter fullscreen mode Exit fullscreen mode

The compilation produces files such as:

main.html
main.js
main.wasm
Enter fullscreen mode Exit fullscreen mode

The important file for the WebAssembly runtime is main.wasm, while the generated JavaScript provides the Emscripten runtime and JavaScript interface.

Calling C WebAssembly from WebForms Core

WebForms Core provides WebAssembly method invocation through its WASM integration.

For example, a backend application can define a WebForms Core action that calls a WebAssembly method:

Fetch.WasmMethod(
    WasmLanguage.CPP,
    "/wasm/main.wasm",
    "set_data",
    InputPlace.Root,
    name,
    backgroundColor,
    fontSize
);
Enter fullscreen mode Exit fullscreen mode

The returned WebForms Core response can then be executed by WebFormsJS.

The WebAssembly function itself does not need to know about the browser DOM.

The complete flow is:

Browser
   ↓
WebForms Core request
   ↓
Backend
   ↓
C WebAssembly
   ↓
WebForms Core response
   ↓
WebFormsJS
   ↓
HTML DOM
Enter fullscreen mode Exit fullscreen mode

Setting a WebAssembly Event

A WebAssembly method can also be associated with a WebForms Core event.

For example:

SetWasmEvent(
    WasmLanguage.CPP,
    "btn_SetBodyValue",
    "click",
    "/wasm/main.wasm",
    "set_data"
);
Enter fullscreen mode Exit fullscreen mode

This allows the WebAssembly function to participate in the WebForms Core event model rather than requiring custom JavaScript event handlers.

C++ with WebForms Core

The C++ implementation uses the same WebForms Core concept but exposes a native C++ interface.

#include <string>

#include <emscripten/emscripten.h>

#include "WebForms.h"

using namespace std;
using namespace WebFormsCore;

extern "C"
{
    EMSCRIPTEN_KEEPALIVE
    int Add(int a, int b)
    {
        return a + b;
    }

    EMSCRIPTEN_KEEPALIVE
    const char* SetData(
        const char* inputPlace,
        const char* text,
        const char* backgroundColor,
        const char* fontSize)
    {
        static std::string response;

        WebForms form;

        form.SetText(inputPlace, text);
        form.SetBackgroundColor("-", backgroundColor);
        form.SetFontSize("-", fontSize);

        response = form.Response();

        return response.c_str();
    }

    EMSCRIPTEN_KEEPALIVE
    const char* GetHtml()
    {
        return "<marquee>Tag From Wasm!</marquee>";
    }
}
Enter fullscreen mode Exit fullscreen mode

The C++ version uses the WebForms class directly:

WebForms form;
Enter fullscreen mode Exit fullscreen mode

Commands are then added through class methods:

form.SetText(inputPlace, text);
form.SetBackgroundColor("-", backgroundColor);
form.SetFontSize("-", fontSize);
Enter fullscreen mode Exit fullscreen mode

The final response is generated with:

response = form.Response();
Enter fullscreen mode Exit fullscreen mode

The response is stored in a static std::string because returning c_str() from a temporary or local string would leave an invalid pointer after the function returns.

Compiling C++

The C++ source can be compiled with Emscripten using em++:

upstream\emscripten\em++.exe main.cpp -o main.html -sEXPORTED_RUNTIME_METHODS=ccall
Enter fullscreen mode Exit fullscreen mode

As with the C version, Emscripten produces the JavaScript and WebAssembly files required by the browser.

C and C++ API Comparison

The two implementations expose the same WebForms Core concept using language-specific APIs.

Operation C C++
Create webforms_create() WebForms form;
Set text webforms_set_text() SetText()
Set background webforms_set_background_color() SetBackgroundColor()
Set font size webforms_set_font_size() SetFontSize()
Generate response webforms_response() Response()
Cleanup webforms_clean() / webforms_free() Automatic object lifetime

The difference is primarily the programming interface.

The generated WebForms Core response follows the same architecture in both cases.

Automatic WebAssembly Method Arguments

One useful part of the WebForms Core WebAssembly integration is that method arguments can be passed from JavaScript based on their JavaScript types.

For example:

Add(10, 20)
Enter fullscreen mode Exit fullscreen mode

passes numeric arguments, while:

SetData("~form", "Hello", "red", "18px")
Enter fullscreen mode Exit fullscreen mode

passes string arguments.

The C/C++ Emscripten loader can determine the argument types from the JavaScript values:

const argTypes = args.map(arg =>
    typeof arg === "string" ? "string" : "number"
);
Enter fullscreen mode Exit fullscreen mode

For the current C/C++ WebAssembly methods, this allows calls to be made without manually writing a separate signature for every method.

WebAssembly as a WebForms Core Commander

This experiment demonstrates an important aspect of the WebForms Core architecture.

WebAssembly does not have to be treated as a replacement for JavaScript DOM manipulation.

Instead, it can become another environment for generating WebForms Core commands.

The architecture can therefore be represented as:

                 WebForms Core
                       │
             ┌─────────┴─────────┐
             ↓                   ↓
        Server Code          WebAssembly
                                 │
                         ┌───────┴───────┐
                         ↓               ↓
                         C              C++
                         │               │
                         └───────┬───────┘
                                 ↓
                         WebForms Response
                                 ↓
                            WebFormsJS
                                 ↓
                              HTML DOM
Enter fullscreen mode Exit fullscreen mode

The key point is that C and C++ do not need to directly control the browser DOM.

They generate WebForms Core commands, and WebFormsJS performs the client-side execution.

C with Mongoose

The same C WebForms Core implementation can also be used in a native C web server.

For example, Mongoose can receive an HTTP request, execute C code, generate a WebForms Core response, and return it to the browser.

The architecture becomes:

Browser
   ↓
HTTP
   ↓
Mongoose
   ↓
C Application
   ↓
WebForms Core
   ↓
WebForms Core Response
   ↓
WebFormsJS
   ↓
HTML DOM
Enter fullscreen mode Exit fullscreen mode

This demonstrates that WebForms.h is not tied specifically to WebAssembly.

The same C WebForms Core implementation can be used in native C applications and in C WebAssembly applications.

Conclusion

Using C and C++ with WebForms Core provides another way to bring native-language code into web UI workflows.

WebForms Core Technology in C/C++

The important part of this experiment is not simply compiling C or C++ into WebAssembly. The more interesting part is combining WebAssembly with the WebForms Core Commander architecture.

C and C++ generate WebForms Core responses through WebForms.h.

Emscripten compiles the code to WebAssembly.

WebForms Core provides the communication and command model.

WebFormsJS executes those commands in the browser.

The resulting architecture remains:

C / C++
   ↓
Emscripten
   ↓
WebAssembly
   ↓
WebForms Core
   ↓
WebFormsJS
   ↓
HTML DOM
Enter fullscreen mode Exit fullscreen mode

This makes C and C++ another practical environment for building WebForms Core functionality while keeping the browser-side execution model consistent.

Related links

On Elanat:

On GitHub:

Top comments (0)