Replace the partial mechanics transcriptions with a separate, readable C11 reconstruction of the complete Win16 image while preserving the original raw Ghidra export as immutable evidence. Cover all ordinary and overlapping entry points, Borland runtime behavior, Win16 imports, segmented data, callbacks, resources, indirect control flow, physics, rendering, persistence, and startup/shutdown lifecycles. Add deterministic extraction and audit tooling plus address-linked ledgers for functions, imports, DGROUP ranges and objects, relocations, resources, and callbacks. The final gate records zero raw, partial, restored, unknown, blocked, or unclassified required units. Keep the semantic-fidelity boundary explicit: the portable C is not claimed to reproduce a byte-identical Borland NE build. Add strict focused harnesses for every reconstructed C unit, exact resource round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source or Cargo metadata is changed in this phase. Test Plan: - `bash original/tools/test_reconstructed_c.sh` -- passed - `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit - `python3 original/tools/audit_reconstruction.py --require-complete` -- passed - `git diff --cached --check` -- passed - `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
316 lines
9.3 KiB
C
316 lines
9.3 KiB
C
#include "../tdkpin_window_messages.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
|
|
Win16FarPtr g_object_windows_application;
|
|
uint8_t g_object_windows_focus_event_marker;
|
|
|
|
static int32_t g_window_style;
|
|
static unsigned g_sequence[32];
|
|
static unsigned g_sequence_count;
|
|
static Win16FarPtr g_last_procedure;
|
|
static Win16FarPtr g_last_receiver;
|
|
static ObjectWindowsMessage *g_last_message;
|
|
static uint16_t g_scroll_position;
|
|
static uint16_t g_scroll_command;
|
|
static HDC16 g_paint_dc;
|
|
static RECT16 g_window_rectangle;
|
|
static MSG16 g_queued_messages[4];
|
|
static unsigned g_queued_count;
|
|
static unsigned g_queued_index;
|
|
static HWND16 g_capture_window;
|
|
static unsigned g_release_calls;
|
|
static unsigned g_translate_calls;
|
|
static unsigned g_dispatch_calls;
|
|
static unsigned g_mouse_calls;
|
|
|
|
enum Sequence {
|
|
SEQ_MESSAGE = 1,
|
|
SEQ_SCROLL,
|
|
SEQ_BEGIN_PAINT,
|
|
SEQ_PAINT,
|
|
SEQ_METHOD,
|
|
SEQ_END_PAINT,
|
|
SEQ_GET_RECT,
|
|
SEQ_CAPTURE,
|
|
SEQ_TRANSLATE,
|
|
SEQ_DISPATCH,
|
|
SEQ_MOUSE,
|
|
SEQ_RELEASE,
|
|
};
|
|
|
|
static void record(unsigned value)
|
|
{
|
|
assert(g_sequence_count < sizeof(g_sequence) / sizeof(*g_sequence));
|
|
g_sequence[g_sequence_count++] = value;
|
|
}
|
|
|
|
int32_t GetWindowLong16(HWND16 window, INT16 index)
|
|
{
|
|
assert(window == 0x1234 && index == -16);
|
|
return g_window_style;
|
|
}
|
|
|
|
void win16_call_object_message_handler(
|
|
Win16FarPtr procedure,
|
|
Win16FarPtr object,
|
|
ObjectWindowsMessage *message)
|
|
{
|
|
g_last_procedure = procedure;
|
|
g_last_receiver = object;
|
|
g_last_message = message;
|
|
record(SEQ_MESSAGE);
|
|
}
|
|
|
|
void win16_call_object_scroll_method(
|
|
Win16FarPtr procedure,
|
|
Win16FarPtr object,
|
|
uint16_t position,
|
|
uint16_t command)
|
|
{
|
|
g_last_procedure = procedure;
|
|
g_last_receiver = object;
|
|
g_scroll_position = position;
|
|
g_scroll_command = command;
|
|
record(SEQ_SCROLL);
|
|
}
|
|
|
|
HDC16 BeginPaint16(HWND16 window, Win16FarPtr paint)
|
|
{
|
|
assert(window == 0x1234);
|
|
win16_write_u16(paint, 0, g_paint_dc);
|
|
record(SEQ_BEGIN_PAINT);
|
|
return g_paint_dc;
|
|
}
|
|
|
|
BOOL16 EndPaint16(HWND16 window, Win16FarPtr paint)
|
|
{
|
|
assert(window == 0x1234 && win16_read_u16(paint) == g_paint_dc);
|
|
record(SEQ_END_PAINT);
|
|
return 1;
|
|
}
|
|
|
|
void win16_call_object_paint_method(
|
|
Win16FarPtr procedure,
|
|
Win16FarPtr object,
|
|
PAINTSTRUCT16 *paint,
|
|
HDC16 dc)
|
|
{
|
|
assert(paint->dc == g_paint_dc && dc == g_paint_dc);
|
|
g_last_procedure = procedure;
|
|
g_last_receiver = object;
|
|
record(SEQ_PAINT);
|
|
}
|
|
|
|
void win16_call_object_method(
|
|
Win16FarPtr procedure, Win16FarPtr object)
|
|
{
|
|
g_last_procedure = procedure;
|
|
g_last_receiver = object;
|
|
record(SEQ_METHOD);
|
|
}
|
|
|
|
BOOL16 GetWindowRect16(HWND16 window, Win16FarPtr rectangle)
|
|
{
|
|
assert(window == 0x1234);
|
|
win16_write_u16(rectangle, 0, (uint16_t)g_window_rectangle.left);
|
|
win16_write_u16(rectangle, 2, (uint16_t)g_window_rectangle.top);
|
|
win16_write_u16(rectangle, 4, (uint16_t)g_window_rectangle.right);
|
|
win16_write_u16(rectangle, 6, (uint16_t)g_window_rectangle.bottom);
|
|
record(SEQ_GET_RECT);
|
|
return 1;
|
|
}
|
|
|
|
HWND16 SetCapture16(HWND16 window)
|
|
{
|
|
g_capture_window = window;
|
|
record(SEQ_CAPTURE);
|
|
return 0xaaaa;
|
|
}
|
|
|
|
BOOL16 ReleaseCapture16(void)
|
|
{
|
|
g_release_calls++;
|
|
record(SEQ_RELEASE);
|
|
return 1;
|
|
}
|
|
|
|
BOOL16 PeekMessage16(
|
|
MSG16 *message,
|
|
HWND16 window,
|
|
UINT16 minimum_message,
|
|
UINT16 maximum_message,
|
|
UINT16 remove_message)
|
|
{
|
|
assert(window == 0 && minimum_message == 0 && maximum_message == 0);
|
|
assert(remove_message == 1);
|
|
if (g_queued_index == g_queued_count) {
|
|
return 0;
|
|
}
|
|
*message = g_queued_messages[g_queued_index++];
|
|
return 1;
|
|
}
|
|
|
|
BOOL16 TranslateMessage16(const MSG16 *message)
|
|
{
|
|
(void)message;
|
|
g_translate_calls++;
|
|
record(SEQ_TRANSLATE);
|
|
return 1;
|
|
}
|
|
|
|
LRESULT16 DispatchMessage16(const MSG16 *message)
|
|
{
|
|
(void)message;
|
|
g_dispatch_calls++;
|
|
record(SEQ_DISPATCH);
|
|
return 0;
|
|
}
|
|
|
|
void win16_call_object_u16_method(
|
|
Win16FarPtr procedure, Win16FarPtr object, uint16_t argument)
|
|
{
|
|
assert(argument == 0x1234);
|
|
g_last_procedure = procedure;
|
|
g_last_receiver = object;
|
|
g_mouse_calls++;
|
|
record(SEQ_MOUSE);
|
|
}
|
|
|
|
static void write_far(
|
|
Win16FarPtr base, uint16_t offset, Win16FarPtr value)
|
|
{
|
|
win16_write_u16(base, offset, win16_far_offset(value));
|
|
win16_write_u16(
|
|
base, (uint16_t)(offset + 2), win16_far_selector(value));
|
|
}
|
|
|
|
static void reset_observations(void)
|
|
{
|
|
g_sequence_count = 0;
|
|
g_last_procedure = 0;
|
|
g_last_receiver = 0;
|
|
g_last_message = 0;
|
|
g_queued_count = 0;
|
|
g_queued_index = 0;
|
|
g_release_calls = 0;
|
|
g_translate_calls = 0;
|
|
g_dispatch_calls = 0;
|
|
g_mouse_calls = 0;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
static uint8_t dgroup[0x1000];
|
|
uint8_t stack_anchor = 0;
|
|
uintptr_t stack_base = (uintptr_t)&stack_anchor - 0x8000;
|
|
win16_reset_segment_bindings();
|
|
win16_bind_segment(0x5000, dgroup, sizeof(dgroup), true);
|
|
win16_set_dgroup_selector(0x5000);
|
|
win16_bind_segment(0x7000, (void *)stack_base, 0x10000, true);
|
|
|
|
Win16FarPtr window = win16_make_far_pointer(0x5000, 0x0200);
|
|
Win16FarPtr attached = win16_make_far_pointer(0x5000, 0x0300);
|
|
win16_write_u16(window, 0, 0x0400);
|
|
win16_write_u16(window, 4, 0x1234);
|
|
win16_write_u16(attached, 0, 0x0500);
|
|
write_far(window, 0x3b, attached);
|
|
|
|
Win16FarPtr default_proc = win16_make_far_pointer(0x6000, 0x1000);
|
|
Win16FarPtr fallback_scroll = win16_make_far_pointer(0x6000, 0x1001);
|
|
Win16FarPtr window_paint = win16_make_far_pointer(0x6000, 0x1002);
|
|
Win16FarPtr horizontal = win16_make_far_pointer(0x6000, 0x2000);
|
|
Win16FarPtr vertical = win16_make_far_pointer(0x6000, 0x2001);
|
|
Win16FarPtr before_paint = win16_make_far_pointer(0x6000, 0x2002);
|
|
Win16FarPtr after_paint = win16_make_far_pointer(0x6000, 0x2003);
|
|
Win16FarPtr resize = win16_make_far_pointer(0x6000, 0x2004);
|
|
Win16FarPtr mouse = win16_make_far_pointer(0x6000, 0x2005);
|
|
write_far(win16_dgroup_pointer(0x0400), 0x0c, default_proc);
|
|
write_far(win16_dgroup_pointer(0x0400), 0x48, fallback_scroll);
|
|
write_far(win16_dgroup_pointer(0x0400), 0x4c, window_paint);
|
|
write_far(win16_dgroup_pointer(0x0500), 0x20, horizontal);
|
|
write_far(win16_dgroup_pointer(0x0500), 0x1c, vertical);
|
|
write_far(win16_dgroup_pointer(0x0500), 0x14, before_paint);
|
|
write_far(win16_dgroup_pointer(0x0500), 0x18, after_paint);
|
|
write_far(win16_dgroup_pointer(0x0500), 0x0c, resize);
|
|
write_far(win16_dgroup_pointer(0x0500), 0x24, mouse);
|
|
|
|
ObjectWindowsMessage message = {
|
|
.wparam = 7,
|
|
.lparam = 0x12345678,
|
|
};
|
|
reset_observations();
|
|
g_window_style = 0;
|
|
object_windows_wm_hscroll_attached(window, &message);
|
|
assert(g_last_procedure == fallback_scroll &&
|
|
g_last_receiver == window && g_last_message == &message);
|
|
|
|
reset_observations();
|
|
g_window_style = 0x00100000;
|
|
object_windows_wm_hscroll_attached(window, &message);
|
|
assert(g_last_procedure == horizontal && g_last_receiver == attached);
|
|
assert(g_scroll_position == 0x5678 && g_scroll_command == 7);
|
|
|
|
reset_observations();
|
|
write_far(window, 0x3b, 0);
|
|
object_windows_wm_hscroll_attached(window, &message);
|
|
assert(g_last_procedure == default_proc && g_last_receiver == window);
|
|
write_far(window, 0x3b, attached);
|
|
|
|
reset_observations();
|
|
g_window_style = 0x00200000;
|
|
object_windows_wm_vscroll_attached(window, &message);
|
|
assert(g_last_procedure == vertical && g_last_receiver == attached);
|
|
|
|
reset_observations();
|
|
g_paint_dc = 0x4444;
|
|
object_windows_wm_paint_attached(window, &message);
|
|
assert(g_sequence_count == 5);
|
|
assert(g_sequence[0] == SEQ_BEGIN_PAINT);
|
|
assert(g_sequence[1] == SEQ_PAINT);
|
|
assert(g_sequence[2] == SEQ_PAINT);
|
|
assert(g_sequence[3] == SEQ_METHOD);
|
|
assert(g_sequence[4] == SEQ_END_PAINT);
|
|
assert(g_last_procedure == after_paint && g_last_receiver == attached);
|
|
|
|
reset_observations();
|
|
g_window_rectangle = (RECT16){10, 20, 70, 100};
|
|
message.wparam = 0;
|
|
object_windows_wm_size_attached(window, &message);
|
|
assert(g_sequence[0] == SEQ_METHOD);
|
|
assert(g_sequence[1] == SEQ_GET_RECT);
|
|
assert(g_sequence[2] == SEQ_MESSAGE);
|
|
assert(win16_read_u16(win16_far_add_offset(window, 0x2d)) == 60);
|
|
assert(win16_read_u16(win16_far_add_offset(window, 0x2f)) == 80);
|
|
|
|
reset_observations();
|
|
message.wparam = 1;
|
|
object_windows_wm_size_attached(window, &message);
|
|
assert(g_sequence_count == 1 && g_sequence[0] == SEQ_MESSAGE);
|
|
|
|
reset_observations();
|
|
win16_write_u8(win16_far_add_offset(attached, 0x22), 1);
|
|
g_queued_messages[0].message = 0x0200;
|
|
g_queued_messages[1].message = 0x0202;
|
|
g_queued_count = 2;
|
|
object_windows_track_mouse_until_button_up(window, &message);
|
|
assert(g_capture_window == 0x1234 && g_release_calls == 1);
|
|
assert(g_translate_calls == 2 && g_dispatch_calls == 2);
|
|
assert(g_mouse_calls == 2);
|
|
assert(g_sequence[g_sequence_count - 1] == SEQ_MESSAGE);
|
|
|
|
reset_observations();
|
|
win16_set_indeterminate_u16(0x0202);
|
|
object_windows_track_mouse_until_button_up(window, &message);
|
|
assert(g_mouse_calls == 1 && g_release_calls == 1);
|
|
|
|
reset_observations();
|
|
win16_write_u8(win16_far_add_offset(attached, 0x22), 0);
|
|
object_windows_track_mouse_until_button_up(window, &message);
|
|
assert(g_capture_window == 0x1234);
|
|
assert(g_mouse_calls == 0 && g_release_calls == 0);
|
|
assert(g_sequence_count == 1 && g_sequence[0] == SEQ_MESSAGE);
|
|
return 0;
|
|
}
|