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
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";
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"
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"
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();
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);
Finally, the generated response is obtained:
char* response = webforms_response(form);
After the response has been generated, the WebForms instance can be cleaned up:
webforms_clean(form);
webforms_free(form);
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();
Therefore, the role of WebForms.h can be summarized as:
C / C++
↓
WebForms.h
↓
WebForms Core Response
↓
WebFormsJS
↓
HTML DOM
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>";
}
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
The compilation produces files such as:
main.html
main.js
main.wasm
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
);
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
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"
);
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>";
}
}
The C++ version uses the WebForms class directly:
WebForms form;
Commands are then added through class methods:
form.SetText(inputPlace, text);
form.SetBackgroundColor("-", backgroundColor);
form.SetFontSize("-", fontSize);
The final response is generated with:
response = form.Response();
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
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)
passes numeric arguments, while:
SetData("~form", "Hello", "red", "18px")
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"
);
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
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
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.
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
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)