473,840 Members | 1,479 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

passing c++ methods as c-callbacks

Hi folks,

after reading several threads on this issue (-> subject) I fear that I
got a problem that cannot easily be solved by the offered workarounds
in an acceptable way, at least not with my limited c & c++ experience.
Maybe some of you can help.

the problem:
I need several instances of a class whose (non-static!) methods should
serve as callbacks for a dll (which can' be manipulated/adapted in any
way). Static use is inacceptable and won't work for my setup because
I'm in desperate need for several independent working instances of the
same class.
The actual problem is the absence of any possibility to pass user data
to the callers of the callbacks (which are some device driver-dlls) so
that I can't use a wrapper to delegate the calls to the correct class
instance.

Is there any chance for a workaround that doesn't touch the dlls in any
way so the same class can be used for each dll? Any help would be
appreciated.

Thanks,
Dirk

Apr 26 '06 #1
9 3350
zh*******@web.d e wrote:
Hi folks,

after reading several threads on this issue (-> subject) I fear that I
got a problem that cannot easily be solved by the offered workarounds
in an acceptable way, at least not with my limited c & c++ experience.
Maybe some of you can help.

the problem:
I need several instances of a class whose (non-static!) methods should
serve as callbacks for a dll (which can' be manipulated/adapted in any
way). Static use is inacceptable and won't work for my setup because
I'm in desperate need for several independent working instances of the
same class.
So, in summary, the DLL has only one function pointer (probably 4
bytes)
yet you require it to distinguish not only functions but also instances

(probably 4+4 bytes). That simply won't fit.
Is there any chance for a workaround that doesn't touch the dlls in any
way so the same class can be used for each dll? Any help would be
appreciated.


If you accept a fixed (but configurable) number of callbacks, define a
template<int N> wrapper, and store the instance pointers and member
pointers in two arrays. wrapper<i> will then retrieve the i'th instance
pointer
and member. While you can decide at runtime what wrapper<i> means,
you can't set more callbecks than the number of instantiated
wrapper<i>s.
(Of course, if you put those in your own DLLs too, you can just open
100.DLL, 200.DLL, 300.DLL to get extra wrapper functions - non
standard)

HTH
Michiel Salters

Apr 26 '06 #2
>> The actual problem is the absence of any possibility to pass user data
to the callers of the callbacks (which are some device driver-dlls) so
that I can't use a wrapper to delegate the calls to the correct class
instance. Is there any chance for a workaround that doesn't touch the dlls in any
way so the same class can be used for each dll? Any help would be
appreciated.


If I understand you correctly, you have multiple device driver dlls
that have callback routines that you must implement and you want to
associate a specific instance of one callback class with each dll?
Based on your description, I'm assuming the callbacks from the device
driver dlls are c-style functions. Also, you are unable pass a void* or
some other type of user data to the device driver that would get
returned in the callback, correct?

In this case, since you cannot pass user data to the dlls that will get
returned in the callback, you will need another way of delegating the
callbacks to C++ classes. Depending on your situation, you may want to
set up a singleton or global callback class that all the c-style
functions will know about and can use to delegate their calls to. Once
the calls are delegated to that singleton object, it would then decide
what specific instance of your final callback class to call based on
some information either known at compile time or at runtime. (You could
also set up your final callback classes as singletons themselves and
have the device driver callbacks call them directly, if there is a
different set of c-style callback for each dll.)

The singleton pattern is often overused, but in a situation like this,
it is definitely a correct choice.

Hope that helps.

--Lyell

Apr 26 '06 #3
First of all thanks a lot for your feedback Michiel and Lyell.

@Lyell:
Unfortunately your approach won't work here because only one of four
callbacks (each device driver controls the same device type and thus
has the same interface and the same four callbacks) contains
information that could help to determine the caller at run or compile
time. No chance to tell where the other callbacks originate from.

@Michiel:
It seems to be that your template approach with a fixed amount of
instances is the only thing that could serve as a solution at the
moment. It's quite frustrating though that one has to sacrifice the
advantage of dynamic scaling.

So again, thanks a lot for your help!

Bye,
Dirk

Apr 26 '06 #4
>> Unfortunately your approach won't work here because only one of four
callbacks (each device driver controls the same device type and thus
has the same interface and the same four callbacks) contains
information that could help to determine the caller at run or compile
time. No chance to tell where the other callbacks originate from.


Maybe you could write an adapter dll for each of your device drivers
and then load your adapter dll instead of loading the device driver dll
directly? There could be a generic adapter dll for any device drivers
you don't handle specifically. You'd then have control over the
callback handling and still have the ability to dynamically scale by
just writing a new adapter dll anytime you want to do something
specific for a particular device driver.

Lyell

Apr 26 '06 #5
zh*******@web.d e wrote:
[snip]
The actual problem is the absence of any possibility to pass user data
to the callers of the callbacks (which are some device driver-dlls) so
that I can't use a wrapper to delegate the calls to the correct class
instance.


So, you write a configurable thunk table. Like so: You create several
functions that can be passed to the dlls as callbacks. Each of these
then looks up in a global table where to call to get the real
functionality.
Each function looks for a particular line in the table. And you fill in
that line dynamically according to what you want things to be doing.

So, the thunk table might include a pointer to an instance of a class
that does the job you want. And that instance might be derived from
a base class that has a member fcn to call. And you just derive a
class for each type of functionality you want.

So it only adds one layer of indirection. You create an instance of the
handling class and put the pointer in the table. Then you pass the
appropriate function pointer to the dll. With a little work you can
even
have the table collect the function pointers, and keep track of what
dlls they have been assigned to, and what type of class they have
had attached for doing the work. Or whatever else book keeping is
required to assist. You can make this exactly as fancy as required.

Wrap the entire thing in a singleton and you are cooking.
Socks

Apr 26 '06 #6
zh*******@web.d e wrote:
The actual problem is the absence of any possibility to pass user data
to the callers of the callbacks (which are some device driver-dlls) so
that I can't use a wrapper to delegate the calls to the correct class
instance.

Is there any chance for a workaround that doesn't touch the dlls in any
way so the same class can be used for each dll? Any help would be
appreciated.


Yes. In the Lisp programming language, there is something known as a
dynamically-scoped variable. A dynamically scoped variable has a
global top-level binding, but it can be overriden locally. For instance
if X is dynamically scoped then (LET ((X 3)) ...) binds X to a new
storage location over the scope of the let block. Any function you call
from there will see X as being bound to that storage location which has
that value. X can be changed of course. When the LET block terminates,
the binding is restored to the previous binding (no matter how that
block terminates: normal exit or non-local exit via throw or whatever).

Under multithreaded implementations , these re-bindings affect only the
calling thread, so dynamic variables effectively become an abstraction
for thread-local storage.

They are useful for passing down context information through functions,
or layers of functions, which don't have the arguments for doing so.

Because of the saving-restoring discipline of the local rebinding,
dynamic variables are more disciplined than simple global variables.
Sure you rebind the variable to create an effect in some other module,
but then the old binding is restored when you are done.

You can give yourself the same thing in C++. In single-threaded code,
it can be done portably. Simply use a global variable for the context,
and use RAII to save and restore its value.

I wrote a pair of templates to do this. The template DynamicVar<T> is
used to define a dynamic variable. It's actually a class object which
contains a T, but also contains a T * pointer to the latest binding. If
that pointer is null, then the embedded T is the binding of that
variable. If that pointer is not null, then it points to the current
location of T.

The other template, RebindVar<T>, is used to temporarily bind a given
variable to a new location. Like DynamicVar<T>, it contains an embedded
T. It takes an initial value through the constructor, and a reference
to the DynamicVar<T>. It saves the original T * pointer within the
DynamicVar<T> and then chages it to point to its own embedded instance
of T. In the destructor, the pointer in the global is restored to its
previous value.

Both DynamicVar and RebindVar have the assignment and conversion
operators to transparently operate on the embedded T. RebindVar
bypasses the pointer, of course! If you have the RebindVar object in
lexical scope, then the dynamic lookup thorugh the pointer isn't
required.

So your code would look something like this:

// file scope or static class variable
DynamicVar<MyCl ass *> d_contextPointe r;

void CallLibrary(MyC lass *obj)
{
// Set up local re-binding of d_contextPointe r

RebindVar<MyCla ss *> contextPointer( obj);
LibraryFunction (&MyClass::Stat icCallback);

// scope ends, old binding is now restored
}

void MyClass::Static Callback()
{
// retrieve context from temporary binding
d_contextPointe r->NonStaticCallb ack();
}

If you need threading support, the DynamicVar and RebindVar templates
can hide the calls to the thread-specific storage API functions on your
platform or whatever, so that the constructor and destructor function
of RebindVar<> is visible only in the context of the calling thread.

As you can see, the scheme supports recursion nicely. The callback
itself can override the dynamic variable in a nested fashion and call
into library, resulting in another callback which can use a different
object.

Greenspun's Tenth Rule of Programming:

"Any sufficiently complicated C or Fortran program contains an ad-hoc,
informally-specified bug-ridden slow implementation of half of Common
Lisp."

Apr 26 '06 #7
>
Is there any chance for a workaround that doesn't touch the dlls in any
way so the same class can be used for each dll? Any help would be
appreciate d.


The solution isn't pretty, but I believe you want what is referred to as
a 'thunk'.

The short explanation of it is to allocate and initialize a structure
with machine language opcodes and use the address of the structure as
your function pointer.

For example if you have the following definition:

class MyObject {
public:
int myMethod (int value);
};

and have an allocated instance of this object named myObject, and need
to create a callback that accomplishes the following:

int Callback1 (int value)
{
return myObject->myMethod (value);
}

Then you need to create a thunk structure like so:

struct Thunk1
{
unsigned u1; // set to opcodes for __asm mov ecx, pThis
unsigned u2; // set to opcodes for __asm push value
unsigned u3; // set to opcodes for __asm call myMethod
};

And then use the address of Thunk1 as the callback.

Obviously this sort of thing is highly unportable, requiring you to
compile a similar function for the target machine then look at the
opcodes emitted to determine how to initialize your structure, but since
we are talking about device drivers I am guessing you have some freedom
in this area.

I may have mistated a few things here, but hopefully the concept is
clear enough. I apologize for the gross hackery :)
Apr 26 '06 #8
>

So, you write a configurable thunk table. Like so: You create several
functions that can be passed to the dlls as callbacks. Each of these
then looks up in a global table where to call to get the real
functionality.
Each function looks for a particular line in the table. And you fill in
that line dynamically according to what you want things to be doing.


I want to add that I like this method a lot better than my suggestion,
but it does have the difference of requiring you to know an upper limit
to the number of objects you may need; which is very likely since we are
talking about a device driver.
Apr 26 '06 #9
Things get quite interesting and fascinating here. I think I need some
time to find my way through all your detailed concepts and
descriptions. Thanks a lot for your help and participation.

Bye,
Dirk

Apr 26 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
2355
by: Anthony Baxter | last post by:
To go along with the 2.4a3 release, here's an updated version of the decorator PEP. It describes the state of decorators as they are in 2.4a3. PEP: 318 Title: Decorators for Functions and Methods Version: $Revision: 1.34 $ Last-Modified: $Date: 2004/09/03 09:32:50 $ Author: Kevin D. Smith, Jim Jewett, Skip Montanaro, Anthony Baxter
6
1906
by: Bryan Martin | last post by:
I have a object that is created in a seperate domain which needs to be passed back to the parent class. Because this object is created in a seperate domain if I try to pass the object back to the parent class (different domain) I receive an error about "File Not Found". I know the object is created successfully and the objects method can be called after loading the object however upon passing it back to the calling class it exploades. I...
7
8676
by: Tron Thomas | last post by:
Under the right compiler the following code: class Base { public: virtual void Method(int){} }; class Derived: public Base {
3
4763
by: Simon Harvey | last post by:
Hi, In my application I get lots of different sorts of information from databases. As such, a lot of information is stored in DataSets and DataTable objects. Up until now, I have been passing around chunks of data in DataTables/DataSets, simply because that was the format that they were in when the data was taken from the database. Now, I know this maybe a pretty silly question with a standard "it depends" answer, but I'm going to...
25
5069
by: Stuart Hilditch | last post by:
Hi all, I am hoping that someone with some experience developing nTier apps can give me some advice here. I am writing an nTier web app that began with a Data Access Layer (DAL), Business Logic Layer (BLL) and User Interface Layer (UIL). The problem I found with this was circular referencing...
5
1656
by: blue | last post by:
We often get connection pooling errors saying that there are no available connections in the pool. I think the problem is that we are passing around open readers all over the place. I am planning on changing this in our code and I expect this to fix our problem. We have our connection pooling set to the default number of connections open. We probably have about 3-7 users concurrently using our web site. So, the problem isn't that we...
2
1483
by: Colin McGuire | last post by:
Hi everyone. This is a question and something new and neat I have found. But to recap - a few months back I learnt about overloading, how to create the same method with a different signature. With some help from people in this newsgroup I created a new class with overloaded constructors that accepted one or two parameters. The code is below. Private Class test Public Sub New(ByVal param1 As Integer)
4
2102
by: shade73 | last post by:
Hey all. I currently have two seperate namespaces and I'm trying to pass a connection around to them. I want to use the same connection & leave it open for 6 methods & then close it. However, all 6 of those methods use that same connection. So my solution was to pass the SqlConnection as a parameter in each method. This works, but it goes super slow. When I changed it back and put the methods all back in the same namespace & didnt...
9
3810
by: Greger | last post by:
Hi, I am building an architecture that passes my custom objects to and from webservices. (Our internal architecture requires me to use webservices to any suggestion to use other remoting techniques are not feasible) The question is; Given that I have a Person object with a private set for id. What is the recommended approac in passing that object to the web service
46
10473
by: ahmed.maryam | last post by:
Hi all, I have 2 C# applications that I need to pass data between. Specifically XML information such as a document or node name. How can I do that? Thanks in advance! ~ Maryam
0
9856
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9698
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10916
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10299
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9436
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
7022
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5684
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4495
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
3136
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.