/* ObjectWindows native-window setup and normal-placement bookkeeping. */ #include "tdkpin_window_placement.h" #include "tdkpin_strings.h" #include "tdkpin_object_list.h" #include "tdkpin_object_lifecycle.h" enum { WINDOW_VMT_OFFSET = 0, WINDOW_HANDLE_OFFSET = 4, WINDOW_PARENT_OFFSET = 6, WINDOW_FLAGS_OFFSET = 0x16, WINDOW_ATTRIBUTES_OFFSET = 0x21, WINDOW_NORMAL_X_OFFSET = 0x29, WINDOW_NORMAL_Y_OFFSET = 0x2b, WINDOW_NORMAL_WIDTH_OFFSET = 0x2d, WINDOW_NORMAL_HEIGHT_OFFSET = 0x2f, WINDOW_ATTACHED_OBJECT_OFFSET = 0x3b, VMT_SETUP_SLOT = 0x10, VMT_MDI_CLIENT_SLOT = 0x30, WINDOW_FLAG_AUTO_FOCUS = 0x08, WINDOW_FLAG_DIALOG_ITEM = 0x02, WINDOW_TITLE_OFFSET = 0x1d, WINDOW_STYLE_OFFSET = 0x21, WINDOW_EXTENDED_STYLE_OFFSET = 0x25, WINDOW_X_OFFSET = 0x29, WINDOW_Y_OFFSET = 0x2b, WINDOW_WIDTH_OFFSET = 0x2d, WINDOW_HEIGHT_OFFSET = 0x2f, WINDOW_PARAMETER_OFFSET = 0x31, WINDOW_MENU_OFFSET = 0x35, WINDOW_ORIGINAL_PROC_OFFSET = 0x37, WINDOW_ATTACHED_OFFSET = 0x3b, WINDOW_SAVED_FOCUS_OFFSET = 0x3f, WINDOW_REGISTER_CLASS_SLOT = 0x1c, WINDOW_CLASS_NAME_SLOT = 0x2c, WINDOW_CREATED_SLOT = 0x38, PARENT_MDI_CLIENT_SLOT = 0x30, }; 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 Win16FarPtr vmt_procedure(Win16FarPtr object, uint16_t slot) { return win16_read_far_pointer( win16_dgroup_pointer(win16_read_u16(object)), slot); } /* 1018:1106 -- construct the complete ObjectWindows TWindow state. */ Win16FarPtr object_windows_window_construct( Win16FarPtr window, uint16_t vmt, Win16FarPtr title, Win16FarPtr parent) { BorlandObjectCallFrame frame = {window, vmt}; if (!borland_enter_object_constructor(&frame, 0)) { return frame.object; } frame.object = object_windows_object_construct(frame.object, 0, parent); write_far(frame.object, WINDOW_TITLE_OFFSET, borland_far_strdup(title)); write_far( frame.object, WINDOW_ORIGINAL_PROC_OFFSET, win16_def_window_proc_pointer()); uint32_t style; if (parent == 0) { style = 0x00cf0000u; } else { Win16FarPtr mdi_client = win16_call_object_far_method( vmt_procedure(parent, PARENT_MDI_CLIENT_SLOT), parent); if (mdi_client == 0) { style = 0x10000000u; } else { object_windows_update_flags(frame.object, true, 8); write_far( frame.object, WINDOW_ORIGINAL_PROC_OFFSET, win16_def_mdi_child_proc_pointer()); style = 0x04000000u; } } win16_write_u32(frame.object, WINDOW_STYLE_OFFSET, style); win16_write_u32(frame.object, WINDOW_EXTENDED_STYLE_OFFSET, 0); win16_write_u16(frame.object, WINDOW_X_OFFSET, 0x8000); win16_write_u16(frame.object, WINDOW_Y_OFFSET, 0); win16_write_u16(frame.object, WINDOW_WIDTH_OFFSET, 0x8000); win16_write_u16(frame.object, WINDOW_HEIGHT_OFFSET, 0); write_far(frame.object, WINDOW_PARAMETER_OFFSET, 0); win16_write_u16(frame.object, WINDOW_MENU_OFFSET, 0); write_far(frame.object, WINDOW_ATTACHED_OFFSET, 0); win16_write_u16(frame.object, WINDOW_SAVED_FOCUS_OFFSET, 0); return frame.object; } /* 1018:134f -- create or attach the native HWND represented by one TWindow. */ uint16_t object_windows_create_native_window(Win16FarPtr window) { if (win16_read_u16(win16_far_add_offset(window, 2)) != 0) { return (win16_indeterminate_u16() & 0xff00u); } object_windows_clear_flag_4(window); Win16FarPtr parent = win16_read_far_pointer(window, 6); HWND16 parent_window = parent == 0 ? 0 : win16_read_u16(win16_far_add_offset(parent, 4)); HWND16 created = 0; if (object_windows_has_flags(window, WINDOW_FLAG_DIALOG_ITEM)) { created = GetDlgItem16( parent_window, (INT16)win16_read_u16(win16_far_add_offset( window, WINDOW_MENU_OFFSET))); } else { bool registered = win16_call_object_bool_method( vmt_procedure(window, WINDOW_REGISTER_CLASS_SLOT), window); if (!registered) { created = win16_indeterminate_u16() & 0xff00u; } else { g_object_windows_creating_object = window; Win16FarPtr class_name = win16_call_object_far_method( vmt_procedure(window, WINDOW_CLASS_NAME_SLOT), window); if (!object_windows_has_flags(window, WINDOW_FLAG_AUTO_FOCUS)) { created = CreateWindowEx16( win16_read_u32(win16_far_add_offset( window, WINDOW_EXTENDED_STYLE_OFFSET)), class_name, win16_read_far_pointer(window, WINDOW_TITLE_OFFSET), win16_read_u32(win16_far_add_offset(window, WINDOW_STYLE_OFFSET)), (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_X_OFFSET)), (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_Y_OFFSET)), (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_WIDTH_OFFSET)), (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_HEIGHT_OFFSET)), parent_window, win16_read_u16(win16_far_add_offset(window, WINDOW_MENU_OFFSET)), g_win16_instance, win16_read_far_pointer(window, WINDOW_PARAMETER_OFFSET)); } else { Win16FarPtr mdi_client = win16_call_object_far_method( vmt_procedure(parent, PARENT_MDI_CLIENT_SLOT), parent); if (mdi_client != 0) { MDICREATESTRUCT16 create = { .class_name = class_name, .title = win16_read_far_pointer(window, WINDOW_TITLE_OFFSET), .owner = g_win16_instance, .x = (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_X_OFFSET)), .y = (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_Y_OFFSET)), .width = (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_WIDTH_OFFSET)), .height = (INT16)win16_read_u16(win16_far_add_offset(window, WINDOW_HEIGHT_OFFSET)), .style = win16_read_u32(win16_far_add_offset(window, WINDOW_STYLE_OFFSET)), .parameter = (LPARAM16)win16_read_far_pointer(window, WINDOW_PARAMETER_OFFSET), }; HWND16 client_window = win16_read_u16( win16_far_add_offset(mdi_client, 4)); created = (HWND16)SendMessage16( client_window, 0x0220, 0, (LPARAM16)win16_stack_pointer(&create)); } } } } win16_write_u16(window, 4, created); if (created == 0) { win16_write_u16(window, 2, 0xffff); } else if (object_windows_object_from_window(created) == 0) { object_windows_bind_window(created, window); int32_t previous = SetWindowLong16( created, -4, (int32_t)win16_read_far_pointer(window, 0x12)); write_far(window, WINDOW_ORIGINAL_PROC_OFFSET, (Win16FarPtr)previous); win16_call_object_method( vmt_procedure(window, WINDOW_CREATED_SLOT), window); } return (win16_indeterminate_u16() & 0xff00u) | (win16_read_u16(win16_far_add_offset(window, 2)) == 0 ? 1u : 0u); } static Win16FarPtr virtual_method( Win16FarPtr object, uint16_t slot) { uint16_t vmt = win16_read_u16(object); return win16_read_far_pointer(win16_dgroup_pointer(vmt), slot); } /* * 1018:15c0 — capture the native window's normal screen rectangle. * Minimized or maximized windows leave all four saved words untouched. For a * child window, the top-left point is translated to the MDI client when the * client exists and flag 08 is set; otherwise attribute bit 40000000 selects * translation to the parent window. GetWindowRect/ScreenToClient BOOL results * are deliberately ignored, matching the target. */ void object_windows_capture_normal_placement(Win16FarPtr window) { HWND16 handle = win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET)); if (IsIconic16(handle) != 0 || IsZoomed16(handle) != 0) { return; } RECT16 rectangle; (void)GetWindowRect16(handle, win16_stack_pointer(&rectangle)); win16_write_u16( window, WINDOW_NORMAL_WIDTH_OFFSET, (uint16_t)(rectangle.right - rectangle.left)); win16_write_u16( window, WINDOW_NORMAL_HEIGHT_OFFSET, (uint16_t)(rectangle.bottom - rectangle.top)); Win16FarPtr parent = win16_read_far_pointer(window, WINDOW_PARENT_OFFSET); if (parent != 0) { Win16FarPtr client = win16_call_object_far_method( virtual_method(parent, VMT_MDI_CLIENT_SLOT), parent); if (client != 0 && object_windows_has_flags(window, WINDOW_FLAG_AUTO_FOCUS)) { HWND16 client_handle = win16_read_u16( win16_far_add_offset(client, WINDOW_HANDLE_OFFSET)); (void)ScreenToClient16( client_handle, win16_stack_pointer(&rectangle)); } else if ((win16_read_u32( win16_far_add_offset( window, WINDOW_ATTRIBUTES_OFFSET)) & 0x40000000U) != 0) { HWND16 parent_handle = win16_read_u16( win16_far_add_offset(parent, WINDOW_HANDLE_OFFSET)); (void)ScreenToClient16( parent_handle, win16_stack_pointer(&rectangle)); } } win16_write_u16(window, WINDOW_NORMAL_X_OFFSET, (uint16_t)rectangle.left); win16_write_u16(window, WINDOW_NORMAL_Y_OFFSET, (uint16_t)rectangle.top); } /* * 1018:170c — ObjectWindows SetupWindow sequence: validate/prepare the native * window, optionally focus it, set up the attached object at +3b through VMT * slot 10, then capture the normal placement. */ void object_windows_setup_window(Win16FarPtr window) { object_windows_prepare_window(window); if (object_windows_has_flags(window, WINDOW_FLAG_AUTO_FOCUS)) { (void)SetFocus16( win16_read_u16( win16_far_add_offset(window, WINDOW_HANDLE_OFFSET))); } Win16FarPtr attached = win16_read_far_pointer(window, WINDOW_ATTACHED_OBJECT_OFFSET); if (attached != 0) { win16_call_object_method( virtual_method(attached, VMT_SETUP_SLOT), attached); } object_windows_capture_normal_placement(window); }