I am trying to use a C API in Swift that requires me to pass a callback to a function using variadic arguments, i.e.:
extern GEOSContextHandle_t GEOS_DLL initGEOS_r(
GEOSMessageHandler notice_function,
GEOSMessageHandler error_function);
where GEOSMessageHandler is defined as:
typedef void (*GEOSMessageHandler)(const char *fmt, ...);
How should I handle this? I tried to implement an Objective-C class with two class methods defined as follows:
#interface HumboldtCallback : NSObject
+(void)noticeCallback:(const char *)args, ... NS_REQUIRES_NIL_TERMINATION;
+(void)errorCallback:(const char *)args, ... NS_REQUIRES_NIL_TERMINATION;
#end
but Swift does not let me access them. If I define the arguments as void* I can access them from Swift:
var GEOS_HANDLE: COpaquePointer {
let noticeCallbackPointer = HumboldtCallback.noticeCallback;
let errorCallbackPointer = HumboldtCallback.errorCallback;
return initGEOS_r(noticeCallbackPointer, errorCallbackPointer)
}
but the compiler still isn't happy:
Cannot invoke 'initGEOS_r' with an argument list of type '((UnsafeMutablePointer<Void>) -> Void, (UnsafeMutablePointer<Void>) -> Void)'
Should I somehow cast the pointer to the callback function before passing it as a parameter to the init function?
You need to write a C function instead of an objective C method. Unfortunately Swift will convert these into Swift Closure. However you can write a function/method in objective C to return your function pointer. This will stop Swift being able to convert the function to a closure. i.e in your objectiveC header:
void myCallback (const char *fmt, ...);
GEOSContextHandle_t getMyCallback ();
then in the class implement getMyCallback like this:
GEOSContextHandle_t getMyCallback () {
return myCallback;
}
and implement your callback function. In Swift you'll end up with:
initGEOS_r(getMyCallback(), ...)
I believe that you can do this with a plain C header and .c file rather than using an object.
Related
I want to create binding to this C function in dart, this C function accepts a function pointer called progress_monitor:
FFI_PLUGIN_EXPORT void* magickSetProgressMonitor(..., const void* progress_monitor,...);
where progress_monitor is a function pointer:
typedef bool(*MagickProgressMonitor)(const char *,const long long,
const long long,void *);
In dart, I tried creating a function pointer like this:
typedef MagickProgressMonitor = bool Function(String text, int offset, int size, List<int>? clientData);
extension _MagickProgressMonitorExtension on MagickProgressMonitor {
/// Creates a native function pointer from this method.
Pointer<Void> toNativeFunctionPointer() {
return Pointer.fromFunction<Bool Function(Pointer<Char>, LongLong, LongLong, Pointer<Void>)>(this, false).cast();
}
}
But I get this error:
The type 'bool Function(String, int, int, List<int>?)' must be a subtype of 'Bool Function(Pointer<Char>, LongLong, LongLong, Pointer<Void>)' for 'fromFunction'.
I have 2 questions:
what types should I use with fromFunction<???> to remove the error?
the last parameter to the C function is a void* pointer which can be anything, right now I am trying to represent it as List<int> in dart and unsigned char array in C, but this doesn't seem correct, is there a way to handle this more correctly?
Update:
I intend to use the above code by exposing an api method by something like this:
void magickSetProgressMonitor(MagickProgressMonitor progressMonitor, [List<int>? clientData]) {
final Pointer<UnsignedChar> clientDataPtr = clientData?.toUnsignedCharArray() ?? nullptr;
final Pointer<Void> progressMonitorPtr = progressMonitor.toNativeFunctionPointer();
Pointer<Void> oldMonitorPtr =
_bindings.magickSetProgressMonitor(...,progressMonitorPtr,...);
...
}
For "void* pointer" you can use Pointer<Void>.
Please see the following code for the appropriate typedefs.
import 'dart:ffi';
import 'package:ffi/ffi.dart';
// void* magickSetProgressMonitor(uint32_t dummy, const void* progress_monitor,...);
// we need a pair of typedefs to describe the signature on both sides
// the two typedefs will look the same if there are just pointers etc
// the differences come in parameters like integers
// this is the C signature
typedef magick_set_progress_monitor = Pointer<Void> Function(
Uint32, // this is just here as an example to show a 32 bit unsigned
Pointer<NativeFunction<magick_progress_monitor>>,
);
// this is the Dart signature
typedef magickSetProgressMonitor = Pointer<Void> Function(
int, // ffi has turned the C uint type to a Dart int
Pointer<NativeFunction<magick_progress_monitor>>,
);
void main() {
final nativeLib = DynamicLibrary.open('mydll');
// lookupFunction is the improved syntax for looking up functions in the lib
// its generics are the C-style signature followed by the Dart-style
// it returns a Function that matches the Dart-style typedef
final mspm = nativeLib
.lookupFunction<magick_set_progress_monitor, magickSetProgressMonitor>(
'magickSetProgressMonitor',
);
// before calling mspm it needs the callback function, so look that up
// this converts the Dart-style function to a pointer to a native function
// matching the C-style typedef
final callbackFunction = Pointer.fromFunction<magick_progress_monitor>(
callback,
true,
);
// and call mspm passing the (dummy, example) int and callback function
final result = mspm(123, callbackFunction);
}
//typedef bool(*MagickProgressMonitor)(const char *,const long long,
// const long long,void *);
// callback functions need a C-style typedef (so that FFI knows the int sizes)
typedef magick_progress_monitor = Bool Function(
Pointer<Utf8>, // the documentation says this is a string, so use Utf8
LongLong,
LongLong,
Pointer<Void>,
);
bool callback(
Pointer<Utf8> t,
int offset,
int extent,
Pointer<Void> client_data,
) {
final text = t.toDartString(); // convert the Pointer<Utf8> to Dart string
// do something here with the values - probably call a Dart function provided by the user
return true;
}
Update following your edit and questions.
You don't have any choice about the callback. Its typedef must match exactly the C typedef that the C code expects to call. You are correct that you shouldn't be exposing Pointer types to your user, so you should keep the callback function in your code, convert the reason string there, then call your user's function with a Dart String.
Finally, it's also clear that this will never work. This is, as its name suggests, a callback function that is called off the main Dart thread by some background process. The C->Dart callback functionality is restricted to callbacks that are made immediately as part of a Dart->C->Dart call.
I'm trying to implement a Python-like function decorator in C using function pointers but I'm getting weird segmentation fault error.
Idea is that we have a decorator function which has inner function wrapper. Decorator then takes some_function as an argument, puts it inside the wrapper along with additional code and returns the wrapper function.
Very simple function decorator in Python:
def decorator(f):
def wrapper():
#do something before
f()
#do something after
return wrapper
def some_func():
print('Hello')
some_func = decorator(some_func)
I know that Python, unlike C, treats functions as first class objects but I'm wondering if the same sort of functionality can be emulated in C by using function pointers.
I tried this
void* do_twice(void (*func)())
{
auto void wrapper()
{
func();
func();
}
return &wrapper;
}
void some_func()
{ printf("Hello\n"); }
int main()
{
void (*fun_ptr)() = &some_func;
fun_ptr = decorator(fun_ptr);
fun_ptr();
return 0;
}
Output
Hello
Segmentation fault
Now here is the funny bit. If I declare a variable inside wrapper like this:
auto void wrapper()
{
int blah=5;
func();
func();
}
Then segmentation fault is fixed. Can someone explain why is this so? Apparently I'm doing something wrong with the pointers and code is very unstable - seemingly unrelated additions to the main function will cause segmentation fault to pop again.
Do you allow me to have an excursion to C++? In this language, there are functor objects, these are kind of structs that can be called like a function:
struct Wrapper
{
/* this is what allows the struct to be called like a function: */
void operator()(/* can define arbitrary parameters here */)
{ /* some implementation */ }
};
In other words, this would allow you to write code like:
Wrapper w; // actually, C++ does more here than C, but that's out of
// scope of this question...
w(); // possible due to the operator() defined above
OK, now let's extend that a bit:
struct Wrapper
{
void(*m_f)(void); /* !!! */
void operator()(void) /* don't want any parameters... */
{
printf("before\n");
m_f();
printf("after\n");
}
};
Don't want to go any deeper, a C++ developer would now deal with accessibility (such that the member m_f can only be used inside the class) and would provide a so-called constructor (for initialising m_f member appropriately). With all that, the final C++ code using the wrapper class might look like:
Wrapper decorate(void(*f)(void))
{
return Wrapper(f); // the fore-mentioned constructor gets called
}
void test(void) { /* do something */ }
void demo(void)
{
Wrapper w = decorate(&test);
w();
}
Why that excursion? Well, have a close look at one specific line:
void(*m_f)(void);
Yes, there is a member variable! Python actually does something similar internally.
The 'problem' with C is that you cannot define your own function call operators. There's only the native one. So the big question is: Where to store the function pointer?
You could have a struct, storing the function pointer (analogously to the C++ solution), and pass that one to your own function emulating the function call operator. Actually, the C++ solution doesn't do anything else either, solely that all this is hidden behind syntactic sugar!
An equivalent C solution might look like this:
struct Wrapper
{
void(*m_f)(void);
};
void executeDecorated(Wrapper w)
{
printf("before\n");
w.m_f();
printf("after\n");
}
void demo(void)
{
Wrapper w = { &someFunction };
executeDecorated(w);
/* do whatever else ... */
executeDecorated(w);
}
This is probably the closest you can get in C (apart from that you might perhaps find better names).
If having a separate struct to store a function pointer brings you sufficient benefit or if you just want to pass the function pointer directly (executeDecorated(&someFunction), assuming the function was adjusted appropriately) is up to you to decide...
I have a very simple function in C and its pointer gets passed into Swift.
void callback() {
NSLog(#"such pointer…");
}
How can it be invoke in Swift using ONLY the pointer? This is NOT about simply invoking it – it works fine when invoked directly. Tried the following and different variations with signature casting, but it always crashes:
let pointer: UnsafePointer<#convention(c)() -> ()> = UnsafePointer(bitPattern: …)
let callback: #convention(c)() -> () = pointer.memory
Swift.print(callback) // (Function)
callback() // Handling crash with signal 11...
Tried defining Callback type with typedef void(*Callback)(); – same thing:
let pointer: UnsafePointer<Callback> = UnsafePointer(bitPattern: …)
let callback: Callback = pointer.memory
Swift.print(callback) // (Function)
callback() // Handling crash with signal 11...
To check that it actually works and points to the right address I have another Objective-C function, which works as expected when invoked from Swift with the callback pointer.
void invokeCallback(uintptr_t callback) {
((void (*)()) callback)(); // such pointer…
}
The same approach as in Swift: How to call a C function loaded from a dylib should work here.
Example for Swift 3 (assuming that funcPtr is a
UnsafeRawPointer containing the function's address):
// Define function type:
typealias callbackFunc = #convention(c) () -> Void
// Convert pointer to function type:
let callback = unsafeBitCast(funcPtr, to: callbackFunc.self)
// Call function:
callback()
Of course the type alias must match the actual function signature,
and the function needs to be a "pure" C function (not an Objective-C
method).
I have the following C function
struct answer* create(struct callbacks *callbacks);
I need to create a struct of function pointers and call this function from Swift
What I have so far is:
func aa(state: CInt, user_data: UnsafeMutablePointer<Void>) {}
func bb(state: CInt, user_data: UnsafeMutablePointer<Void>) {}
struct CallbacksStruct {
let on_aa = aa
let on_bb = bb
}
and I try to call the function like this:
var callbackStruct = CallbacksStruct()
let ans = create(&callbackStruct)
but, without any success
Is it even possible in Swift ?
Yes, it should be possible. In Swift 2, one can send a Swift closure as a parameter to C, when C expects a function pointer. In your case, you have wrapped it in a struct, so an addition of '#convention(c)' to explicitly state that it's C, might help.
see examples here
new-conventionc-in-swift-2-how-can-i-use-it
I am converting a C header file for a video encoder DLL to Delphi Pascal.
I've run into some issues with access violations with the following function and need help resolving this:
h264venc_tt * MC_EXPORT_API h264OutVideoNew(
void * (MC_EXPORT_API * get_rc)(const char* name),
const struct h264_v_settings * set,
int32_t options,
int32_t CPU,
int32_t frame0,
int32_t nframes);
Note: MC_EXPORT_API = cdecl
The get_rc is declared as follows:
// resource functions dispatcher
void * MC_EXPORT_API get_rc(const char* name)
{
if (!strcmp(name, "err_printf"))
return (void*) error_printf;
else if (!strcmp(name, "prg_printf"))
return (void*) progress_printf;
else if (!strcmp(name, "wrn_printf"))
return (void*) warn_printf;
else if (!strcmp(name, "inf_printf"))
return (void*) info_printf;
return NULL;
}
This function returns a pointer to another function that has a Variable Argument list. One of these is declared as this:
void error_printf(const char * fmt, ...)
{
char lst[256];
va_list marker;
va_start(marker,fmt);
vsprintf(lst,fmt,marker);
va_end(marker);
printf("%s\n", lst);
}
I've translated this the function call and the get_rc to this Delphi Pascal code:
PErrorMessageHandler = function (const Name: String): Pointer; cdecl varargs;
function h264OutVideoNew(
get_rc: PErrorMessageHandler;
settings: Ph264_v_settings;
options: int32;
CPU: int32;
frame0: int32;
nFrames: int32
): Pointer; cdecl; external 'mc_enc_avc.dll' index 4;
Unfortunately, I have no idea how to implement the C-style method error_printf shown above.
Can anyone help to point me in the right direction? I am also curious if I have implemented the other functions correctly as I am getting access violations when I try to call the h264OutVideoNew() function.
PS! I've not included the packed record Th264_v_settings/P_h264_v_settings in this post as this is very long and not really the problem.
A C parameter of type char* is a pointer to a null-terminated array of 8 bit characters. In Delphi the equivalent type is PAnsiChar. You cannot use string since that is a managed Delphi type that has no equivalent in C.
In addition, the error function prototype has void return value. You are returning a pointer and that's an error.
The bigger problem that you have is that you cannot readily implement a C style function that receives a variable number of arguments in Delphi. You can declare and call such a function, but you cannot implement one. This means that such a function, with variable arguments, has to be an external function.
Now, you could write your own assembler routine to full off the variable arguments. However, that's not the route I would take. I would write the function in C and then compile it to a .obj file that can be linked into your Delphi program with $LINK.
If you don't actually need to read off the variable arguments, you can ignore them like this:
TErrorMessageHandler = procedure(Name: PAnsiChar); cdecl;
Note that I have made the following changes:
Change the type name to be prefixed with T which is standard.
Corrected the type of the Name parameter.
Changed from function to procedure to match the C declaration.
Removed the varargs which we cannot implement in Delphi and thus ignore the additional parameters.
Then your imported function would look like this:
function h264OutVideoNew(
get_rc: TErrorMessageHandler;
settings: Ph264_v_settings;
options: int32;
CPU: int32;
frame0: int32;
nFrames: int32
): Pointer; cdecl; external 'mc_enc_avc.dll' index 4;
And then you can implement the error callback function like this:
procedure error_printf(Name: PAnsiChar); cdecl;
begin
// do stuff here
end;