e.g.
CExisting::doSomething(blah..)
gets remapped to my COverrideExisting::doSomething(blah..)
I keep the original vtable entry, but how do I call it if need be ?
at the moment I swap the entries back, then call this->doSomething(blah..)
I know how to call a normal function pointer, but with a class function I
need
to add the this pointer into the call stack which I'm not sure how to do
many thanks for any suggestions
cheers
Geoff
A brave fellow you are, rewriting v-tables.
> e.g.
> CExisting::doSomething(blah..)
> gets remapped to my COverrideExisting::doSomething(blah..)
>
> I keep the original vtable entry, but how do I call it
> if need be ? at the moment I swap the entries back, then
> call this->doSomething(blah..) I know how to call a normal
> function pointer, but with a class function I need to add
> the this pointer into the call stack which I'm not sure how
> to do
First, a few, perhaps unwelcome caveats.
1. If you need to ask this, you probably should
stick to C++ and not be rewriting v-tables.
2. I have never seen v-table manipulation done
outside of a compiler that solved a problem not
better solved within the language constraints.
So, I am skeptical that what you are doing is
a good idea, necessary, efficient or prudent.
3. Whatever you do in that realm is going to
be non-portable and may break as the compiler
evolves, even on the same platform. And it
is likely to fail when multiple inheritance
enters the picture.
> many thanks for any suggestions
Now, with that out of the way, I have a couple
of suggestions.
1. Use the compiler's -Fa option to see how
members are called by compiler generated code.
(And if you cannot read assembler, I am duty-
bound to repeat caveat #1.) You will discover
that the this pointer is actually passed in a
register rather than the call stack. So, you
will be writing some assember to help perform
that call. (So you had better know assembler.)
2. Be sure, for your call helper, that you
accommodate the various ways that parameters
of varying type and number are passed, at
least for the range of variation that can be
expected for the methods whose classes you
are dorking in this manner.
3. If suggestions #1 and #2 seem daunting,
either learn enough assembler that it stops
being daunting, or give up v-table rewriting.
> cheers
> Geoff
Have fun. (I hope it's just fun.)
--
-Larry Brasfield
(address munged)
By switching the function pointers back then calling this->DoSomething()
I may run the risk of missing some calls if they're in another thread.
I was rather hoping that someone may had done this before and could offer
their example of what was needed that I may change to suit my call.
I'm more than happy to do the work/research behind this if you have any urls
that may help ?
cheers
Geoff
"Larry Brasfield" <larry_brasf...@hotmail.com> wrote in message
news:MPG.1720258bb...@msnews.microsoft.com...
He scarcely could do this. VC keeps vtables in const
memory.
> > e.g.
> > CExisting::doSomething(blah..)
> > gets remapped to my COverrideExisting::doSomething(blah..)
> >
> > I keep the original vtable entry, but how do I call it
> > if need be ? at the moment I swap the entries back, then
> > call this->doSomething(blah..) I know how to call a normal
> > function pointer, but with a class function I need to add
> > the this pointer into the call stack which I'm not sure how
> > to do
>
> First, a few, perhaps unwelcome caveats.
>
> 1. If you need to ask this, you probably should
> stick to C++ and not be rewriting v-tables.
>
> 2. I have never seen v-table manipulation done
> outside of a compiler that solved a problem not
> better solved within the language constraints.
There is one such problem that you can't solve with
C++.
If you have a COM object with two interfaces that
you need to count separately the problem is solved
immediately in C by setting the corresponding entries
of one interface to one set of functions and those of
the second to another set of functions.
This can't be done using the C++ language, because
when overriding a virtual function you override it for
all parent classes. One approach that I know of
involves intermediate classes with transition calls to
AddRef and Release.
Those guys in the C++ committee should consider the
possibility of deferent overrides for different parents.
It could be done like this:
struct I { virtual void f() = 0; };
struct I1 : I { };
struct I2 : I { };
struct S : I1, I2 {
virtual void I1::f();
virtual void I2::f();
};
> So, I am skeptical that what you are doing is
> a good idea, necessary, efficient or prudent.
>
> 3. Whatever you do in that realm is going to
> be non-portable and may break as the compiler
> evolves, even on the same platform. And it
> is likely to fail when multiple inheritance
> enters the picture.
>
> > many thanks for any suggestions
>
> Now, with that out of the way, I have a couple
> of suggestions.
>
> 1. Use the compiler's -Fa option to see how
> members are called by compiler generated code.
> (And if you cannot read assembler, I am duty-
> bound to repeat caveat #1.) You will discover
> that the this pointer is actually passed in a
> register rather than the call stack.
Not with __stdcall functions.
Sergei
that's where VirtualProtect() comes in handy...
Platform SDK: Memory Management
VirtualProtect
The VirtualProtect function changes the access protection on a region of
committed pages in the virtual address space of the calling process.
To change the access protection of any process, use the VirtualProtectEx
function.
BOOL VirtualProtect(
LPVOID lpAddress, // region of committed pages
SIZE_T dwSize, // size of the region
DWORD flNewProtect, // desired access protection
PDWORD lpflOldProtect // old protection
);
"Sergei" <ser...@summertime.mtu-net.ru> wrote in message
news:OPV2$m84BHA.2740@tkmsftngp07...
cheers
Geoff
"Mucki" <mu...@gryps.org> wrote in message
news:3CB95BD6...@gryps.org...
> Geoff wrote:
> > Larry
> > I understand your points, but I don't see another way around it.
> > My COverride class is in an extension dll which I'm running inside the
main
> > app
> > which has the CExisting class exposed through it's API.
> > What I do when my app get's loaded in is to get the existing classes,
pass
> > the
> > function override to my new class, then whenever the main app calls this
> > function
> > I can decide whether to let the call go through to the original object.
> > I cannot see how to achieve this any other way.
> >
>
> just do:
>
> COverride::func()
> {
> if (callParent) CExisting::func()
> }
>
> thats default polymorphism and virtual functino behavior
>
> Mucki
>
>
> ------------------------------------------------------------------------
>
> Subject:
>
> Re: Help needed calling redirected vtable function
> From:
>
> "Geoff" <sirb...@NOSPAMzoom.co.uk>
> Date:
>
> Sun, 14 Apr 2002 17:23:31 +0100
>
> Newsgroups:
>
> microsoft.public.vc.language
>
>
> Hi Mucki
> I can see this would work where I had derived off CExisting, and wanted to
> pass the
> call to a lower class in the chain, but I'm not derived from CExisting and
> I've
> changed the address of the function I'm intercepting in the vtable of
> CExisting.
> Calling CExisting::func() would surely only call my own function again ?
> I think that you may have misunderstood (as I often do reading other's
> posts),
> but if <I> have I'd really appreciate some enlightenment.
>
> cheers
> Geoff
>
Ok ... so let me get this straight:
In the main module you have a
class CExisting
{
virtual void foo();
};
and in the extensino module you have a
class COverride
{
virtual void foo();
};
which is *not* derived from CExisting.
and then at runtime you do:
for all CExisting* obj in objects
{
<somehow determine dynamic class of obj>
<copy vtable of dynamic class of obj into CExisting>
obj->foo();
<resture vtable>
}
Is this correct ?
If yes: *WHY* (!!!) do you not simply dervie COverride from CExisting ??
If no: please clarify what exactly you are doing and even more
important: what do you want to achieve with it.
Mucki
I couldn't find in the compiler's reference any hints on what
one should supply for this parameter.
And I would never write this in a real code:
//////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <iostream.h>
class S {
public:
void New() {
DWORD OldProtection;
VirtualProtect
(
*reinterpret_cast<void **>(this),
1,
PAGE_READWRITE,
&OldProtection
);
o1 = (void (*)()) (*reinterpret_cast<void ***>(this))[0];
(*reinterpret_cast<void ***>(this))[0] = n1;
o2 = (void (__stdcall *)(S *)) (*reinterpret_cast<void ***>(this))[1];
(*reinterpret_cast<void ***>(this))[1] = n2;
}
virtual void f1() { cout << "original f1" << endl; }
virtual void __stdcall f2() { cout << "original f2" << endl; }
private:
static void (*o1)();
static void (__stdcall *o2)(S *);
static void n1() {
void *This;
__asm mov This, ecx
cout << "new f1 calling ";
__asm mov ecx, This
o1();
}
static void __stdcall n2(S *p) {
cout << "new f2 calling ";
o2(p);
}
};
void (*S::o1)() = 0;
void (__stdcall *S::o2)(S *) = 0;
int main() {
S s, *p = &s;
p->f1();
p->f2();
s.New();
p->f1();
p->f2();
}
//////////////////////////////////////////////////////////////////////////////
Sergei
Geoff
"Sergei" <ser...@summertime.mtu-net.ru> wrote in message
news:#v6CxwF5BHA.492@tkmsftngp02...
I have a drawing app with loads of different types of drawable classes
I need to be able to control whether these object's stored in the drawing
draw or not
When the application needs to regenerate them it calls their virtual draw()
func
I have no notification of when any of these objects are being drawn, nor
access to it's draw()
All of these drawable classes are derived from the same set, specialising
more as they go
I derive my class from one of these base classes
I'm sure you understand, but just to be clear
here are 4 classes that are used within the drawing app.
I derive from C3, which means that I have the same bunch of virtual
functions in my class as all the other drawables
[C1 -> C2 -> C3 -> C4]
[C1 -> C2 -> C3 -> C5]
[C1 -> C2 -> C3 -> C6]
[C1 -> C2 -> C3 -> C7->C8]
to control everything's visibilty I need to have changed the vtable for
every classtype derived from C3
here's an example of how I then set the overriden function
// get the object's vtable pointer
void** pOriginalVFPtr = (void**)*(void**)pObject; // here pObject can be
anything derived from C3
// create subclass object and then get it's vtable
CMyOverride *pOverride = new CMyOverride;
void** pOverrideVFPtr = (void**)*(void**)pOverride;
DWORD op, op2;
BOOL bRes;
// change the original function pointer to our new one
bRes = VirtualProtect (&pOriginalVFPtr[4], sizeof(pOriginalVFPtr[4]),
PAGE_EXECUTE_READWRITE, &op);
pOriginalVFPtr[4] = pOverrideVFPtr[4]; // <<< this works perfectly
because of the common base class >>>
bRes = VirtualProtect (&pOriginalVFPtr[4], sizeof(pOriginalVFPtr[4]), op,
&op2);
delete pOverride;
CMyOverride::draw()
{
if (yes I want to draw)
{
put back original function pointer..
this->draw();
return overriden function pointer..
}
else
don't do anything..
}
Does that make sense ?
My knowledge of C++ is quite flaky, but it does work ;)
cheers
Geoff
"Michael Lacher" <Michael...@geospace.co.at> wrote in message
news:3CBA7ED4...@geospace.co.at...
Well, it's close to what asked for. I would be
careful to distinguish that from what you need.
> but here's what I'm doing...
I'm going to condense what you wrote here to a
more abstract description. Please correct me
if I got it wrong.
You have an interface thru which holders of
objects implementing that interface perform
an action we will call draw. There are some
subtypes derived from this interface -- let's
say DrawableOrange, DrawableApple, etc.
You wish to convert the behavior in response
to holders calling draw(), on a class-wide
basis, from { draw as appropriate for the
subtype } to { do nothing }, such that all
DrawableOrange objects might be made to do
nothing on a draw() call in one fell swoop.
Here is a C++ solution to that problem:
class IDrawable {
public:
virtual ~IDrawable() {}
virtual void draw() = 0;
};
class ISwitchDrawable : public IDrawable {
public:
// This next method may or may not belong here
// depending on who does class-wide hiding and
// what they have to know in order to do so.
virtual void enableDrawByClass(bool) = 0;
// Note: Still abstract absent draw() method.
};
// Wrap and own an instance of IDrawable.
template <typename DrawableKind>
class SwitchDrawable : public ISwitchDrawable {
static bool ourDrawEnabled = false;
DrawableKind * myDrawer;
public:
SwitchDrawable(DrawableKind * drawer)
: myDrawer( drawer ) { }
~SwitchDrawable() { delete myDrawer; }
virtual void enableDrawByClass(bool enable) {
ourDrawEnabled = enable;
}
virtual void draw() {
if (ourDrawEnabled)
myDrawer->draw();
}
};
// An example usage
class OrangeDisplay : public IDrawable {
void draw() { /* draw an orange somewhere */ }
};
class AppleDisplay : public IDrawable {
void draw() { /* draw an apple somewhere */ }
};
typedef SwitchDrawable<OrangeDisplay> DrawableOrange;
typedef SwitchDrawable<AppleDisplay> DrawableApple;
DrawableOrange juicy(new OrangeDisplay);
DrawableOrange fruit(new OrangeDisplay);
DrawableApple delicious(new AppleDisplay);
void show()
{
juicy.enableDrawByClass(true);
delicious.enableDrawByClass(true);
juicy.draw();
fruit.draw();
delicious.draw();
// Just drew 3 objects.
juicy.enableDrawByClass(false);
juicy.draw();
fruit.draw();
delicious.draw();
// Just drew 1 object.
}
This is an example of the adaptor pattern.
Just a correction for a C#ism I let
creep into that code ...
...
> // Wrap and own an instance of IDrawable.
> template <typename DrawableKind>
> class SwitchDrawable : public ISwitchDrawable {
//// > static bool ourDrawEnabled = false;
static bool ourDrawEnabled;
...
> };
Then, somewhere else:
template<typename d>
static bool SwitchDrawable<d>::ourDrawEnabled = false;
> DrawableOrange juicy(new OrangeDisplay);
> DrawableOrange fruit(new OrangeDisplay);
>
> DrawableApple delicious(new AppleDisplay);
>
shouldn't those be exactly the other way round ??
ie:
OrangeDisplay juicy(new DrawableOrange);
Mucki
PS: you technique only works if can modify the creation code for the
objectgs, if all you implement is a plugin DLL then this solution
wouldn't really work.
> Sergei's post seems to be exactly what I need, but here's what I'm doing...
>
> I have a drawing app with loads of different types of drawable classes
> I need to be able to control whether these object's stored in the drawing
> draw or not
> When the application needs to regenerate them it calls their virtual draw()
> func
> I have no notification of when any of these objects are being drawn, nor
> access to it's draw()
> All of these drawable classes are derived from the same set, specialising
> more as they go
> I derive my class from one of these base classes
>
> I'm sure you understand, but just to be clear
> here are 4 classes that are used within the drawing app.
> I derive from C3, which means that I have the same bunch of virtual
> functions in my class as all the other drawables
>
> [C1 -> C2 -> C3 -> C4]
>
> [C1 -> C2 -> C3 -> C5]
>
> [C1 -> C2 -> C3 -> C6]
>
> [C1 -> C2 -> C3 -> C7->C8]
>
>
> to control everything's visibilty I need to have changed the vtable for
> every classtype derived from C3
>
do you want to change the behaviour of the derived classes as Larry
Brasfield wrote, or do you want to do what i suspect:
Inject a class into the hierarchy at a point which is not the leaf
without changing the code ?
ie:
[C1 -> C2 -> C3 -> MyClass -> C4 ]
I think overriding the vtable is the only suitable way to do this, but I
am not sure if this will always work as expected ... Some compiler
optimizations might kill your app ...
If this is really what you are trying to do then I think you should
really considering a totally different strategy. (Why do you want to
control other objects visibility through your class at all ?)
Mucki
My proposed solution, as I wrote it,
implements exactly that interposition,
(or injection, if you like). If you
look at what I wrote, you will see
an interface, IDrawable, offered by
the "leaf", wrapped by the interposed
stuff, and exposed again at the top:
IDrawable -> ISwitchDrawable ->
SwitchDrawable<DrawableKind> wrapping
an IDrawable subclass.
> I think overriding the vtable is the only suitable way to
> do this, but I am not sure if this will always work as
> expected ... Some compiler optimizations might kill your app ...
Well, I see the same dangers and said as
much in my first response in this thread.
> If this is really what you are trying to do then I think you should
> really considering a totally different strategy. (Why do you want to
> control other objects visibility through your class at all ?)
What he claims to want to accomplish seems
reasonable enough to me. I just question
the necessity to be rewriting v-tables to
do it. I especially shudder at having to
make calls that bottom out into the memory
management hardware driver. I expect there
is a performance penalty to be paid there.
I don't think so. Can you say why?
Please see my other post of several
minutes ago showing what that code
is supposed to be doing.
> Mucki
>
> PS: you technique only works if can modify the creation code for the
> objectgs, if all you implement is a plugin DLL then this solution
> wouldn't really work.
I did assume that the plugin interface was
to be preserved and the switching was to
be effected by whatever is using the DLL.
> In article <3CBBCD77...@geospace.co.at>,
> Michael Lacher (Michael...@geospace.co.at) says...
>
>>Larry Brasfield wrote:
>>
>>
>>
>>>DrawableOrange juicy(new OrangeDisplay);
>>>DrawableOrange fruit(new OrangeDisplay);
>>>
>>>DrawableApple delicious(new AppleDisplay);
>>>
>>>
>>
>>shouldn't those be exactly the other way round ??
>>
>>ie:
>>OrangeDisplay juicy(new DrawableOrange);
>>
>
> I don't think so. Can you say why?
>
> Please see my other post of several
> minutes ago showing what that code
> is supposed to be doing.
>
uhm ... sorry .. you are right ... I didn't completely understand your
code the first time i read it .
> In article <3CBBCE15...@geospace.co.at>,
> Michael Lacher (Michael...@geospace.co.at) says...
> ....
>
>>do you want to change the behaviour of the derived classes as Larry
>>Brasfield wrote, or do you want to do what i suspect:
>>
>>Inject a class into the hierarchy at a point which is not the leaf
>>without changing the code ?
>>
>>ie:
>>
>>[C1 -> C2 -> C3 -> MyClass -> C4 ]
>>
>
> My proposed solution, as I wrote it,
> implements exactly that interposition,
> (or injection, if you like). If you
> look at what I wrote, you will see
> an interface, IDrawable, offered by
> the "leaf", wrapped by the interposed
> stuff, and exposed again at the top:
> IDrawable -> ISwitchDrawable ->
> SwitchDrawable<DrawableKind> wrapping
> an IDrawable subclass.
>
Yes ... but you assume that the object C4 is derived from IDrawable ( or
i still do not understand the technique). If all classes except my own
are already fixed (ie: in binary form only) and I can only add my object
through an extension DLL then this would not work. (except by creating
new leaves C4' which is : public C4,public IDrawable, but then future
"normal" extension will be broken).
Mucki
>
>>I think overriding the vtable is the only suitable way to
>>do this, but I am not sure if this will always work as
>>expected ... Some compiler optimizations might kill your app ...
>>
>
> Well, I see the same dangers and said as
> much in my first response in this thread.
>
>
>>If this is really what you are trying to do then I think you should
>>really considering a totally different strategy. (Why do you want to
>>control other objects visibility through your class at all ?)
>>
>
> What he claims to want to accomplish seems
> reasonable enough to me. I just question
> the necessity to be rewriting v-tables to
> do it. I especially shudder at having to
> make calls that bottom out into the memory
> management hardware driver. I expect there
> is a performance penalty to be paid there.
>
It sounds to me like he is trying to retrofit something like a LOD or
better culling into an existing scenegraph or somthing by trying to
modify the behaviour of the original Node class. And I think this is not
a really good idea. Apart from the C++ issues you have to think about
the fact that derived classes might assume things about its parent which
are not true anymore after the modification.
Mucki
Here is what I assumed about the OP's
situation from what I have read so far:
A common abstract base class is involved.
("All of these drawable classes are derived
from the same set, ..." and they are known
to have virtual methods.) Visibility is to
be controllable for a set of classes that
implement that ABC. ("to control everything's
visibilty I need to have changed the vtable
for every classtype derived from [a single
common base class]") The plugin classes
are not subject to modification and upper
layers of the application are difficult or
impossible to mess with just now. ("I have
no notification of when any of these objects
are being drawn, nor access to it's draw()")
From the non-modifiability of the DLL's, I
infer that the OP has the option of altering
the code which loads the DLL's, otherwise he
would not have posted anything.
> If all classes except my own
> are already fixed (ie: in binary form only) and I can only add my object
> through an extension DLL then this would not work. (except by creating
> new leaves C4' which is : public C4,public IDrawable, but then future
> "normal" extension will be broken).
I think maybe you have an inverted idea
as to what is fixed and what is mutable.
You seem to suggest that the OP wants to
modify the extension DLL's whereas I see
that those are fixed and whatever loads
those DLL's is to be modified.
I assume the plugin's are already exposing
some defined interface. The IDrawable I
used in my example solution is a standin
for whatever interface that is. That same
interface is exposed again by the wrapper
so the existing clients can continue to
use it as before. My solution does require
that instantiation of the plugin objects be
accessible so they can be wrapped.
Do you still see a mismatch between what I
propose and the OP's problem as stated?
...
> > What he claims to want to accomplish seems
> > reasonable enough to me. I just question
> > the necessity to be rewriting v-tables to
> > do it. I especially shudder at having to
> > make calls that bottom out into the memory
> > management hardware driver. I expect there
> > is a performance penalty to be paid there.
>
> It sounds to me like he is trying to retrofit something like a LOD
(I do not grok 'LOD'.)
> or better culling into an existing scenegraph or somthing by trying to
> modify the behaviour of the original Node class. And I think this is not
> a really good idea. Apart from the C++ issues you have to think about
> the fact that derived classes might assume things about its parent which
> are not true anymore after the modification.
Well, there are probably many issues in such
a design that have not been posted. We can
only address the problems as evident.
The problem does have the flavor of a design
retrofit that might be happening at the wrong
level, but I do not see enough to justify
that suspicion or to tell the OP that doing
a retrofit is the wrong approach altogether.
My wrapper design does not preclude passing
assumed base class characteristics down thru
the hierarchy. Of course, not knowing of any
such characteristics, I did not propagate any.
> In article <3CBBDF75...@geospace.co.at>,
> Michael Lacher (Michael...@geospace.co.at) says...
>
>>Larry Brasfield wrote:
>>
>>
>>>In article <3CBBCE15...@geospace.co.at>,
>>>Michael Lacher (Michael...@geospace.co.at) says...
>>>....
>>>
[snip]
>
>>If all classes except my own
>>are already fixed (ie: in binary form only) and I can only add my object
>>through an extension DLL then this would not work. (except by creating
>>new leaves C4' which is : public C4,public IDrawable, but then future
>>"normal" extension will be broken).
>>
>
> I think maybe you have an inverted idea
> as to what is fixed and what is mutable.
> You seem to suggest that the OP wants to
> modify the extension DLL's whereas I see
> that those are fixed and whatever loads
> those DLL's is to be modified.
>
well ... he said that "My COverride class is in an extension dll which
I'm running inside the main app" so combined with the other i read this
all as:
The main app is fixed and all extension dlls are fixed except his own.
> I assume the plugin's are already exposing
> some defined interface. The IDrawable I
> used in my example solution is a standin
> for whatever interface that is. That same
> interface is exposed again by the wrapper
> so the existing clients can continue to
> use it as before. My solution does require
> that instantiation of the plugin objects be
> accessible so they can be wrapped.
>
> Do you still see a mismatch between what I
> propose and the OP's problem as stated?
>
I believe he cannot change the instantiation of the plugin objects. If
he could, then your solution is quite practical.
> ....
>
>>It sounds to me like he is trying to retrofit something like a LOD
>>
> (I do not grok 'LOD'.)
>
Level Of Detail. (In this case i had something in mind like hiding
objects depending on distance or relacing with lowresolution versions or
something)
>>or better culling into an existing scenegraph or somthing by trying to
>>modify the behaviour of the original Node class. And I think this is not
>>a really good idea. Apart from the C++ issues you have to think about
>>the fact that derived classes might assume things about its parent which
>>are not true anymore after the modification.
>>
>
> Well, there are probably many issues in such
> a design that have not been posted. We can
> only address the problems as evident.
>
> The problem does have the flavor of a design
> retrofit that might be happening at the wrong
> level, but I do not see enough to justify
> that suspicion or to tell the OP that doing
> a retrofit is the wrong approach altogether.
>
> My wrapper design does not preclude passing
> assumed base class characteristics down thru
> the hierarchy. Of course, not knowing of any
> such characteristics, I did not propagate any.
>
Maybe I go too far with my assumptions, anyway I think that with more
information about what the general idea we could help him alot better :)
Mucki
Not if you're writing a program that I will happen
to modify a year later.
Sergei
OK. I can see that interpretation. It
conflicts with what I got from the other
words I cited from the OP. So I don't
know what to think. Perhaps we should
wait for him to clarify.
...
> > My solution does require
> > that instantiation of the plugin objects be
> > accessible so they can be wrapped.
>
> > Do you still see a mismatch between what I
> > propose and the OP's problem as stated?
>
> I believe he cannot change the instantiation of the plugin objects. If
> he could, then your solution is quite practical.
I think we are reduced to waiting for
the OP's response.
[snip about 'LOD'. Thanks.]
...
> Maybe I go too far with my assumptions, anyway I think that with more
> information about what the general idea we could help him alot better :)
I couldn't agree more.
Having been so stern about v-table writing
and the rarity of its necessity, I do feel
somewhat compelled to back up those words.
> to help me, I've included a graphical view of the system
That was indeed helpful. Before I respond
in more detail, could you clarify a few
more points raised below?
> The MainApplication has a fixed hierarchy which I cannot change.
>
> My application is the extension DLL, which is the only part I can do
> anything with.
Is it true that the extension DLL implements
a pure abstract base class? (interface only,
nothing but pure virtual methods)
> In MyDLL I can derive my own objects from any existing and register
> them with the MainApp which will then call their draw methods when
> needed.
I take it that MyDLL provides a creation
function? Does this function handle
multiple subclasses coming from MyDLL
or are you supposed to register one
for each subclass?
> With the objects I register myself (MyOverride and SuperText) I have
> a draw() method which I fill in and can choose whether to draw or not (but
> don't want to, as it needs to be a generic solution for all objects).
>
> With the other types (Line, Arc, Spline, Text, Symbol) I can only
> instantiate new objects of these types, or modify those that are
> existing in the drawing.
Do you have reason to be controlling
how those other objects behave when
they are instantiated outside of your
control? Or do you just need to
control the ones you instantiate?
> I have no notification of the draw() being called on any objects other than
> those I have registered myself, thus I need a method to get this
> notification.
>
> MyDLL gets all registered types derived from Drawable and sets their
> vtable entry for draw() to the vtable entry in MyOverride.
Do you have the opportunity to
re-register those registered
types?
> When the MainApp calls draw() on any of these objects it comes to
> MyOverride::draw() first so I can decide whether to pass on the
> call or not.
Now I'm a little puzzled. Do you
have a reference to those other
objects (the ones not created by
MyDLL) or is it just by virtue
of reaching their v-tables that
you can tell they exist?
> I understand that it's not the ideal solution, but it really is the
> only valid solution due to limitations of the MainApp.
Please forgive me for continuing to
be skeptical of that claim. If it
is true, (and I will not pretend to
know it is false), I am quite
interested to understand why.
When you block draw() calls, how
(roughly) do you determine which
classes to block them for? Is it
done on an instance-by-instance
basis? Or is it always per-class
without regard for which instances
are involved? Are you modifying
the drawing of objects unrelated
to the ones MyDLL creates?
> There is the issue of performance, but I think the cost is worth it
> for the extra functionality.
How big a hit do you take for each unprotect/
protect sequence?
> I hope this clarifies.
Pretty much, yes.
...
"Larry Brasfield" <larry_brasf...@hotmail.com> wrote in message
news:MPG.17263cb49...@msnews.microsoft.com...
> In article <u$9IaxY5BHA.1812@tkmsftngp02>,
> Geoff (sirb...@NOSPAMzoom.co.uk) says...
> Is it true that the extension DLL implements
> a pure abstract base class? (interface only,
> nothing but pure virtual methods)
no, there are base implementations for most (or all ?) methods
>
> > In MyDLL I can derive my own objects from any existing and register
> > them with the MainApp which will then call their draw methods when
> > needed.
>
> I take it that MyDLL provides a creation
> function? Does this function handle
> multiple subclasses coming from MyDLL
> or are you supposed to register one
> for each subclass?
no, by registering *each* new class type with the MainApp, the MainApp
can use them as it's own (as any plug-in system should)
the base functionality for creating and using these objects is in the base
classes
> > With the objects I register myself (MyOverride and SuperText) I have
> > a draw() method which I fill in and can choose whether to draw or not
(but
> > don't want to, as it needs to be a generic solution for all objects).
> >
> > With the other types (Line, Arc, Spline, Text, Symbol) I can only
> > instantiate new objects of these types, or modify those that are
> > existing in the drawing.
>
> Do you have reason to be controlling
> how those other objects behave when
> they are instantiated outside of your
> control? Or do you just need to
> control the ones you instantiate?
whether I instantiate them or not, I do not have control over them
but I need control over *all* objects
>
> > I have no notification of the draw() being called on any objects other
than
> > those I have registered myself, thus I need a method to get this
> > notification.
> >
> > MyDLL gets all registered types derived from Drawable and sets their
> > vtable entry for draw() to the vtable entry in MyOverride.
>
> Do you have the opportunity to
> re-register those registered
> types?
no
>
> > When the MainApp calls draw() on any of these objects it comes to
> > MyOverride::draw() first so I can decide whether to pass on the
> > call or not.
>
> Now I'm a little puzzled. Do you
> have a reference to those other
> objects (the ones not created by
> MyDLL) or is it just by virtue
> of reaching their v-tables that
> you can tell they exist?
>
the MainApp has the references to all these objects, and when it needs
to update the display it will call the draw() method on each object it has
in the drawing.
Because I redirect the draw() method by replacing the appropriate entry in
the vtable
for each *type* of object, then my replaced function gets called instead.
example:
Line
__vfptr
[0] 0x0...
[1] 0x0...
[2] 0x06660666 (was 0x01110111)
Arc
__vfptr
[0] 0x0...
[1] 0x0...
[2] 0x06660666 (was 0x02220222)
MyOverride
__vfptr
[0] 0x0...
[1] 0x0...
[2] 0x06660666 - ( draw() method )
> > I understand that it's not the ideal solution, but it really is the
> > only valid solution due to limitations of the MainApp.
>
> Please forgive me for continuing to
> be skeptical of that claim. If it
> is true, (and I will not pretend to
> know it is false), I am quite
> interested to understand why.
There are methods to make each object visible/invisible
BUT this is for the whole drawing.
There can be many *Views* of the drawing model and as such an object made
invisible
will not show in *any* view.
This is a <real> pain.
If a view has many objects in line of sight, then clarity can be lost and so
it makes sense
to be able to remove some objects from the view to focus on those you do
want to see.
This is just one example of many
>
> When you block draw() calls, how
> (roughly) do you determine which
> classes to block them for? Is it
> done on an instance-by-instance
> basis? Or is it always per-class
> without regard for which instances
> are involved? Are you modifying
> the drawing of objects unrelated
> to the ones MyDLL creates?
it's per object, irrelevant of type
each object has a unique identifier that we can use to sort what is drawn
and in which view
(each view having a unique id we can match against)
>
> > There is the issue of performance, but I think the cost is worth it
> > for the extra functionality.
>
> How big a hit do you take for each unprotect/
> protect sequence?
>
we haven't tested with too many objects yet,
but by being able to call the original draw() for each class type with it's
function pointer
(and this pointer) rather than resetting the vtable for every object we need
to draw
we will only have to do the protect/unprotect once for every class type in
the lifetime
of the user session with the drawing
this will (should) mean significantly less overhead
In article <eWIM7kZ5BHA.1900@tkmsftngp02>,
Geoff (sirb...@NOSPAMzoom.co.uk) says...
...
> "Larry Brasfield" <larry_brasf...@hotmail.com> wrote in message
> news:MPG.17263cb49...@msnews.microsoft.com...
...
> > Is it true that the extension DLL implements
> > a pure abstract base class? (interface only,
> > nothing but pure virtual methods)
>
> no, there are base implementations for most (or all ?) methods
That certainly complicates any wrapping
strategy one might envision.
...
> > I take it that MyDLL provides a creation
> > function? Does this function handle
> > multiple subclasses coming from MyDLL
> > or are you supposed to register one
> > for each subclass?
>
> no, by registering *each* new class type with the MainApp, the
> MainApp can use them as it's own (as any plug-in system should)
> the base functionality for creating and using these objects is
> in the base classes
There must be some assistance with creation
from the plugin unless it provides enough
type information to allow synthesizing new
objects from that alone.
...
> > Do you have reason to be controlling
> > how those other objects behave when
> > they are instantiated outside of your
> > control? Or do you just need to
> > control the ones you instantiate?
>
> whether I instantiate them or not, I do not have control over
> them but I need control over *all* objects
This is the clincher, as I see it.
More on this later.
...
> > Do you have the opportunity to
> > re-register those registered
> > types?
>
> no
This further precludes the possible
ways of interposing anything within
the constraints established by the
plugin architecture.
...
> > Now I'm a little puzzled. Do you
> > have a reference to those other
> > objects (the ones not created by
> > MyDLL) or is it just by virtue
> > of reaching their v-tables that
> > you can tell they exist?
>
> the MainApp has the references to all these objects, and when
> it needs to update the display it will call the draw() method
> on each object it has in the drawing.
I take that as "No, I do not, within the
code I have control over, have references
to the set of objects upon which I need
to effect behavior changes."
[v-table overwriting demo cut]
That's been pretty clear already.
...
[regarding necessity of v-table rewriting]
> > Please forgive me for continuing to
> > be skeptical of that claim. If it
> > is true, (and I will not pretend to
> > know it is false), I am quite
> > interested to understand why.
>
> There are methods to make each object visible/invisible
> BUT this is for the whole drawing.
> There can be many *Views* of the drawing model and as such
> an object made invisible will not show in *any* view.
> This is a <real> pain.
> If a view has many objects in line of sight, then clarity
> can be lost and so it makes sense to be able to remove some
> objects from the view to focus on those you do want to see.
> This is just one example of many
Ok, the light is dawning now.
What you are doing is, in fact, going
into existing binary code, outside of
what you actually get to affect with
source code changes, and modifying
the behavior of portions of the binary
image otherwise outside your control.
That task is not in the ordinary realm
of programming to which my earliest
post was directed, where I said:
I have never seen v-table manipulation
done outside of a compiler that solved
a problem not better solved within the
language constraints. So, I am skeptical
that what you are doing is a good idea,
necessary, efficient or prudent.
I still wonder about prudence, but
given that the binary image is more or
less fixed, or at least the v-table
layout will have to be preserved to
retain plugin compatibility, I can
see your solution as not reckless.
Given the invasive nature of what you
are doing, together with the fact that
what you are invading is apparently not
subject to redesign in C++ to accomodate
these new requirements, I can see the
sense of effecting the invasion with
v-table manipulation.
So, please accept my thanks for putting
up with all my warnings and skepticism
in a good-natured manner.
I trust you have got the member-calling
sequence problem solved by now. If your
original question is still pending, (How
do I call the original v-table entry?),
I will be happy to help with that, and
without so much paternalistic verbage.
I will offer just this little tip: It
is reasonable to substitute the v-table
pointer in existing objects to refer
to a new v-table, probably in writable
memory. You can arrange that no further
object patching is needed (per-object)
after the first one, and you should be
able to avoid repeated v-table writing,
using just one rewrite to allow capture
of each object's use of the its orignal
v-table. With this technique, you can
entirely avoid the issue of how to do
your own member-call in assembler.
-Best regards,
-Larry Brasfield
(address munged)
I have another idea about optimizing the vtable rewrites:
rewrite the vtable as you did but do not point to your function, instead
point to a piece of code that looks like this: JMP funcPtr; (in fact
emulate a small second vtable :) ). then replace the funcPtr with the
pointer of the original member function, or the NOOP version implemented
in your class depending on visibility.
Mucki
"Larry Brasfield" <larry_brasf...@hotmail.com> wrote in message
news:MPG.1726ba5c4...@msnews.microsoft.com...