Tweak the interpose API, and fix a couple of bugs.

develop
Alexander Gavrilov 2012-08-18 11:48:07 +04:00
parent 236ffd578b
commit 01ba2a31fc
3 changed files with 26 additions and 9 deletions

@ -161,6 +161,7 @@ VMethodInterposeLinkBase::VMethodInterposeLinkBase(virtual_identity *host, int v
: host(host), vmethod_idx(vmethod_idx), interpose_method(interpose_method), chain_mptr(chain_mptr), : host(host), vmethod_idx(vmethod_idx), interpose_method(interpose_method), chain_mptr(chain_mptr),
saved_chain(NULL), next(NULL), prev(NULL) saved_chain(NULL), next(NULL), prev(NULL)
{ {
assert(vmethod_idx >= 0 && interpose_method != NULL);
} }
VMethodInterposeLinkBase::~VMethodInterposeLinkBase() VMethodInterposeLinkBase::~VMethodInterposeLinkBase()
@ -198,6 +199,7 @@ bool VMethodInterposeLinkBase::apply()
return false; return false;
set_chain(old_ptr); set_chain(old_ptr);
host->interpose_list.push_back(this);
// Link into the chain if any // Link into the chain if any
if (old_link) if (old_link)

@ -81,12 +81,18 @@ namespace DFHack
return addr_to_method_pointer<P>(identity.get_vmethod_ptr(idx)); return addr_to_method_pointer<P>(identity.get_vmethod_ptr(idx));
} }
/* VMethod interpose API /* VMethod interpose API.
This API allows replacing an entry in the original vtable
with code defined by DFHack, while retaining ability to
call the original code. The API can be safely used from
plugins, and multiple hooks for the same vmethod are
automatically chained in undefined order.
Usage: Usage:
struct my_hack : public someclass { struct my_hack : df::someclass {
typedef someclass interpose_base; typedef df::someclass interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, foo, (int arg)) { DEFINE_VMETHOD_INTERPOSE(void, foo, (int arg)) {
... ...
@ -98,7 +104,12 @@ namespace DFHack
IMPLEMENT_VMETHOD_INTERPOSE(my_hack, foo); IMPLEMENT_VMETHOD_INTERPOSE(my_hack, foo);
void init() { void init() {
my_hack::interpose_foo.apply() if (!INTERPOSE_HOOK(my_hack, foo).apply())
error();
}
void shutdown() {
INTERPOSE_HOOK(my_hack, foo).remove();
} }
*/ */
@ -112,6 +123,7 @@ namespace DFHack
class::interpose_##name(&class::interpose_base::name, &class::interpose_fn_##name); class::interpose_##name(&class::interpose_base::name, &class::interpose_fn_##name);
#define INTERPOSE_NEXT(name) (this->*interpose_##name.chain) #define INTERPOSE_NEXT(name) (this->*interpose_##name.chain)
#define INTERPOSE_HOOK(class, name) (class::interpose_##name)
class DFHACK_EXPORT VMethodInterposeLinkBase { class DFHACK_EXPORT VMethodInterposeLinkBase {
/* /*

@ -33,9 +33,12 @@ struct title_hook : df::viewscreen_titlest {
uint8_t *buf = gps->screen; uint8_t *buf = gps->screen;
int32_t *stp = gps->screentexpos; int32_t *stp = gps->screentexpos;
for (const char *p = "DFHack " DFHACK_VERSION; *p; p++) { for (const char *p = "DFHack " DFHACK_VERSION;
*buf++ = *p; *buf++ = 7; *buf++ = 0; *buf++ = 1; *p && buf < gps->screen_limit;
*stp++ = 0; p++, buf += gps->dimy*4, stp += gps->dimy)
{
buf[0] = *p; buf[1] = 7; buf[2] = 0; buf[3] = 1;
*stp = 0;
} }
} }
} }
@ -47,7 +50,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
{ {
if (gps) if (gps)
{ {
if (!title_hook::interpose_render.apply()) if (!INTERPOSE_HOOK(title_hook, render).apply())
out.printerr("Could not interpose viewscreen_titlest::render\n"); out.printerr("Could not interpose viewscreen_titlest::render\n");
} }
@ -56,6 +59,6 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
DFhackCExport command_result plugin_shutdown ( color_ostream &out ) DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{ {
title_hook::interpose_render.remove(); INTERPOSE_HOOK(title_hook, render).remove();
return CR_OK; return CR_OK;
} }