#include "../tdkpin_program_entry.h" #include "../tdkpin_application.h" #include #include uint32_t g_tdkpin_windows_version; Win16FarPtr g_win16_message_box; static jmp_buf g_exit_jump; static uint16_t g_exit_status; static uint32_t g_version_result; static unsigned g_order[16]; static unsigned g_order_count; static unsigned g_message_calls; static unsigned g_construct_calls; static unsigned g_run_calls; static unsigned g_destruct_calls; enum CallOrder { CALL_INIT_TASK = 1, CALL_BORLAND_STARTUP, CALL_STACK, CALL_TPWINCRT, CALL_MULTIMEDIA, CALL_UNIT_91, CALL_UNIT_86, CALL_UNIT_72, CALL_GET_VERSION, CALL_MESSAGE_BOX, CALL_CONSTRUCT, CALL_RUN, CALL_DESTRUCT, CALL_EXIT, }; static void record_call(unsigned call) { assert(g_order_count < sizeof(g_order) / sizeof(*g_order)); g_order[g_order_count++] = call; } BorlandWin16StartupRegisters InitTask16(void) { record_call(CALL_INIT_TASK); return (BorlandWin16StartupRegisters){ .loader_ax = 1, .command_line = win16_make_far_pointer(0x4444, 0x0100), .show_command = 7, .previous_instance = 0, .instance = 0x2222, }; } void borland_initialize_win16_runtime( const BorlandWin16StartupRegisters *registers) { assert(registers->loader_ax == 1 && registers->instance == 0x2222); assert(registers->command_line == win16_make_far_pointer(0x4444, 0x0100)); record_call(CALL_BORLAND_STARTUP); } void tdkpin_initialize_stack_guard(void) { record_call(CALL_STACK); } void tpwincrt_initialize_runtime_unit(void) { record_call(CALL_TPWINCRT); } void multimedia_initialize_runtime_unit(void) { record_call(CALL_MULTIMEDIA); } void tdkpin_initialize_unit_ordinal_91(void) { record_call(CALL_UNIT_91); } void tdkpin_initialize_unit_ordinal_86(void) { record_call(CALL_UNIT_86); } void tdkpin_initialize_unit_ordinal_72(void) { record_call(CALL_UNIT_72); } uint32_t GetVersion16(void) { record_call(CALL_GET_VERSION); return g_version_result; } INT16 win16_call_message_box_far( Win16FarPtr procedure, HWND16 owner, Win16FarPtr text, Win16FarPtr caption, UINT16 type) { assert(procedure == g_win16_message_box); assert(owner == 0); assert(text == win16_dgroup_pointer(0x0396)); assert(caption == win16_dgroup_pointer(0x03c8)); assert(type == 0x10); g_message_calls++; record_call(CALL_MESSAGE_BOX); return 1; } Win16FarPtr object_windows_application_construct( Win16FarPtr object, uint16_t vmt, Win16FarPtr name) { assert(object == win16_dgroup_pointer(0x0748)); assert(vmt == 0x0024); assert(name == win16_dgroup_pointer(0x03e1)); win16_write_u16(object, 0, vmt); g_construct_calls++; record_call(CALL_CONSTRUCT); return object; } void win16_call_object_method( Win16FarPtr procedure, Win16FarPtr object) { assert(procedure == win16_make_far_pointer(0x6000, 0x1111)); assert(object == win16_dgroup_pointer(0x0748)); g_run_calls++; record_call(CALL_RUN); } void win16_call_object_destructor( Win16FarPtr procedure, Win16FarPtr object, uint16_t dispose_mode) { assert(procedure == win16_make_far_pointer(0x6000, 0x2222)); assert(object == win16_dgroup_pointer(0x0748)); assert(dispose_mode == 0); g_destruct_calls++; record_call(CALL_DESTRUCT); } _Noreturn void borland_runtime_exit(uint16_t status) { g_exit_status = status; record_call(CALL_EXIT); longjmp(g_exit_jump, 1); } 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 run_case(uint32_t version, bool supported) { g_version_result = version; g_order_count = 0; g_message_calls = 0; g_construct_calls = 0; g_run_calls = 0; g_destruct_calls = 0; if (setjmp(g_exit_jump) == 0) { tdkpin_ne_program_entry(); assert(false); } assert(g_exit_status == 0); assert(g_tdkpin_windows_version == version); for (unsigned index = 0; index < 9; index++) { assert(g_order[index] == index + 1); } if (supported) { assert(g_message_calls == 0); assert(g_construct_calls == 1 && g_run_calls == 1 && g_destruct_calls == 1); assert(g_order_count == 13); assert(g_order[9] == CALL_CONSTRUCT); assert(g_order[10] == CALL_RUN); assert(g_order[11] == CALL_DESTRUCT); assert(g_order[12] == CALL_EXIT); } else { assert(g_message_calls == 1); assert(g_construct_calls == 0 && g_run_calls == 0 && g_destruct_calls == 0); assert(g_order_count == 11); assert(g_order[9] == CALL_MESSAGE_BOX); assert(g_order[10] == CALL_EXIT); } } int main(void) { static uint8_t dgroup[0x800]; win16_reset_segment_bindings(); win16_bind_segment(0x7000, dgroup, sizeof(dgroup), true); win16_set_dgroup_selector(0x7000); g_win16_message_box = win16_make_far_pointer(0x5000, 0x0100); Win16FarPtr vmt = win16_dgroup_pointer(0x0024); write_far(vmt, 0x1c, win16_make_far_pointer(0x6000, 0x1111)); write_far(vmt, 0x08, win16_make_far_pointer(0x6000, 0x2222)); run_case(0xabcd6302u, false); /* major 2 */ run_case(0xabcd0903u, false); /* Windows 3.9 */ run_case(0xabcd0a03u, true); /* Windows 3.10 */ run_case(0xabcd0004u, true); /* Windows 4.x */ return 0; }