Simplifying Legacy Integration: Using Call-In Stubs in Uniface 10.4
Integration between modern 4GL environments and traditional C (3GL) code often feels like a high-wire act. You have to manually juggle memory handles, parameter mappings, and execution states. One slip—like a mismatched data type or a forgotten handle release—and your application crashes.
If you are working with Uniface 10.4, there is a better way. Instead of writing verbose, error-prone C code to activate Uniface services, you can use Call-In Stubs. This feature generates clean C wrappers for your 4GL services, handling the heavy lifting automatically.
Here is how to streamline your C-to-Uniface integration.
The Old Way: Manual & Tedious
Let’s say you need to call a simple operation named CALLIN inside a Uniface service CALLINSRV.
Without stubs, you are forced to write about 20 lines of boilerplate code just to fire a single trigger. You have to manually instantiate the environment, service, and operation, and then painstakingly map every parameter.
#include <h3gl.h>
void main (void)
{
UHACT hEnv, hIn, hOp;
long opStat;
/* 1. Manual Lifecycle Management */
uecreate(1, 0, 0, "my.asn", 0, 0, &hEnv);
uinstnew(hEnv, "CALLINSRV", 0, 0, UDEFAULT_COMM_MODE, 0, &hIn, 0);
uinstopr(hIn, "CALLIN", 0, &hOp);
/* 2. The actual call */
uopract(hOp, &opStat, 0);
/* 3. Manual Cleanup (Order matters!) */
uinstdel(hIn, 0);
uedelete(hEnv);
ufreeh(&hOp); ufreeh(&hIn); ufreeh(&hEnv);
}
The Pain Points:
- Verbose: It is hard to see the business logic amidst the infrastructure code.
- Fragile: If you add a parameter to your Uniface service later, you have to rewrite the C code to push/pop that parameter manually.
The New Way: Generating Call-In Stubs
Uniface can examine your compiled service and generate a C "stub" file. This file contains wrapper functions that handle all the Uniface plumbing for you.
Step 1: Compile Your Service
Ensure your Uniface service is compiled and the UAR file is up to date. The generator reads from the compiled descriptor, not the source code.
Step 2: Generate the Stub
Run the following command in your terminal:
ide /sti ServiceName
Uniface creates two files:
-
ui_servicename.h(Header file) -
ui_servicename.c(Source file containing the wrapper logic)
For our CALLINSRV example, this generates functions like ui_callin_callinsrv(), which maps directly to your 4GL operation.
Step 3: Refactored C Code
Now your C code becomes drastically simpler:
#include <h3gl.h>
/* In a real project, link the .obj/.o file instead of including .c */
#include <ui_callinsrv.c>
void main (void)
{
UHACT hEnv;
/* Initialize the environment once */
uecreate(1, 0, 0, "my.asn", 0, 0, &hEnv);
/* The complex logic is now a single function call */
ui_callin_callinsrv();
/* Tear down */
uedelete(hEnv);
ufreeh(&hEnv);
}
⚠️ Common Pitfalls & Best Practices
While stubs make life easier, there are still traps for the unwary.
1. Don't Forget the Lifecycle!
A common misconception is that the stub handles everything. It does not. The stub only manages the Service and Operation handles. You are still responsible for creating the Uniface Environment (uecreate) before calling the stub and destroying it (uedelete) afterward.
Symptom: If you forget uecreate, your program will likely crash with a segmentation fault or return an obscure error code immediately upon calling the stub.
2. Linking vs. Including
In the example above, we #include the .c file for simplicity. In a professional build pipeline:
- Don't:
#include "ui_service.c"in multiple places. This leads to "duplicate symbol" errors during linking. - Do: Compile
ui_service.cseparately into an object file (.oor.obj) and link it to your main application.
3. Stale Signatures
If you update your Uniface service (e.g., add a new parameter) but forget to run ide /sti again, your C code is now calling a ghost.
Risk: The stub will try to map parameters that don't exist or have changed types, leading to runtime corruption that is very hard to debug.
Fix: Make stub generation a standard step in your build pipeline whenever UARs change.
4. Never Edit the Stub Manually
You might be tempted to add a printf inside the generated ui_servicename.c for debugging.
Don't do it. Any time you regenerate the stub, your changes are wiped out. If you need logging, wrap the stub call in your own wrapper function.
Conclusion
Call-In Stubs in Uniface 10.4 turn a complex, 20-line manual integration task into a robust, 3-line function call. By automating the parameter mapping, you not only save time but also eliminate an entire class of "fat-finger" errors in your C/Uniface bridge.
Happy Coding
Top comments (0)