C++ V8 object context - c++

I'm trying to perform a callback in C++ (where C++ is running as part of a node.js program). The callback is to a 3rd party library, where it will call the callback when it has data to pass.
The problem I appear to be having is with variable types:
static void sensorEventCallback(const char *protocol, const char *model,
int id, int dataType, const char *value, int timestamp,
int callbackId, void *context)
{
//process the data here
}
Handle<Value> sensorEvents( const Arguments& args ) {
HandleScope scope;
...
callbackId = tdRegisterSensorEvent(
reinterpret_cast<TDSensorEvent>(&telldus_v8::sensorEventCallback),
Context::GetCurrent()->Global());
}
The error I'm getting:
error: cannot convert ‘v8::Local<v8::Object>’ to ‘void*’ for argument
‘2’ to ‘int tdRegisterSensorEvent(void ()(const char, const char*,
int, int, const char*, int, int, void*), void*)’
It appears to be struggling with argument 2 which is the context. Any thoughts on how I can convert the V8 object to one that tdRegisterSensorEvent will accept?

Snooping a bit, that GetCurrent appears to be defined in the V8 header to return a Local<Context>:
v8.h on GitHub, location of GetCurrent() in the Context object definition
This Local<T> is a template for a "lightweight, stack allocated handle", derived from a base class Handle<T>:
v8.h on GitHub, definition of Local
v8.h on GitHub, definition of Handle
So seems you've got a Context pointer whose lifetime is being managed by something called a HandleScope. If you pull the context pointer out and save it to use in a callback later, it may or may not still exist at the time the call is made.
If you know all the callbacks will happen before it's freed by the handle scope, you can try getting the pointer out using the dereference operator overload and passing it:
v8.h on GitHub, T* Handle::operator*()
But you may not have this guarantee.

As n.m. says I would guess the address of the context object should be passed. You can then cast that back in your callback
void telldus_v8::sensorEventCallback(const char *protocol, const char *model,
int id, int dataType, const char *value, int timestamp,
int callbackId, void *context)
{
v8::Local<v8::Object>* ctx_ptr = static_cast<v8::Local<v8::Object>*>(context);
//process the data here
}
v8::Local<v8::Object> ctx = Context::GetCurrent()->Global();
callbackId = tdRegisterSensorEvent(
reinterpret_cast<TDSensorEvent>(&telldus_v8::sensorEventCallback),
&ctx);

Related

How to assign functions to a function pointer?

I am coding a Gameboy Emulator, and for the CPU's instructions I use this struct here (in cpp.hpp) to store info about them. The map is used to access all this information through a key equal to its personal opcode:
struct instruction {
std::string name; //name of the instruction
int cycles; //clock cycles required to be executed
int paramNum; //number of params accepted
void* function; //code to be executed
};
class Cpu {
private:
std::map<unsigned char, instruction> instrMap;
void Cpu::fillInstructions(void);
instruction addInstruction(std::string, int, int, void*);
public:
void add_A_n(unsigned char);
}
Then in the cpu.cpp I have for example one of the function I want to cast to a function pointer in order to be assigned to the field of the struct instruction. So I have this code:
void Cpu::add_A_n(unsigned char n) {
//body
}
void Cpu::addInstructions(std::string name, int cycles, int paramNum, void* function) {
instruction i = {name, cycles, paramNum, function};
return i;
}
void Cpu::fillInstructions() {
instrMap[0x80] = Cpu::addInstruction("ADD A, n", 4, 0, (void*)&Cpu::add_A_n);
}
The goal is to fetch the opcode from the memory, then to use this opcode to retrieve from the map the information about the relative instruction, and finally to execute its function by using a switch case to select the right one:
((void (*)(void))instrMap[0x80].function)(); //for 0 params
((void (*)(unsigned char))instrMap[0x90].function)((unsigned char)operand); //for 1 param
My goal is to cast the all the functions, even the ones who requires some parameters, to the one in the struct.
The respective function it is correctly executed, but a warning is raised:
warning: converting from 'void (Cpu::)()' to 'void' [-Wpmf-conversions]
instrMap[0x80] = Cpu::addInstruction("ADD A, n", 4, 0, (void*)&Cpu::add_A_n);
How can I solve it and why does it occur? Thanks
&Cpu::add_A_n returns a pointer to a member function, which is very different from an ordinary function pointer, and the two can't be mixed. The weirdness around pointer to member functions is to account for the fact that non-static member functions all require a this instance in order to call the function.
In your case, if a function like add_A_n really doesn't depend on this, just make it static, or a non-member function:
class Cpu {
...
static add_A_n(unsigned char);
};
This way, it no longer needs a this to be called, and &Cpu::add_A_n becomes an ordinary function pointer.

Trying to do DetourAttach but cannot convert my lua function's datatype to LPVOID

So this is how my function actually looks like
DetourAttach(&(LPVOID&)lua_tolstring, (PBYTE)tostring);
lua_tolstring is const char* and LPVOID gives me this error.
typedef void* LPVOID
invalid type conversion
How can i make this work?
You don't have the right semantics for DetourAttach. The first argument is a pointer-to-pointer-to-function, which should be initialized to the original function being hooked. The second argument is a pointer-to-function containing your hook function.
See This blog for examples.
So you can't just pass the function. You have to initialize a variable, e.g.:
// Declaration of LUA API function in header
const char*lua_tostring (lua_State *L, int index);
// Your hook function must have this signature to match
const char*my_tostring (lua_State *L, int index);
// Your variable
const char* (*Real_lua_tostring)(lua_State *L, int index) = lua_tostring;
// Make the call
DetourAttach(&(LPVOID&)Real_lua_tolstring, (PVOID)my_tostring);

Error in return a function pointer in C++ without typedef

I'm trying to return a pointer to function without the use of typedef, but the compiler (gcc) is emitting a strange error, as if I could not do that kind of setting.
Remarks: With the use of typedef code works.
code:
void catch_and_return(void (*pf)(char*, char*, int&), char *name_one, char* name_two, int& number)(char*, char *, int&)
{
pf(name_one, name_two, number);
return pf;
}
Error:
'catch_and_return' declared as function returning a function
Can you explain to me why the compiler does not let me do this? Thank you!
Declare your function as the following:
void (*catch_and_return(void (*pf)(char*, char*, int&), char *name_one, char* name_two, int& number))(char*, char *, int&)
{
pf(name_one, name_two, number);
return pf;
}
The syntax for functions that returns functions is:
returned-function-return-type (* function-name (parameter-list) ) (function-to-return-parameter-list)
Note: This declarations can be cumbersome to understand at first sight, use typedef whenever is possible

stl map const_iterator and g++ error

I'm trying to port some windows"s MFC class to linux because I have to port a windows software to linux.
here is the code I need to port
165: SMapCI it = _s$.find("nchairs");
166: if (it==_s$.end()) return 10;
167: int n = strtoul(it->second.text.GetString(), NULL, 10);
and _s$ and SMapCI are defined like this
typedef std::map<CString, STablemapSymbol> SMap;
SMap _s$;
typedef SMap::const_iterator SMapCI;
So, here is my CString class
class CString {
protected:
std::string str;
public:
CString(const char *_cstr) { str = _cstr;; };
bool operator<(char *_cstr) const { return str < _cstr;};
const char *GetString() { return str.c_str();};
};
And When I build my code, I get following error:
CTablemap/CTablemap.h:167:54: error: passing ‘const CString’ as ‘this’ argument of ‘const char* const CString::GetString()’ discards qualifiers [-fpermissive]
I don't understand this error.
g++ documentation say that
passing 'const OBJECT' as 'this' argument of 'FUNCTION' discards qualifiers
*Message found in GCC version 4.5.1
*you're returning an address
*you're attempting to access a container element with a const_iterator using a member function that has no non-const versions. The non-const function does not guarantee it will not alter the data
but ... my GetString function is defined as "const char *", so I have the keyword const ...
So I don't get it ... any help will be more than welcome
note: I'm using my own CString class instead of directly changing it with std::string because the code I want to port is too huge, and I want to do the minimum modification on it. (and some function defined in CString are not defined in std::string)
thanks in advance for any help !!
Your function signature should be
const char *GetString() const
Notice the last const.
Right now, you're saying, "I'm returning a const char pointer from a non-const CString instance". This is fine, but what you're being asked to do is define a function that can be used on a const CString instance - and that's what the last const (after the function parameter list) does, specify that that function can be called on a const CString.
You may want both versions of that function, but in particular, you need it here because the const_iterator exposes its contents as const objects, regardless of what they are inside the container itself.
The prototype of GetString should be:
const char *GetString() const;
The first const means that the caller cannot modify the returned value. The second const means that this method can be called for a const CString.
On the other hand, I would also change the operator< and use:
bool operator<(const char *_cstr)

Casting void *user_data to object

how do I cast void *something to an object in standard C++?
Specifically I want want to cast void *userdata
to std::map<String, void*>
Is this possible? I am trying:
//void *user_data is a parameter of this function (callback)
std::map <String, void*> user_data_n; //this line is ok
user_data_n = static_cast<std::map<String, void *>>(*user_data); //I get the errors here.
ERRORs:
Spurious '>>' user '>' to terminate a template argument list
Expected '>' before '(' token
'void *' is not a pointer-to-object type
or is there a better way to carry information about the caller object and some other parameters I can pass to void *user_data?
UPDATE:
Ass suggested by #aaa carp I changed >> to > > and the first two errors were solved. The last is strange, Why do I get that kind of message when casting it here and not when putting that object when setting the callback?
std::map<String, void*> user_data_h;
user_data_h["Object"] = this; //this is a MainController object
user_data_h["h"] = h; //h was defined as int *h
createTrackbar("trackbar_H", winName, h, 255, trackbar_handler, &user_data_h);
where createTrackbar is defined as:
int createTrackbar( const string& trackbarname, const string& winname,
int* value, int count, TrackbarCallback onChange, void* userdata);
UPDATE2:
doing this solved my problem but following the same approach, why I still get error when trying to cast objects contained in my map object?
void trackbar_handler(int value, void *user_data){
std::map <String, void*> *user_data_map;
user_data_map = reinterpret_cast<std::map<String, void *> *>(user_data); //WORKED!! ;)
MainController *controller; //the same class type I put using "this" above
controller = reinterpret_cast<MainController *>( user_data_map["Object"]); //ERROR here
int *var = reinterpret_cast<int*> (user_data_map["h"]); //ERROR also here
>> should be > >
and you do not want to dereference void pointer, instead cast void pointer to desired pointer type and then dereference
#casa has already provided you with answer to second problem
When you're casting from a void *, your result will be a pointer too. So the map declaration should be:
std::map <String, void*> *user_data_n;
Second, you should use reinterpret_cast for such (potentially dangerous) casts:
user_data_n = reinterpret_cast<std::map<String, void *> *>(user_data);
Update:
As others suggested, you could simply use a static_cast as well.
Why do I get that kind of message when casting it here and not when putting that object when setting the callback?
Any pointer can be implicitly converted to void *, but when converting it back to a pointer of some specific type, you need an explicit cast.
why I still get error when trying to cast objects contained in my map object?
As already mentioned in the comments, you need to dereference the pointer before using the map object. You might want to define a reference instead to make things easier:
std::map <String, void*> &user_data_map =
*(static_cast<std::map<String, void *> *>(user_data));
An noted, the >> in that line to close your template should be > > (with a space).
Also, if user_data is a void pointer, you cannot dereference it. You could cast the pointer to another pointer type with reinterpret_cast:
std::map <String, void*> *user_data_n_ptr; //note this is a pointer to a map.
user_data_n_ptr = reinterpret_cast<std::map<String, void *> *>(user_data);
This will cast the void pointer to a std::map .
You should be careful with this. void pointers shouldn't typically be thrown around in c++. There may be a better way to do what you want and avoid void * all together.
I suppose this is for serving a C callback? It might be better to have a specialized struct which keeps all those values using the exact types. That way you'd be down to one cast for the whole thing. Something like this:
struct callback_user_data {
my_class* that;
int number;
callback_user_data(my_class* p, int i) : that(p), number(i) {}
};
// the callback
void my_callback(void* user_data)
{
callback_user_data* cbud = static_cast<callback_user_data*>(user_data);
somehow_use(cbud->that, cbud->number);
}
//call the function, passing our user data
callback_user_data cbud(this, 42);
some_function_taking_our_callback(&my_callback, &cbud);
Note that usually I have this seen (and used) this so that not a special type is passed, but only this, which has all the necessary data anyway:
// the callback
void my_callback(void* user_data)
{
my_class* that = static_cast<my_class*>(user_data);
that->f();
std::cout << that->number << '\n';
}
//call the function, passing our user data
some_function_taking_our_callback(&my_callback, this);