diff --git a/library/VTableInterpose.cpp b/library/VTableInterpose.cpp index 447070624..f612ba8bd 100644 --- a/library/VTableInterpose.cpp +++ b/library/VTableInterpose.cpp @@ -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), saved_chain(NULL), next(NULL), prev(NULL) { + assert(vmethod_idx >= 0 && interpose_method != NULL); } VMethodInterposeLinkBase::~VMethodInterposeLinkBase() @@ -198,6 +199,7 @@ bool VMethodInterposeLinkBase::apply() return false; set_chain(old_ptr); + host->interpose_list.push_back(this); // Link into the chain if any if (old_link) diff --git a/library/include/VTableInterpose.h b/library/include/VTableInterpose.h index 59a5c2831..5eaeaed85 100644 --- a/library/include/VTableInterpose.h +++ b/library/include/VTableInterpose.h @@ -81,12 +81,18 @@ namespace DFHack return addr_to_method_pointer
(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:
- struct my_hack : public someclass {
- typedef someclass interpose_base;
+ struct my_hack : df::someclass {
+ typedef df::someclass interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, foo, (int arg)) {
...
@@ -98,7 +104,12 @@ namespace DFHack
IMPLEMENT_VMETHOD_INTERPOSE(my_hack, foo);
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);
#define INTERPOSE_NEXT(name) (this->*interpose_##name.chain)
+#define INTERPOSE_HOOK(class, name) (class::interpose_##name)
class DFHACK_EXPORT VMethodInterposeLinkBase {
/*
diff --git a/plugins/devel/vshook.cpp b/plugins/devel/vshook.cpp
index 28f983624..319ff0e99 100644
--- a/plugins/devel/vshook.cpp
+++ b/plugins/devel/vshook.cpp
@@ -33,9 +33,12 @@ struct title_hook : df::viewscreen_titlest {
uint8_t *buf = gps->screen;
int32_t *stp = gps->screentexpos;
- for (const char *p = "DFHack " DFHACK_VERSION; *p; p++) {
- *buf++ = *p; *buf++ = 7; *buf++ = 0; *buf++ = 1;
- *stp++ = 0;
+ for (const char *p = "DFHack " DFHACK_VERSION;
+ *p && buf < gps->screen_limit;
+ 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