Forums » Programming with the ECS »
Callback's for external dll libraries with Oberon
Added by Runar Tenfjord 11 months ago
I got a partially work wrapper for libui-ng
and got stuck at how to use callbacks with Oberon.
The "hello-world.c":
#include <stdio.h> #include <ui.h> int onClosing(uiWindow *w, void *data) { uiQuit(); return 1; } int main(void) { uiInitOptions o = {0}; const char *err; uiWindow *w; uiLabel *l; err = uiInit(&o); if (err != NULL) { fprintf(stderr, "Error initializing libui-ng: %s\n", err); uiFreeInitError(err); return 1; } // Create a new window w = uiNewWindow("Hello World!", 300, 30, 0); uiWindowOnClosing(w, onClosing, NULL); l = uiNewLabel("Hello, World!"); uiWindowSetChild(w, uiControl(l)); uiControlShow(uiControl(w)); uiMain(); uiUninit(); return 0; }
Partial ported version:
MODULE Test; IN Ext IMPORT UI; PROCEDURE Test(); VAR a : UI.App; w : UI.Window; b : UI.Button; BEGIN UI.InitApp(a); UI.InitWindow(w, "Hello World!", 300, 30, FALSE); UI.InitButton(b, "ClickMe!"); w.SetChild(b); w.Show(); a.Main(); a.Destroy(); END Test; BEGIN Test(); END Test.
Further files attached.
What I was thinking to do was to pass the procedure pointer to the Oberon callback
as the 3rd argument to the callback register function:
uiWindowOnClosing(w, onClosing, NULL);
This will then get passed as the 2nd argument to the callback function:
int onClosing(uiWindow *w, void *data) { uiQuit(); return 1; }
But I was unsure how to design this and if it is possible to do.
Hope this makes sense. Similar problematic to this would
probably surface many places.
Best regards
Runar Tenfjord
Ext.UI.mod (5.92 KB) Ext.UI.mod | |||
ui.cpp (1.52 KB) ui.cpp | |||
winlib.hpp (3.05 KB) winlib.hpp | |||
winui.cpp (1.13 KB) winui.cpp | |||
Makefile (1.25 KB) Makefile |
Replies (7)
RE: Callback's for external dll libraries with Oberon - Added by Florian Negele 11 months ago
Callbacks are not supported at the moment. The predefined system call wrappers only convert from the ECS calling convention to the calling convention of the underlying system, but not the other way round. This is why you cannot register Oberon procedures directly. For each procedure you want to get called by the library, you need to define and register a wrapper function instead which reverses the calling convention before calling the actual procedure. Have a look at the definitions of the system call wrappers of your target runtime environment to get an idea how to accomplish this.
RE: Callback's for external dll libraries with Oberon - Added by Runar Tenfjord 11 months ago
winuishim.asm:
.code _winui_onClosing call dword @uiQuit mov eax, 1 ret
and added the following lines to Ext.UI.mod:
(* Callback shim code *) VAR ^ winui_onClosing ["_winui_onClosing"]: SYSTEM.BYTE; ... (** Initialize Window *) PROCEDURE InitWindow*(VAR w : Window; title- : ARRAY OF CHAR; width, height : INTEGER; hasMenubar : BOOLEAN); VAR ptr : ADDRESS; BEGIN ptr := uiNewWindow(SYSTEM.ADR(title[0]), width, height, INTEGER(hasMenubar)); w.ptr := ptr; uiWindowOnClosing(w.ptr, SYSTEM.ADR(winui_onClosing), 0) END InitWindow; ...
It seems to work.
However I got some random segmentation faults
on the windows platform. The dll was compiled from git trunk as now
official package exists. Not sure why this happens.
I will try on Linux to check if this is related to the windows build.
Just a note: The winlib.hpp has a GPL3 license with runtime exception.
If I place this code on github, that will be then the license of the library code?
RE: Callback's for external dll libraries with Oberon - Added by Florian Negele 11 months ago
Have you tried registering uiQuit directly? Are you compiling for Win32 or Win64? The runtime exception explicitly allows that your code can be of any license.
RE: Callback's for external dll libraries with Oberon - Added by Runar Tenfjord 11 months ago
Sorry for the late reply.
This was built on Win64. I had to compile the library myself as no official
build exists. I believe the crash is related to the version of the Windows SDK
used. I will try later to build the original libui
library and with the older MFC
libraries.
With regards to the callback I was planning to recreate a object orient hierarchy
with the bindings. I have done this earlier with the XDS compiler and I think this
is a natural fit.
XDS repository is at: https://github.com/tenko/XDSStdLib/blob/main/src/UI.ob2
The callbacks use the senderData argument to activate the callback of
the "object".
(** Button click callback *) PROCEDURE (this : Button) OnClicked*(); BEGIN END OnClicked; PROCEDURE ["C"] ButtonOnClicked(sender : UIDll.Control; senderData : UIDll.VOID); VAR this : Button; BEGIN this := SYSTEM.VAL(Button, senderData); this.OnClicked() END ButtonOnClicked;
Then I just "subclass" the Button for a custom action on the callback.
There are examples of this at the bottom of the source file.
I was hoping to get this working with ECS Oberon, but using RECORD
rather thanPOINTER TO RECORD
to avoid the memory allocations.
Not sure this is possible though, but it would be nice to
get this working to have a portable UI library available.
RE: Callback's for external dll libraries with Oberon - Added by Florian Negele 11 months ago
The type descriptor necessary for subclassing is stored differently for records and pointers to records. In this particular case it is probably easier to work with pointers like in your example, as they point to the button as well as the type descriptor.
RE: Callback's for external dll libraries with Oberon - Added by Runar Tenfjord 11 months ago
Thanks for the clarification.
I will try to get this working and publish information when it is usable.
RE: Callback's for external dll libraries with Oberon - Added by Runar Tenfjord 10 months ago
I got the callback working for the Win64 platform by investigating the runtime as you suggested:
.code _winui_onClosing call rdx ; call on 2rd argument mov eax, 1 ret
The crash I experienced was due to some wrong setup from my side on compiling
the libui-ng.dll
. Downloading and setting up Visual Studio correctly is a complete
nightmare and by chance I found a fork which compiled the correct .dll
in the
Github CI setup.
It is just a matter for chewing through the wrapper code to get this working now.