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
798 lines
26 KiB
C
798 lines
26 KiB
C
/* ObjectWindows dynamic handlers from message table 1028:05cc. */
|
|
|
|
#include "tdkpin_window_messages.h"
|
|
#include "tdkpin_object_list.h"
|
|
|
|
enum {
|
|
OBJECT_VMT_OFFSET = 0,
|
|
OBJECT_STATUS_OFFSET = 2,
|
|
OBJECT_WINDOW_HANDLE_OFFSET = 4,
|
|
OBJECT_FLAGS_OFFSET = 0x16,
|
|
OBJECT_PARENT_OFFSET = 6,
|
|
WINDOW_DEFAULT_HANDLER_SLOT = 0x0c,
|
|
WINDOW_MESSAGE_0014_SLOT = 0x10,
|
|
WINDOW_CAN_CLOSE_SLOT = 0x3c,
|
|
WINDOW_SCROLL_HANDLER_SLOT = 0x48,
|
|
APPLICATION_MAIN_WINDOW_OFFSET = 8,
|
|
APPLICATION_CAN_CLOSE_SLOT = 0x44,
|
|
WIN16_GWL_STYLE = -16,
|
|
WIN16_WS_HSCROLL_HIGH = 0x0010,
|
|
WIN16_WS_VSCROLL_HIGH = 0x0020,
|
|
WIN16_WM_GETDLGCODE = 0x0087,
|
|
WIN16_WM_COMMAND = 0x0111,
|
|
WIN16_DLGC_BUTTON_MASK = 0x0030,
|
|
WIN16_GWW_ID = -12,
|
|
DGROUP_TURBO_WINDOW_CLASS_NAME = 0x068c,
|
|
CHILD_WINDOWED_CALLBACK_OFFSET = 0x0cc7,
|
|
WINDOW_MDI_CLIENT_SLOT = 0x30,
|
|
WIN16_WM_MDIDESTROY = 0x0221,
|
|
WINDOW_SAVED_FOCUS_OFFSET = 0x3f,
|
|
WINDOW_ATTACHED_OBJECT_OFFSET = 0x3b,
|
|
WINDOW_WIDTH_OFFSET = 0x2d,
|
|
WINDOW_HEIGHT_OFFSET = 0x2f,
|
|
WIN16_WM_LBUTTONUP = 0x0202,
|
|
};
|
|
|
|
static Win16FarPtr object_vmt_procedure(
|
|
Win16FarPtr object, uint16_t slot)
|
|
{
|
|
uint16_t vmt = win16_read_u16(
|
|
win16_far_add_offset(object, OBJECT_VMT_OFFSET));
|
|
return win16_read_far_pointer(win16_dgroup_pointer(vmt), slot);
|
|
}
|
|
|
|
static Win16FarPtr application_main_window(void)
|
|
{
|
|
return win16_read_far_pointer(
|
|
g_object_windows_application, APPLICATION_MAIN_WINDOW_OFFSET);
|
|
}
|
|
|
|
static void call_default_handler(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
win16_call_object_message_handler(
|
|
object_vmt_procedure(window, WINDOW_DEFAULT_HANDLER_SLOT),
|
|
window,
|
|
message);
|
|
}
|
|
|
|
static Win16FarPtr attached_object(Win16FarPtr window)
|
|
{
|
|
return win16_read_far_pointer(window, WINDOW_ATTACHED_OBJECT_OFFSET);
|
|
}
|
|
|
|
static void dispatch_attached_scroll(
|
|
Win16FarPtr window,
|
|
ObjectWindowsMessage *message,
|
|
uint32_t required_style,
|
|
uint16_t attached_slot)
|
|
{
|
|
HWND16 handle = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
uint32_t style = (uint32_t)GetWindowLong16(handle, WIN16_GWL_STYLE);
|
|
if ((style & required_style) == 0) {
|
|
win16_call_object_message_handler(
|
|
object_vmt_procedure(window, WINDOW_SCROLL_HANDLER_SLOT),
|
|
window,
|
|
message);
|
|
return;
|
|
}
|
|
|
|
Win16FarPtr attached = attached_object(window);
|
|
if (attached == 0) {
|
|
call_default_handler(window, message);
|
|
return;
|
|
}
|
|
win16_call_object_scroll_method(
|
|
object_vmt_procedure(attached, attached_slot),
|
|
attached,
|
|
(uint16_t)message->lparam,
|
|
message->wparam);
|
|
}
|
|
|
|
/* 1018:1788 -- horizontal scrolling with optional attached controller. */
|
|
void object_windows_wm_hscroll_attached(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
dispatch_attached_scroll(
|
|
window, message, 0x00100000u, 0x20);
|
|
}
|
|
|
|
/* 1018:17f8 -- vertical scrolling with optional attached controller. */
|
|
void object_windows_wm_vscroll_attached(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
dispatch_attached_scroll(
|
|
window, message, 0x00200000u, 0x1c);
|
|
}
|
|
|
|
/*
|
|
* 1018:1868 -- BeginPaint/EndPaint lifetime around attached +14/+18 and window
|
|
* +4c virtuals. All three receive the same 32-byte PAINTSTRUCT16 stack object.
|
|
*/
|
|
void object_windows_wm_paint_attached(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
(void)message;
|
|
PAINTSTRUCT16 paint;
|
|
HWND16 handle = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
(void)BeginPaint16(handle, win16_stack_pointer(&paint));
|
|
Win16FarPtr attached = attached_object(window);
|
|
if (attached != 0) {
|
|
win16_call_object_paint_method(
|
|
object_vmt_procedure(attached, 0x14),
|
|
attached,
|
|
&paint,
|
|
paint.dc);
|
|
}
|
|
win16_call_object_paint_method(
|
|
object_vmt_procedure(window, 0x4c),
|
|
window,
|
|
&paint,
|
|
paint.dc);
|
|
if (attached != 0) {
|
|
win16_call_object_method(
|
|
object_vmt_procedure(attached, 0x18), attached);
|
|
}
|
|
(void)EndPaint16(handle, win16_stack_pointer(&paint));
|
|
}
|
|
|
|
/* 1018:18e9 -- attached resize notification and cached outer dimensions. */
|
|
void object_windows_wm_size_attached(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
Win16FarPtr attached = attached_object(window);
|
|
if (attached != 0 && message->wparam != 1) {
|
|
win16_call_object_method(
|
|
object_vmt_procedure(attached, 0x0c), attached);
|
|
}
|
|
if (message->wparam == 0) {
|
|
RECT16 rectangle;
|
|
HWND16 handle = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
(void)GetWindowRect16(handle, win16_stack_pointer(&rectangle));
|
|
win16_write_u16(
|
|
window,
|
|
WINDOW_WIDTH_OFFSET,
|
|
(uint16_t)(rectangle.right - rectangle.left));
|
|
win16_write_u16(
|
|
window,
|
|
WINDOW_HEIGHT_OFFSET,
|
|
(uint16_t)(rectangle.bottom - rectangle.top));
|
|
}
|
|
call_default_handler(window, message);
|
|
}
|
|
|
|
/*
|
|
* 1018:1986 -- attached mouse tracking. The original keeps the last/unfilled
|
|
* MSG contents when PeekMessage is false, so the initial message id is made an
|
|
* explicit indeterminate word instead of invoking undefined host-C behavior.
|
|
*/
|
|
void object_windows_track_mouse_until_button_up(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
Win16FarPtr attached = attached_object(window);
|
|
if (attached != 0 &&
|
|
win16_read_u8(win16_far_add_offset(attached, 0x22)) != 0) {
|
|
HWND16 handle = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
(void)SetCapture16(handle);
|
|
MSG16 queued = {.message = win16_indeterminate_u16()};
|
|
do {
|
|
if (PeekMessage16(&queued, 0, 0, 0, 1) != 0) {
|
|
(void)TranslateMessage16(&queued);
|
|
(void)DispatchMessage16(&queued);
|
|
}
|
|
win16_call_object_u16_method(
|
|
object_vmt_procedure(attached, 0x24),
|
|
attached,
|
|
handle);
|
|
} while (queued.message != WIN16_WM_LBUTTONUP);
|
|
(void)ReleaseCapture16();
|
|
}
|
|
call_default_handler(window, message);
|
|
}
|
|
|
|
/* 1018:0673 — AL=1 exactly when every requested bit is set at object +0x16. */
|
|
bool object_windows_has_flags(Win16FarPtr object, uint8_t mask)
|
|
{
|
|
uint8_t flags = win16_read_u8(
|
|
win16_far_add_offset(object, OBJECT_FLAGS_OFFSET));
|
|
return (flags & mask) == mask;
|
|
}
|
|
|
|
/* 1018:05dc — inherited virtual default returning AX=0. */
|
|
uint16_t object_windows_zero_word_default(Win16FarPtr object)
|
|
{
|
|
(void)object;
|
|
return 0;
|
|
}
|
|
|
|
/* 1018:0641 — set or clear a mask in the packed object flag byte at +0x16. */
|
|
void object_windows_update_flags(
|
|
Win16FarPtr object, bool set, uint8_t mask)
|
|
{
|
|
Win16FarPtr address =
|
|
win16_far_add_offset(object, OBJECT_FLAGS_OFFSET);
|
|
uint8_t flags = win16_read_u8(address);
|
|
win16_write_u8(address, set ? (uint8_t)(flags | mask)
|
|
: (uint8_t)(flags & (uint8_t)~mask));
|
|
}
|
|
|
|
/* 1018:05f3, 060d, 0627 — fixed-mask compiler wrappers. */
|
|
void object_windows_set_flag_1(Win16FarPtr object)
|
|
{
|
|
object_windows_update_flags(object, true, 1);
|
|
}
|
|
|
|
void object_windows_set_flag_4(Win16FarPtr object)
|
|
{
|
|
object_windows_update_flags(object, true, 4);
|
|
}
|
|
|
|
void object_windows_clear_flag_4(Win16FarPtr object)
|
|
{
|
|
object_windows_update_flags(object, false, 4);
|
|
}
|
|
|
|
/* 1018:0f38 — ask the appropriate CanClose virtual and dispose on approval. */
|
|
void object_windows_close_if_allowed(Win16FarPtr window)
|
|
{
|
|
bool allowed;
|
|
if (window == application_main_window()) {
|
|
allowed = win16_call_object_bool_method(
|
|
object_vmt_procedure(
|
|
g_object_windows_application, APPLICATION_CAN_CLOSE_SLOT),
|
|
g_object_windows_application);
|
|
} else {
|
|
allowed = win16_call_object_bool_method(
|
|
object_vmt_procedure(window, WINDOW_CAN_CLOSE_SLOT), window);
|
|
}
|
|
if (allowed) {
|
|
borland_dispose_object(window);
|
|
}
|
|
}
|
|
|
|
/* 1018:0f22 — dynamic id 0x0010 (WM_CLOSE). */
|
|
void object_windows_wm_close(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
(void)message;
|
|
object_windows_close_if_allowed(window);
|
|
}
|
|
|
|
/* 1018:0f8d — dynamic id 0x0002 (WM_DESTROY). */
|
|
void object_windows_wm_destroy(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
if (window == application_main_window()) {
|
|
PostQuitMessage16(win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET)));
|
|
}
|
|
call_default_handler(window, message);
|
|
}
|
|
|
|
/* 1018:0fcc — dynamic id 0x0082 (WM_NCDESTROY). */
|
|
void object_windows_wm_nc_destroy(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
HWND16 handle = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
object_windows_unbind_window(handle);
|
|
call_default_handler(window, message);
|
|
win16_write_u16(window, OBJECT_WINDOW_HANDLE_OFFSET, 0);
|
|
}
|
|
|
|
/* 1018:0ffd — dynamic id 0x0006 (WM_ACTIVATE). */
|
|
void object_windows_wm_activate(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
call_default_handler(window, message);
|
|
if (message->wparam == 0) {
|
|
return;
|
|
}
|
|
Win16FarPtr active =
|
|
object_windows_has_flags(window, 1) ? window : 0;
|
|
object_windows_application_set_active_dialog(
|
|
g_object_windows_application, active);
|
|
}
|
|
|
|
/* 1018:1054 — dynamic id 0x0011 (WM_QUERYENDSESSION). */
|
|
void object_windows_wm_query_end_session(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
bool allowed;
|
|
if (window == application_main_window()) {
|
|
allowed = win16_call_object_bool_method(
|
|
object_vmt_procedure(
|
|
g_object_windows_application, APPLICATION_CAN_CLOSE_SLOT),
|
|
g_object_windows_application);
|
|
} else {
|
|
allowed = win16_call_object_bool_method(
|
|
object_vmt_procedure(window, WINDOW_CAN_CLOSE_SLOT), window);
|
|
}
|
|
message->result = allowed ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
* 1018:10aa — dynamic id 0x0014. The numeric id and exact behavior are kept
|
|
* explicit because a stronger source-level OWL method name is not encoded.
|
|
*/
|
|
void object_windows_message_0014(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
if (window == application_main_window()) {
|
|
object_windows_close_if_allowed(window);
|
|
return;
|
|
}
|
|
win16_call_object_message_handler(
|
|
object_vmt_procedure(window, WINDOW_MESSAGE_0014_SLOT),
|
|
window,
|
|
message);
|
|
}
|
|
|
|
static void dispatch_scroll_message(
|
|
Win16FarPtr window,
|
|
ObjectWindowsMessage *message,
|
|
uint16_t style_high_mask)
|
|
{
|
|
uint32_t style = (uint32_t)GetWindowLong16(
|
|
win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET)),
|
|
WIN16_GWL_STYLE);
|
|
uint16_t style_high = (uint16_t)(style >> 16);
|
|
uint16_t slot = (style_high & style_high_mask) == 0
|
|
? WINDOW_SCROLL_HANDLER_SLOT
|
|
: WINDOW_DEFAULT_HANDLER_SLOT;
|
|
win16_call_object_message_handler(
|
|
object_vmt_procedure(window, slot), window, message);
|
|
}
|
|
|
|
/* 1018:0b6c — dynamic id 0x0114 (WM_HSCROLL). */
|
|
void object_windows_wm_hscroll(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
dispatch_scroll_message(
|
|
window, message, WIN16_WS_HSCROLL_HIGH);
|
|
}
|
|
|
|
/* 1018:0b25 — dynamic id 0x0115 (WM_VSCROLL). */
|
|
void object_windows_wm_vscroll(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
dispatch_scroll_message(
|
|
window, message, WIN16_WS_VSCROLL_HIGH);
|
|
}
|
|
|
|
/*
|
|
* 1018:08f0 — dynamic id 0x0111 (WM_COMMAND).
|
|
*
|
|
* Win16 encodes the command id in WPARAM, a control HWND in LOWORD(LPARAM),
|
|
* and the notification in HIWORD(LPARAM). ObjectWindows maps three numeric
|
|
* bands into dynamic ids by 16-bit subtraction: command-0x6000,
|
|
* control-0x8000, and notification-0x7000.
|
|
*/
|
|
void object_windows_wm_command(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
uint16_t control_window = (uint16_t)message->lparam;
|
|
uint16_t notification = (uint16_t)((uint32_t)message->lparam >> 16);
|
|
|
|
if (object_windows_has_flags(window, 1) &&
|
|
control_window == 0 && notification == 0) {
|
|
HWND16 dialog = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
HWND16 control = GetDlgItem16(dialog, (INT16)message->wparam);
|
|
if (control != 0 &&
|
|
(((uint16_t)SendMessage16(
|
|
control, WIN16_WM_GETDLGCODE, 0, 0) &
|
|
WIN16_DLGC_BUTTON_MASK) != 0)) {
|
|
control_window = control;
|
|
message->lparam = (LPARAM16)control;
|
|
}
|
|
}
|
|
|
|
if (control_window == 0) {
|
|
if (message->wparam < 0x6000) {
|
|
HWND16 focus = GetFocus16();
|
|
Win16FarPtr target = object_windows_object_from_window(focus);
|
|
HWND16 owner = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
while (target == 0 && focus != 0 && focus != owner) {
|
|
focus = GetParent16(focus);
|
|
target = object_windows_object_from_window(focus);
|
|
}
|
|
if (target == 0) {
|
|
target = window;
|
|
}
|
|
object_windows_dispatch_event(
|
|
0x10,
|
|
(uint16_t)(message->wparam - 0x6000u),
|
|
win16_stack_pointer(message),
|
|
target);
|
|
return;
|
|
}
|
|
call_default_handler(window, message);
|
|
return;
|
|
}
|
|
|
|
HWND16 owner = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
HWND16 child_window = GetDlgItem16(owner, (INT16)message->wparam);
|
|
Win16FarPtr child = object_windows_object_from_window(child_window);
|
|
if (child != 0 && notification < 0x1000) {
|
|
object_windows_dispatch_event(
|
|
0x18,
|
|
(uint16_t)(notification - 0x7000u),
|
|
win16_stack_pointer(message),
|
|
child);
|
|
return;
|
|
}
|
|
|
|
if (message->wparam < 0x1000) {
|
|
object_windows_dispatch_event(
|
|
0x14,
|
|
(uint16_t)(message->wparam - 0x8000u),
|
|
win16_stack_pointer(message),
|
|
window);
|
|
return;
|
|
}
|
|
win16_call_object_message_handler(
|
|
object_vmt_procedure(window, 0x14), window, message);
|
|
}
|
|
|
|
/* 1018:0d6a — shared TWindow VMT +0x2c class-name provider. */
|
|
Win16FarPtr object_windows_turbo_window_class_name(Win16FarPtr window)
|
|
{
|
|
(void)window;
|
|
return win16_dgroup_pointer(DGROUP_TURBO_WINDOW_CLASS_NAME);
|
|
}
|
|
|
|
/*
|
|
* 1018:0a85 — VMT +0x48 shared by WM_HSCROLL/WM_VSCROLL.
|
|
* HIWORD(LPARAM) identifies the control window. Bound controls dispatch their
|
|
* notification as id-0x7000; native controls use GWW_ID and id-0x8000.
|
|
*/
|
|
void object_windows_route_scroll_notification(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
HWND16 control = (HWND16)((uint32_t)message->lparam >> 16);
|
|
if (control == 0) {
|
|
call_default_handler(window, message);
|
|
return;
|
|
}
|
|
|
|
Win16FarPtr child = object_windows_object_from_window(control);
|
|
if (child != 0) {
|
|
object_windows_dispatch_event(
|
|
0x18,
|
|
(uint16_t)(message->wparam - 0x7000u),
|
|
win16_stack_pointer(message),
|
|
child);
|
|
return;
|
|
}
|
|
|
|
uint16_t control_id = GetWindowWord16(control, WIN16_GWW_ID);
|
|
if (control_id < 0x1000) {
|
|
object_windows_dispatch_event(
|
|
0x14,
|
|
(uint16_t)(control_id - 0x8000u),
|
|
win16_stack_pointer(message),
|
|
window);
|
|
return;
|
|
}
|
|
win16_call_object_message_handler(
|
|
object_vmt_procedure(window, 0x14), window, message);
|
|
}
|
|
|
|
/*
|
|
* 1018:0bb3 — select a command target from the event HWND, explicit parent
|
|
* object (+6/+8), or HWND property lookup. A missing/self target falls back to
|
|
* the current window's VMT +0x0c; otherwise id WPARAM-0x6000 is dispatched.
|
|
*/
|
|
void object_windows_route_command_target(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
Win16FarPtr target = 0;
|
|
HWND16 own_window = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
if (message->window != own_window) {
|
|
target = win16_read_far_pointer(window, OBJECT_PARENT_OFFSET);
|
|
if (target == 0) {
|
|
target = object_windows_object_from_window(message->window);
|
|
}
|
|
}
|
|
if (target == 0) {
|
|
call_default_handler(window, message);
|
|
return;
|
|
}
|
|
object_windows_dispatch_event(
|
|
0x10,
|
|
(uint16_t)(message->wparam - 0x6000u),
|
|
win16_stack_pointer(message),
|
|
target);
|
|
}
|
|
|
|
/*
|
|
* 1018:0c59 — forward to the explicit parent object. WM_COMMAND uses WPARAM;
|
|
* every other message derives the dynamic id from this window's GWW_ID.
|
|
*/
|
|
void object_windows_forward_event_to_parent(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
Win16FarPtr parent =
|
|
win16_read_far_pointer(window, OBJECT_PARENT_OFFSET);
|
|
if (parent == 0) {
|
|
return;
|
|
}
|
|
uint16_t id = message->message == WIN16_WM_COMMAND
|
|
? message->wparam
|
|
: GetWindowWord16(
|
|
win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET)),
|
|
WIN16_GWW_ID);
|
|
object_windows_dispatch_event(
|
|
0x14,
|
|
(uint16_t)(id - 0x8000u),
|
|
win16_stack_pointer(message),
|
|
parent);
|
|
}
|
|
|
|
/*
|
|
* 1018:0ce7 — mark all windowed children, then destroy the native HWND.
|
|
* Flag 8 selects MDI destruction: the parent VMT +0x30 getter is deliberately
|
|
* called twice, and the second returned client HWND receives WM_MDIDESTROY.
|
|
*/
|
|
void object_windows_destroy_native_window(Win16FarPtr window)
|
|
{
|
|
HWND16 handle = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
if (handle == 0) {
|
|
return;
|
|
}
|
|
object_windows_for_each_child(
|
|
window,
|
|
win16_relocated_code_pointer(4, CHILD_WINDOWED_CALLBACK_OFFSET));
|
|
if (object_windows_has_flags(window, 8)) {
|
|
Win16FarPtr parent =
|
|
win16_read_far_pointer(window, OBJECT_PARENT_OFFSET);
|
|
uint16_t parent_vmt = win16_read_u16(parent);
|
|
Win16FarPtr getter = win16_read_far_pointer(
|
|
win16_dgroup_pointer(parent_vmt), WINDOW_MDI_CLIENT_SLOT);
|
|
if (win16_call_object_far_method(getter, parent) != 0) {
|
|
Win16FarPtr client =
|
|
win16_call_object_far_method(getter, parent);
|
|
HWND16 client_window = win16_read_u16(win16_far_add_offset(
|
|
client, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
(void)SendMessage16(
|
|
client_window, WIN16_WM_MDIDESTROY, handle, 0);
|
|
return;
|
|
}
|
|
}
|
|
(void)DestroyWindow16(handle);
|
|
}
|
|
|
|
/*
|
|
* 1018:0e46 — register an ObjectWindows class only when GetClassInfo cannot
|
|
* find it. VMT +0x2c returns the far class name and +0x34 fills WNDCLASS16.
|
|
*/
|
|
bool object_windows_register_class(Win16FarPtr window)
|
|
{
|
|
uint16_t vmt = win16_read_u16(window);
|
|
Win16FarPtr class_name_proc =
|
|
win16_read_far_pointer(win16_dgroup_pointer(vmt), 0x2c);
|
|
Win16FarPtr class_name =
|
|
win16_call_object_far_method(class_name_proc, window);
|
|
WNDCLASS16 window_class;
|
|
if (GetClassInfo16(
|
|
g_win16_instance, class_name, &window_class) != 0) {
|
|
return true;
|
|
}
|
|
Win16FarPtr builder =
|
|
win16_read_far_pointer(win16_dgroup_pointer(vmt), 0x34);
|
|
win16_call_object_wndclass_method(builder, window, &window_class);
|
|
return RegisterClass16(&window_class) != 0;
|
|
}
|
|
|
|
/* 1018:1274 — construct the shared ObjectWindows WNDCLASS16 descriptor. */
|
|
void object_windows_build_window_class(
|
|
Win16FarPtr window, WNDCLASS16 *window_class)
|
|
{
|
|
window_class->style = 3;
|
|
window_class->window_proc = win16_relocated_code_pointer(4, 0x018b);
|
|
window_class->class_extra_bytes = 0;
|
|
window_class->window_extra_bytes = 0;
|
|
window_class->instance = g_win16_instance;
|
|
window_class->icon =
|
|
LoadIcon16(0, win16_make_far_pointer(0, 0x7f00));
|
|
window_class->cursor =
|
|
LoadCursor16(0, win16_make_far_pointer(0, 0x7f00));
|
|
window_class->background_brush = 6;
|
|
window_class->menu_name = 0;
|
|
uint16_t vmt = win16_read_u16(window);
|
|
Win16FarPtr class_name_proc =
|
|
win16_read_far_pointer(win16_dgroup_pointer(vmt), 0x2c);
|
|
window_class->class_name =
|
|
win16_call_object_far_method(class_name_proc, window);
|
|
}
|
|
|
|
/* 1018:12f5 — unaligned uint16 virtual field getter at object +0x35. */
|
|
uint16_t object_windows_get_field_35(Win16FarPtr window)
|
|
{
|
|
return win16_read_u16(win16_far_add_offset(window, 0x35));
|
|
}
|
|
|
|
/* 1018:1586 — remember focus only when it is a child of this native HWND. */
|
|
void object_windows_remember_child_focus(Win16FarPtr window)
|
|
{
|
|
HWND16 focus = GetFocus16();
|
|
if (focus == 0) {
|
|
return;
|
|
}
|
|
HWND16 parent = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
if (IsChild16(parent, focus) != 0) {
|
|
win16_write_u16(window, WINDOW_SAVED_FOCUS_OFFSET, focus);
|
|
}
|
|
}
|
|
|
|
/* 1018:1547 — restore a saved child focus when both HWNDs remain suitable. */
|
|
void object_windows_restore_child_focus(Win16FarPtr window)
|
|
{
|
|
HWND16 saved = win16_read_u16(win16_far_add_offset(
|
|
window, WINDOW_SAVED_FOCUS_OFFSET));
|
|
if (saved == 0 || IsWindow16(saved) == 0) {
|
|
return;
|
|
}
|
|
HWND16 owner = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
if (IsIconic16(owner) == 0) {
|
|
(void)SetFocus16(saved);
|
|
}
|
|
}
|
|
|
|
/* 1018:169d — base WM_ACTIVATE behavior plus dialog focus save/restore. */
|
|
void object_windows_wm_activate_with_focus(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
object_windows_wm_activate(window, message);
|
|
if (!object_windows_has_flags(window, 1)) {
|
|
return;
|
|
}
|
|
if (message->wparam == 0) {
|
|
object_windows_remember_child_focus(window);
|
|
} else {
|
|
object_windows_restore_child_focus(window);
|
|
}
|
|
}
|
|
|
|
/* 1018:1a0e — SC_MINIMIZE/SC_RESTORE focus handling before default dispatch. */
|
|
void object_windows_wm_syscommand_focus(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
if (object_windows_has_flags(window, 1)) {
|
|
if (message->wparam == 0xf020) {
|
|
object_windows_remember_child_focus(window);
|
|
} else if (message->wparam == 0xf120) {
|
|
object_windows_restore_child_focus(window);
|
|
}
|
|
}
|
|
call_default_handler(window, message);
|
|
}
|
|
|
|
/* 1018:1761 — receiver-only VMT +0x38 hook, then default event handler. */
|
|
void object_windows_call_slot_38_then_default(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
win16_call_object_method(
|
|
object_vmt_procedure(window, 0x38), window);
|
|
call_default_handler(window, message);
|
|
}
|
|
|
|
/* 1018:1960 — save child focus before forwarding the unchanged event. */
|
|
void object_windows_remember_focus_then_default(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
object_windows_remember_child_focus(window);
|
|
call_default_handler(window, message);
|
|
}
|
|
|
|
/*
|
|
* 1018:1311 — forward through the original far WNDPROC stored unaligned at
|
|
* object +0x37/+0x39, then publish DX:AX into message result +0x0a/+0x0c.
|
|
*/
|
|
void object_windows_call_original_window_proc(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
Win16FarPtr procedure = win16_read_far_pointer(window, 0x37);
|
|
HWND16 handle = win16_read_u16(win16_far_add_offset(
|
|
window, OBJECT_WINDOW_HANDLE_OFFSET));
|
|
message->result = CallWindowProc16(
|
|
procedure,
|
|
handle,
|
|
message->message,
|
|
message->wparam,
|
|
message->lparam);
|
|
}
|
|
|
|
/* 1008:2c08 — receiver-only VMT +0x38 call; event argument is ignored. */
|
|
void object_windows_call_slot_38(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
(void)message;
|
|
win16_call_object_method(
|
|
object_vmt_procedure(window, 0x38), window);
|
|
}
|
|
|
|
/* 1008:2cd9 — dialog default handler: set the 32-bit result to zero. */
|
|
void object_windows_zero_message_result(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
(void)window;
|
|
message->result = 0;
|
|
}
|
|
|
|
/*
|
|
* 1008:2c1f -- query whether session termination must be rejected. The main
|
|
* window delegates to TApplication.CanClose at VMT +44; other windows use
|
|
* their own CanClose at +3c. The message result is the exact logical inverse.
|
|
*/
|
|
void object_windows_query_end_session_result(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
Win16FarPtr receiver = window;
|
|
uint16_t slot = 0x3c;
|
|
if (window == win16_read_far_pointer(
|
|
g_object_windows_application, 8)) {
|
|
receiver = g_object_windows_application;
|
|
slot = 0x44;
|
|
}
|
|
uint16_t vmt = win16_read_u16(receiver);
|
|
Win16FarPtr procedure =
|
|
win16_read_far_pointer(win16_dgroup_pointer(vmt), slot);
|
|
bool can_close = win16_call_object_bool_method(procedure, receiver);
|
|
message->result = can_close ? 0 : 1;
|
|
}
|
|
|
|
/*
|
|
* 1008:2c83 -- focus the HWND in message.wParam, recover its ObjectWindows
|
|
* object, and invoke VMT +0c on the optional unaligned far child at +0x43.
|
|
* The process marker is set on every path and has no reader in this image.
|
|
*/
|
|
void object_windows_focus_message(
|
|
Win16FarPtr ignored, ObjectWindowsMessage *message)
|
|
{
|
|
(void)ignored;
|
|
(void)SetFocus16(message->wparam);
|
|
Win16FarPtr window = object_windows_object_from_window(message->wparam);
|
|
if (window != 0) {
|
|
Win16FarPtr attached = win16_read_far_pointer(window, 0x43);
|
|
if (attached != 0) {
|
|
uint16_t vmt = win16_read_u16(attached);
|
|
Win16FarPtr procedure =
|
|
win16_read_far_pointer(win16_dgroup_pointer(vmt), 0x0c);
|
|
win16_call_object_method(procedure, attached);
|
|
}
|
|
}
|
|
g_object_windows_focus_event_marker = 1;
|
|
}
|
|
|
|
/* 1018:0c3d — generated receiver/event forwarding call to VMT +0x0c. */
|
|
void object_windows_forward_default(
|
|
Win16FarPtr window, ObjectWindowsMessage *message)
|
|
{
|
|
call_default_handler(window, message);
|
|
}
|
|
|
|
/* 1018:0cc7 — set object flag 4 only after field +4 becomes nonzero. */
|
|
void object_windows_set_flag_4_if_windowed(
|
|
uint16_t ignored, Win16FarPtr object)
|
|
{
|
|
(void)ignored;
|
|
if (win16_read_u16(win16_far_add_offset(
|
|
object, OBJECT_WINDOW_HANDLE_OFFSET)) != 0) {
|
|
object_windows_set_flag_4(object);
|
|
}
|
|
}
|