I am trying to write a wrapper on top of winapi. I want to wrap functions that accept pointers for callback functions.
As an example, consider this:
// The unsafe callback type the FFI function accepts
type UnsafeCallback = unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32;
// The safe callback type my function should accept
type SafeCallback = fn(exception_info: &ConvertedExceptionInfo) -> u32;
The functions that will be used:
// The function exposed by winapi
unsafe extern "system" fn SetExceptionHandler(handler: UnsafeCallback);
// The function I want to expose in my library
fn SetExceptionHandler(handler: SafeCallback);
I want to create a wrapping function that looks like this:
unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32 {
let result = panic::catch_unwind(|| {
// Convert ExceptionInfo into ConvertedExceptionInfo. I know this is undefined behavior, but its only here
// to demonstrate program flow
let converted_exception_info: ConvertedExceptionInfo = (*exception_info).into();
// Call the corresponding safe function (as to how we get the function pointer here, that's
// the whole question)
return safe_callback(&converted_exception_info);
});
return match result {
Ok(val) => val,
Err(_) => _
};
}
I can think of two possibilities to create this wrapping function:
Creating a wrapping function at runtime
Create a closure or similar construct inside the safe
SetExceptionHandler method.
I have no idea how to get the closure across the FFI boundary.
Exposing a conversion macro and generating the function at compile time
Edit the SetExceptionHandler function to accept the UnsafeCallback
type.
Then I could create a macro that generates the wrapping function at compile time and expose this macro to the user.
I would have to expose unsafe extern parameters again, so it is not
how I would prefer to do it.
I have no idea how to structure such a macro or if this is even possible.
Is my first idea possible and feasible? If so, how could this be done?
If not, is writing a macro like the second idea possible and feasible? If so, how could this be done?
Based on
How do I create a Rust callback function to pass to a FFI function?
How do I convert a Rust closure to a C-style callback?
How do I pass a closure through raw pointers as an argument to a C function?
I get the impression that my first idea is probably not possible with the exception of something called trampolining.
Is trampolining possible in safe Rust and in this situation?
After much searching, i have found a blog post that explains a nice solution for the problem of wrapping callbacks. Article here
Related
In boost.asio example of asynchronous UDP server we can find next code:
void start_receive()
{
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
boost::bind(&udp_server::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
..........
void handle_receive(const boost::system::error_code& error,
std::size_t /*bytes_transferred*/)
According to specification of basic_datagram_socket::async_receive_from function, its prototype is
template<
typename MutableBufferSequence,
typename ReadToken = DEFAULT>
DEDUCED async_receive_from(
const MutableBufferSequence & buffers,
endpoint_type & sender_endpoint,
ReadToken && token = DEFAULT);
when token may be a function with prototype
void handler(
const boost::system::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes received.
);
I do not understand two things (at least)
How bind work here? It accept handle_receive pointer, udp_server object (what for?) and two placeholders. How does it turn to function that is called at the end of asynchronous call and get context varibles?
How does handle_receive function access a recv_buffer_ which is an argument of async_receive_from function but not of handle_receive?
Bind returns a bound function object. There's extensive documentation about how it works and why you'd use it:
https://www.boost.org/doc/libs/1_77_0/libs/bind/doc/html/bind.html
also see https://en.cppreference.com/w/cpp/utility/functional/bind
udp_server object (what for?)
(Non-static) member functions take an implicit this pointer argument to the class instance (object). So a 2-argument non-static member function void X::foo(int,int) consttakes 3 arguments:X const*, int, int`.
How does handle_receive function access a recv_buffer_ which is an argument of async_receive_from function but not of handle_receive?
recv_buffer_ is a data member of the same class (udp_server), so in handle_receive it is implicitly accessing it as this->recv_buffer_. This is very elementary C++, so I recommend maybe reading a good introduction or book if this is new for you.
When receiving data on wire and sending it to upper applications, normally, in C style, we have a struct for example with a void*:
struct SData{
//... len, size, version, msg type, ...
void* payload;
}
Later in the code, after error checking and mallocating, ..., we can do something as:
if(msgType == type1){
struct SType1* ptr = (struct SType1*) SData->payload;
}
In C++, an attempt to use unique_ptr fails in the following snippet:
struct SData{
// .. len, size, version, msg type, ...
std::unique_ptr<void> payload;
}
But as you know, this will cause:
error: static assertion failed: can't delete pointer to incomplete type
Is there a way to use smart pointers to handle this?
One solution I found is here:
Should std::unique_ptr<void> be permitted
Which requires creating a custom deleter:
void HandleDeleter(HANDLE h)
{
if (h) CloseHandle(h);
}
using
UniHandle = unique_ptr<void, function<void(HANDLE)>>;
This will require significantly more additional code (compared to the simple unsafe C Style), since for each type of payload there has to be some logic added.
This will require significantly more additional code (compared to the simple unsafe C Style), since for each type of payload there has to be some logic added.
The additional complexity is only calling the added destructors. You could use a function pointer instead of std::function since no closure state should ever be used.
If you don't want destructors, but only to add RAII to the C idiom, then use a custom deleter which simply does operator delete or std::free.
I have a legacy template function I'm trying to call that has a slew of specializations for function pointers with different numbers of arguments. I'm writing a new template function of my own that take some arbitrary kind of non-capturing lambda and needs to pass it to the other library. If I do this directly, then the template resolution fails. If however I explicitly cast it to be related function pointer type, things work.
The problem then is how to make my template code get that function pointer type from the lambda's type or force the explicit conversion without explicitly referencing the type.
Just use unary-plus to convert a lambda to a function pointer, as in:
auto* f = +[]{ std::cout << "Hello, world!\n"; }; // f is of type void (*)()
I did something along the lines of creating a struct for phoenix::function
struct to_upper_impl
{
template <typename T1>
struct result { typedef std::string type; };
std::string operator()(const std::string & s) const
{
return boost::algorithm::to_upper_copy(s);
}
};
boost::phoenix::function<to_upper_impl> to_upper;
and then using that function in my semantic actions.
I was wondering if I can use some kind of a one-liner in my semantic code instead (of creating the struct)?
Thanks!
As far as I know - no.Till now there is no other ways to pass other callable type as a parameter to phoenix::function. While I experimenting with it I try to use C++11 lambdas and failed when try to call phoenix::function wiht some parameters because of the Boost.ResultOf protocol. You can see explanation in this thread:
Can't call a lazy lambda function with parameters via boost::phoenix::function.Using boost( BLL) and phoenix lambdas is not much shortener and lighter. So by now there is no good alternatives.
I am currently writing a program in C++0x which I am fairly new to.
I am setting up callbacks between objects and using lambda to match the types (like boost::bind() does in ways)
If I call a function in the asio library like:
socket_.async_read_some(buffer(&(pBuf->front()), szBuffer),
[=](const boost::system::error_code &error, size_t byTrans) {
this->doneRead(callBack, pBuf, error, byTrans); });
This compiles fine, and runs as expected, 'doneRead' is called back from 'async_read_some'
so I have a similar call back in my own code:
client->asyncRead([=](string msg){this->newMsg(msg); });
This takes just a string, and asyncReads prototype is as follows
void ClientConnection::asyncRead(void(*callBack)(string))
But I get this compile error:
Server.cpp: In member function ‘void
Server::clientAccepted(std::shared_ptr,
const boost::system::error_code&)’:
Server.cpp:31:3: error: no matching
function for call to
‘ClientConnection::asyncRead(Server::clientAccepted(std::shared_ptr,
const
boost::system::error_code&)::)’
Server.cpp:31:3: note: candidate is:
ClientConnection.h:16:9: note: void
ClientConnection::asyncRead(void
(*)(std::string))
ClientConnection.h:16:9: note: no
known conversion for argument 1 from
‘Server::clientAccepted(std::shared_ptr,
const
boost::system::error_code&)::’
to ‘void (*)(std::string)’
How can this issue be resolved?
Your lambda captures this implicitly. A lambda that captures things cannot convert to a raw function pointer.
So you need to write asyncRead so it accepts the lambda function object directly, instead of letting it convert to a function pointer
template<typename CallbackType>
void ClientConnection::asyncRead(CallbackType callback);
Alternatively, if you don't want to write this as a template, you can use a polymorphic function object wrapper
void ClientConnection::asyncRead(std::function<void(string)> callBack);
I would also consider changing the callback's interface so it accepts the string by const reference (unless all the callback implementations inherently want to modify or save/move the passed string internally, which seem unlikely in your case).