/* Dynamic Win16 multimedia helper DLL lifecycle from Code3. */ #include "tdkpin_multimedia.h" extern Win16FarPtr g_multimedia_procedures[11]; /* 1028:4750..477b */ extern HINSTANCE16 g_multimedia_module; /* 1028:4781 unaligned */ extern uint8_t g_multimedia_initialized; /* 1028:4784 */ static const char *const multimedia_procedure_names[11] = { "CTL3DAUTOSUBCLASS", "CTL3DCOLORCHANGE", "CTL3DCTLCOLOREX", "CTL3DENABLED", "CTL3DDLGFRAMEPAINT", "CTL3DGETVER", "CTL3DREGISTER", "CTL3DSUBCLASSDLG", "CTL3DSUBCLASSDLGEX", "CTL3DSUBCLASSCTL", "CTL3DUNREGISTER", }; /* * 1010:00a2 — test whether the CTL3D file can be found in the exact original * search order. The 80-byte result is only a success indicator; LoadLibrary * later receives the unchanged global library name/path buffer. */ bool multimedia_locate_library( Win16FarPtr module, Win16FarPtr library_path) { uint8_t search_path_bytes[256]; uint8_t result_bytes[80]; uint8_t extension_bytes[5]; uint8_t file_name_bytes[9]; Win16FarPtr search_path = win16_stack_pointer(search_path_bytes); Win16FarPtr result = win16_stack_pointer(result_bytes); Win16FarPtr extension = win16_stack_pointer(extension_bytes); Win16FarPtr file_name = win16_stack_pointer(file_name_bytes); win16_write_u8(search_path, 0); (void)multimedia_search_file(search_path, library_path, result); if (win16_read_u8(result) != 0) { return true; } (void)GetWindowsDirectoryFar16(search_path, 0xff); (void)multimedia_search_file(search_path, library_path, result); if (win16_read_u8(result) != 0) { return true; } (void)GetSystemDirectoryFar16(search_path, 0xff); (void)multimedia_search_file(search_path, library_path, result); if (win16_read_u8(result) != 0) { return true; } HINSTANCE16 module_handle = GetModuleHandle16(module); (void)GetModuleFileNameFar16(module_handle, search_path, 0x100); (void)multimedia_split_path( extension, file_name, search_path, search_path); (void)multimedia_search_file(search_path, library_path, result); if (win16_read_u8(result) != 0) { return true; } Win16FarPtr environment_path = multimedia_environment_value( win16_dgroup_pointer(0x046a)); (void)multimedia_search_file(environment_path, library_path, result); return win16_read_u8(result) != 0; } /* 1010:0002 — unload the helper and clear every dynamically resolved slot. */ void multimedia_unload(void) { if (g_multimedia_module >= 0x20) { (void)FreeLibrary16(g_multimedia_module); } g_multimedia_initialized = 0; for (unsigned index = 0; index < 11; index++) { g_multimedia_procedures[index] = 0; } } /* 1010:0079 — notify the helper for this task, then perform common unload. */ void multimedia_finalize_current_task(void) { Win16FarPtr terminate_task = g_multimedia_procedures[10]; if (g_multimedia_initialized && terminate_task != 0) { (void)win16_call_pascal_u16(terminate_task, GetCurrentTask16()); multimedia_unload(); } } /* * 1010:03e0 — multimedia-aware TApplication destructor. Finalize the current * helper task before the application/root destructors and owned-allocation * cleanup. The hidden VMT zero passed to TApplication prevents double free. */ void multimedia_application_destruct( Win16FarPtr object, uint16_t vmt) { multimedia_finalize_current_task(); object_windows_application_destruct(object, 0); BorlandObjectCallFrame frame = {object, vmt}; borland_finish_object_destructor(&frame, 0); } /* * 1010:03af — exported loader wrapper. Each byte argument occupies a 16-bit * Pascal stack slot; only AL is returned. The target always clears 1028:4783 * after the underlying 1010:01c2 call, regardless of its result. */ uint8_t multimedia_initialize_export( uint8_t argument_1, uint8_t argument_2, uint8_t argument_3, uint16_t argument_4, uint16_t argument_5) { uint8_t result = multimedia_initialize( argument_1, argument_2, argument_3, argument_4, argument_5); g_multimedia_pending = 0; return result; } /* * 1010:01c2 — load and validate CTL3D.DLL/CTL3DV2.DLL. * Procedure slots retain their exact binary order at 1028:4750..477b. */ uint8_t multimedia_initialize( uint8_t argument_1, uint8_t argument_2, uint8_t auto_subclass, uint16_t module_offset, uint16_t module_selector) { if (g_multimedia_initialized) { return 1; } if (!g_multimedia_legacy_windows) { (void)SetErrorMode16(0x8000); g_multimedia_module = LoadLibrary16(g_multimedia_library_path); (void)SetErrorMode16(0); } else { bool located = multimedia_locate_library( win16_make_far_pointer(module_selector, module_offset), win16_dgroup_pointer(0x478d)); g_multimedia_module = located ? LoadLibrary16(g_multimedia_library_path) : 0; } if (g_multimedia_module < 0x20) { return 0; } for (unsigned index = 0; index < 11; index++) { if (index == 8 && g_multimedia_legacy_windows) { g_multimedia_procedures[index] = 0; } else { g_multimedia_procedures[index] = GetProcAddress16( g_multimedia_module, multimedia_procedure_names[index]); } } g_multimedia_initialized = win16_call_pascal_u16( g_multimedia_procedures[6], GetCurrentTask16()) != 0; if (g_multimedia_initialized) { g_multimedia_version = win16_call_pascal_u16_no_args(g_multimedia_procedures[5]); bool enabled = win16_call_pascal_u16_no_args( g_multimedia_procedures[3]) != 0; g_multimedia_initialized = enabled && g_multimedia_version >= 9; } if (!g_multimedia_initialized) { multimedia_unload(); return 0; } g_multimedia_argument_2 = argument_2; g_multimedia_argument_1 = argument_1; if (!g_multimedia_legacy_windows && auto_subclass != 0) { g_multimedia_auto_subclassed = win16_call_pascal_u16( g_multimedia_procedures[0], g_win16_instance) != 0; } else { g_multimedia_auto_subclassed = 0; } return 1; }