const VERSION_BLOCK_SIZE: u32 = 0xA0;
const VS_FFI_SIGNATURE: u32 = 0xFEEF_04BD;
const VS_FFI_STRUCVERSION: u32 = 0x0001_0000;
fn build_version_block() -> [u8; VERSION_BLOCK_SIZE as usize] {
let mut buf = [0u8; VERSION_BLOCK_SIZE as usize];
buf[0..2].copy_from_slice(&(VERSION_BLOCK_SIZE as u16).to_le_bytes());
buf[2..4].copy_from_slice(&52u16.to_le_bytes());
buf[4..6].copy_from_slice(&0u16.to_le_bytes());
let key = "VS_VERSION_INFO";
for (i, c) in key.encode_utf16().enumerate() {
let off = 6 + i * 2;
buf[off..off + 2].copy_from_slice(&c.to_le_bytes());
}
let ffi_off = 40;
buf[ffi_off..ffi_off + 4].copy_from_slice(&VS_FFI_SIGNATURE.to_le_bytes());
buf[ffi_off + 4..ffi_off + 8].copy_from_slice(&VS_FFI_STRUCVERSION.to_le_bytes());
buf[ffi_off + 8..ffi_off + 12].copy_from_slice(&0x0007_0007u32.to_le_bytes());
buf[ffi_off + 12..ffi_off + 16].copy_from_slice(&0x0009_0050u32.to_le_bytes());
buf[ffi_off + 16..ffi_off + 20].copy_from_slice(&0x0007_0007u32.to_le_bytes());
buf[ffi_off + 20..ffi_off + 24].copy_from_slice(&0x0009_0050u32.to_le_bytes());
buf[ffi_off + 24..ffi_off + 28].copy_from_slice(&0x0000_003Fu32.to_le_bytes());
buf[ffi_off + 28..ffi_off + 32].copy_from_slice(&0u32.to_le_bytes());
buf[ffi_off + 32..ffi_off + 36].copy_from_slice(&0x0004_0004u32.to_le_bytes());
buf[ffi_off + 36..ffi_off + 40].copy_from_slice(&2u32.to_le_bytes());
buf[ffi_off + 40..ffi_off + 44].copy_from_slice(&0u32.to_le_bytes());
buf[ffi_off + 44..ffi_off + 48].copy_from_slice(&0u32.to_le_bytes());
buf[ffi_off + 48..ffi_off + 52].copy_from_slice(&0u32.to_le_bytes());
buf
}
use super::{HostState, Registry, StubFn, Win32Error, arg_dword};
use crate::emulator::emulator::{Cpu, Mmu};
pub fn register(registry: &mut Registry) {
registry.register(
"version.dll",
"GetFileVersionInfoSizeA",
stub_get_file_version_info_size_a as StubFn,
2,
);
registry.register(
"version.dll",
"GetFileVersionInfoA",
stub_get_file_version_info_a as StubFn,
4,
);
registry.register(
"version.dll",
"VerQueryValueA",
stub_ver_query_value_a as StubFn,
4,
);
}
fn stub_get_file_version_info_size_a(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &mut Registry,
) -> Result<u32, Win32Error> {
let _filename = arg_dword(cpu, mmu, 0)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoSizeA", t))?;
let handle = arg_dword(cpu, mmu, 1)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoSizeA", t))?;
if handle != 0 {
mmu.store32(handle, 0).map_err(|t| {
crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoSizeA", t)
})?;
}
Ok(VERSION_BLOCK_SIZE)
}
fn stub_get_file_version_info_a(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &mut Registry,
) -> Result<u32, Win32Error> {
let _filename = arg_dword(cpu, mmu, 0)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoA", t))?;
let _handle = arg_dword(cpu, mmu, 1)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoA", t))?;
let len = arg_dword(cpu, mmu, 2)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoA", t))?;
let data = arg_dword(cpu, mmu, 3)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoA", t))?;
if data == 0 || len == 0 {
return Ok(0);
}
let block = build_version_block();
let to_write = (len as usize).min(block.len());
mmu.write_initializer(data, &block[..to_write])
.map_err(|t| crate::emulator::win32::trap_to_win32_local("GetFileVersionInfoA", t))?;
Ok(1)
}
fn stub_ver_query_value_a(
cpu: &mut Cpu,
mmu: &mut Mmu,
_state: &mut HostState,
_registry: &mut Registry,
) -> Result<u32, Win32Error> {
let block = arg_dword(cpu, mmu, 0)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("VerQueryValueA", t))?;
let sub_block = arg_dword(cpu, mmu, 1)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("VerQueryValueA", t))?;
let lpp_buffer = arg_dword(cpu, mmu, 2)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("VerQueryValueA", t))?;
let pu_len = arg_dword(cpu, mmu, 3)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("VerQueryValueA", t))?;
if block == 0 || sub_block == 0 {
return Ok(0);
}
let key = crate::emulator::win32::read_cstr_local(mmu, sub_block, 260)?;
if key == "\\" {
let ffi_ptr = block.wrapping_add(40);
if lpp_buffer != 0 {
mmu.store32(lpp_buffer, ffi_ptr)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("VerQueryValueA", t))?;
}
if pu_len != 0 {
mmu.store32(pu_len, 52)
.map_err(|t| crate::emulator::win32::trap_to_win32_local("VerQueryValueA", t))?;
}
return Ok(1);
}
Ok(0)
}