#include "../tdkpin_multimedia.h" #include #include #include Win16FarPtr g_multimedia_procedures[11]; HINSTANCE16 g_multimedia_module; uint8_t g_multimedia_initialized; uint8_t g_multimedia_pending; uint16_t g_multimedia_version; uint8_t g_multimedia_auto_subclassed; uint8_t g_multimedia_argument_2; uint8_t g_multimedia_argument_1; uint8_t g_multimedia_legacy_windows; char g_multimedia_library_path[21] = "CTL3D.DLL"; Win16FarPtr g_object_windows_application; HINSTANCE16 g_win16_previous_instance; HINSTANCE16 g_win16_instance; uint16_t g_win16_show_command; Win16FarPtr g_win16_message_box; Win16FarPtr g_object_windows_dispatch_proc; uint16_t g_object_windows_thunk_code_selector; Win16FarPtr g_object_windows_free_thunk; Win16FarPtr g_object_windows_message_hook; static HINSTANCE16 g_freed_module; static Win16FarPtr g_called_procedure; static uint16_t g_called_argument; static unsigned g_sequence; static bool g_check_sequence; static Win16FarPtr g_destroyed_application; static HINSTANCE16 g_load_result; static uint16_t g_register_result; static uint16_t g_version_result; static uint16_t g_enabled_result; static uint16_t g_auto_result; static int g_search_success_attempt; static unsigned g_search_calls; static char g_search_paths[5][256]; static unsigned g_load_calls; static unsigned g_proc_calls; static UINT16 g_error_modes[4]; static unsigned g_error_mode_calls; static uint8_t g_dgroup[0x5000]; static void write_far_string(Win16FarPtr destination, const char *source) { size_t length = strlen(source); for (size_t index = 0; index <= length; index++) { win16_write_u8( win16_far_add_offset(destination, (uint16_t)index), (uint8_t)source[index]); } } static void read_far_string( Win16FarPtr source, char *destination, size_t capacity) { size_t index = 0; while (index + 1 < capacity) { uint8_t byte = win16_read_u8( win16_far_add_offset(source, (uint16_t)index)); destination[index++] = (char)byte; if (byte == 0) { return; } } destination[capacity - 1] = 0; } BOOL16 FreeLibrary16(HINSTANCE16 module) { if (g_check_sequence) { assert(++g_sequence == 2); } g_freed_module = module; return 1; } Win16Handle GetCurrentTask16(void) { return 0x1234; } uint16_t win16_call_pascal_u16(Win16FarPtr procedure, uint16_t argument) { if (g_check_sequence) { assert(++g_sequence == 1); } g_called_procedure = procedure; g_called_argument = argument; if (procedure == g_multimedia_procedures[6]) { return g_register_result; } if (procedure == g_multimedia_procedures[0]) { assert(argument == g_win16_instance); return g_auto_result; } return 0xabcd; } uint16_t win16_call_pascal_u16_no_args(Win16FarPtr procedure) { if (procedure == g_multimedia_procedures[5]) { return g_version_result; } assert(procedure == g_multimedia_procedures[3]); return g_enabled_result; } void object_windows_application_destruct( Win16FarPtr object, uint16_t vmt) { assert(++g_sequence == 3); assert(vmt == 0); g_destroyed_application = object; } void borland_finish_object_destructor( BorlandObjectCallFrame *frame, uint16_t vmt_field_offset) { assert(++g_sequence == 4); assert(frame->object == g_destroyed_application); assert(frame->vmt_argument == 0x0200 && vmt_field_offset == 0); } UINT16 SetErrorMode16(UINT16 mode) { g_error_modes[g_error_mode_calls++] = mode; return 0; } HINSTANCE16 LoadLibrary16(const char *library_name) { assert(strcmp(library_name, g_multimedia_library_path) == 0); g_load_calls++; return g_load_result; } Win16FarPtr GetProcAddress16( HINSTANCE16 module, const char *procedure_name) { static const char *const names[11] = { "CTL3DAUTOSUBCLASS", "CTL3DCOLORCHANGE", "CTL3DCTLCOLOREX", "CTL3DENABLED", "CTL3DDLGFRAMEPAINT", "CTL3DGETVER", "CTL3DREGISTER", "CTL3DSUBCLASSDLG", "CTL3DSUBCLASSDLGEX", "CTL3DSUBCLASSCTL", "CTL3DUNREGISTER", }; assert(module == g_load_result && g_proc_calls < 11); unsigned index = 0; while (index < 11 && strcmp(procedure_name, names[index]) != 0) { index++; } assert(index < 11); g_proc_calls++; return win16_make_far_pointer( 0x9000, (uint16_t)(0x100 + index)); } Win16FarPtr multimedia_search_file( Win16FarPtr search_path, Win16FarPtr file_name, Win16FarPtr result) { char file_name_text[32]; read_far_string(file_name, file_name_text, sizeof(file_name_text)); assert(strcmp(file_name_text, g_multimedia_library_path) == 0); assert(g_search_calls < 5); read_far_string( search_path, g_search_paths[g_search_calls], sizeof(g_search_paths[g_search_calls])); bool found = (int)g_search_calls == g_search_success_attempt; g_search_calls++; win16_write_u8(result, found ? 'X' : 0); win16_write_u8(win16_far_add_offset(result, 1), 0); return result; } UINT16 GetWindowsDirectoryFar16(Win16FarPtr buffer, UINT16 size) { assert(size == 0xff); write_far_string(buffer, "WIN"); return 3; } UINT16 GetSystemDirectoryFar16(Win16FarPtr buffer, UINT16 size) { assert(size == 0xff); write_far_string(buffer, "SYS"); return 3; } HINSTANCE16 GetModuleHandle16(Win16FarPtr module_name) { assert(module_name == win16_make_far_pointer(0x7000, 0x1234)); return 0x5555; } UINT16 GetModuleFileNameFar16( HINSTANCE16 module, Win16FarPtr buffer, UINT16 size) { assert(module == 0x5555 && size == 0x100); write_far_string(buffer, "C:\\APP\\GAME.EXE"); return 15; } uint16_t multimedia_split_path( Win16FarPtr extension, Win16FarPtr file_name, Win16FarPtr directory, Win16FarPtr input) { char input_text[32]; read_far_string(input, input_text, sizeof(input_text)); assert(strcmp(input_text, "C:\\APP\\GAME.EXE") == 0); assert(extension != 0 && file_name != 0 && directory == input); write_far_string(directory, "MOD"); return 7; } Win16FarPtr multimedia_environment_value(Win16FarPtr name) { char name_text[8]; read_far_string(name, name_text, sizeof(name_text)); assert(strcmp(name_text, "PATH") == 0); return win16_make_far_pointer(0x7000, 0x4700); } static void fill_procedures(void) { for (unsigned index = 0; index < 11; index++) { g_multimedia_procedures[index] = win16_make_far_pointer(0x8000, (uint16_t)(0x100 + index)); } } static void reset_loader(void) { for (unsigned index = 0; index < 11; index++) { g_multimedia_procedures[index] = 0; } g_multimedia_initialized = 0; g_multimedia_module = 0; g_multimedia_version = 0; g_multimedia_auto_subclassed = 0; g_multimedia_argument_1 = 0; g_multimedia_argument_2 = 0; g_multimedia_legacy_windows = 0; g_load_result = 64; g_register_result = 1; g_version_result = 9; g_enabled_result = 1; g_auto_result = 1; g_search_success_attempt = 0; g_search_calls = 0; g_load_calls = 0; g_proc_calls = 0; g_error_mode_calls = 0; g_freed_module = 0; write_far_string( win16_make_far_pointer(0x7000, 0x478d), g_multimedia_library_path); } int main(void) { uint8_t stack_anchor = 0; uintptr_t stack_base = (uintptr_t)&stack_anchor - 0x8000; win16_reset_segment_bindings(); win16_bind_segment(0x7000, g_dgroup, sizeof(g_dgroup), true); win16_set_dgroup_selector(0x7000); win16_bind_segment(0x7200, (void *)stack_base, 0x10000, true); write_far_string(win16_make_far_pointer(0x7000, 0x046a), "PATH"); write_far_string(win16_make_far_pointer(0x7000, 0x4700), "ENV"); write_far_string( win16_make_far_pointer(0x7000, 0x478d), g_multimedia_library_path); fill_procedures(); g_multimedia_module = 31; g_multimedia_initialized = 1; g_freed_module = 0; multimedia_unload(); assert(g_freed_module == 0 && g_multimedia_module == 31); assert(!g_multimedia_initialized); for (unsigned index = 0; index < 11; index++) { assert(g_multimedia_procedures[index] == 0); } fill_procedures(); g_multimedia_module = 64; g_multimedia_initialized = 1; Win16FarPtr terminator = g_multimedia_procedures[10]; g_called_procedure = 0; multimedia_finalize_current_task(); assert(g_called_procedure == terminator && g_called_argument == 0x1234); assert(g_freed_module == 64 && !g_multimedia_initialized); fill_procedures(); g_multimedia_initialized = 0; g_called_procedure = 0; multimedia_finalize_current_task(); assert(g_called_procedure == 0 && g_multimedia_procedures[0] != 0); fill_procedures(); g_multimedia_module = 64; g_multimedia_initialized = 1; g_sequence = 0; g_check_sequence = true; Win16FarPtr application = win16_make_far_pointer(0x7000, 2); multimedia_application_destruct(application, 0x0200); g_check_sequence = false; assert(g_sequence == 4 && g_destroyed_application == application); reset_loader(); g_win16_instance = 0x4444; g_multimedia_pending = 0x7f; assert(multimedia_initialize_export(1, 2, 1, 0x1234, 0x7000) == 1); assert(g_multimedia_pending == 0); assert(g_multimedia_argument_1 == 1 && g_multimedia_argument_2 == 2); assert(g_multimedia_auto_subclassed == 1); assert(g_proc_calls == 11 && g_error_mode_calls == 2); assert(g_error_modes[0] == 0x8000 && g_error_modes[1] == 0); assert(multimedia_initialize(9, 8, 0, 0x1234, 0x7000) == 1); assert(g_load_calls == 1); /* Already initialized: no second load. */ reset_loader(); g_load_result = 31; assert(multimedia_initialize(1, 2, 1, 0x1234, 0x7000) == 0); assert(g_proc_calls == 0 && g_multimedia_module == 31); reset_loader(); g_register_result = 0; assert(multimedia_initialize(1, 2, 1, 0x1234, 0x7000) == 0); assert(g_freed_module == 64 && g_multimedia_procedures[0] == 0); reset_loader(); g_version_result = 8; assert(multimedia_initialize(1, 2, 1, 0x1234, 0x7000) == 0); assert(g_freed_module == 64); reset_loader(); g_multimedia_legacy_windows = 1; g_search_success_attempt = -1; assert(multimedia_initialize(1, 2, 1, 0x1234, 0x7000) == 0); assert(g_load_calls == 0 && g_multimedia_module == 0); reset_loader(); g_multimedia_legacy_windows = 1; assert(multimedia_initialize(3, 4, 1, 0x1234, 0x7000) == 1); assert(g_proc_calls == 10 && g_multimedia_procedures[8] == 0); assert(g_multimedia_auto_subclassed == 0); assert(g_error_mode_calls == 0); for (int attempt = 0; attempt < 5; attempt++) { g_search_success_attempt = attempt; g_search_calls = 0; assert(multimedia_locate_library( win16_make_far_pointer(0x7000, 0x1234), win16_make_far_pointer(0x7000, 0x478d))); assert(g_search_calls == (unsigned)attempt + 1); } assert(strcmp(g_search_paths[0], "") == 0); assert(strcmp(g_search_paths[1], "WIN") == 0); assert(strcmp(g_search_paths[2], "SYS") == 0); assert(strcmp(g_search_paths[3], "MOD") == 0); assert(strcmp(g_search_paths[4], "ENV") == 0); g_search_success_attempt = -1; g_search_calls = 0; assert(!multimedia_locate_library( win16_make_far_pointer(0x7000, 0x1234), win16_make_far_pointer(0x7000, 0x478d))); assert(g_search_calls == 5); return 0; }