// DER EINZIGE ORT MIT koffi im Kern (Regel R1, KONZEPT § 4.3) — die rohe // Win32-Anbindung für optische Laufwerke. Entscheidungen stehen NICHT hier, // sondern in disc.ts; die Konstanten samt Herleitung in codes.ts. Dadurch // ist alles außer diesen Aufrufen ohne Windows und ohne Laufwerk prüfbar // (dasselbe Muster wie win_ioctl.py/windows.py im Docker-Zweig, dort an // echter Hardware bewiesen — 28.08.2026, BU40N; hier gemessen in // beweise/laufwerk.js, 30.08.2026). import koffi from 'koffi' import { FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, Win32Fehler, type LaufwerkApi } from './codes' export type { LaufwerkApi } let echteApi: LaufwerkApi | null = null /** Die echten kernel32-Aufrufe — einmal geladen, dann wiederverwendet. */ export function win32Api(): LaufwerkApi { if (echteApi !== null) return echteApi const kernel32 = koffi.load('kernel32.dll') const GetLogicalDrives = kernel32.func('uint32_t __stdcall GetLogicalDrives()') const GetDriveTypeW = kernel32.func('uint32_t __stdcall GetDriveTypeW(str16 lpRootPathName)') const CreateFileW = kernel32.func( 'void* __stdcall CreateFileW(str16 lpFileName, uint32_t dwDesiredAccess, uint32_t dwShareMode, void *lpSecurityAttributes, uint32_t dwCreationDisposition, uint32_t dwFlagsAndAttributes, void *hTemplateFile)', ) const CloseHandle = kernel32.func('bool __stdcall CloseHandle(void *hObject)') const GetLastError = kernel32.func('uint32_t __stdcall GetLastError()') // 5.7.0 (Durchsicht F11): Welches Kernel-Gerät steckt hinter G:? — // QueryDosDeviceW liefert \Device\CdRom0 (learn.microsoft.com, // fileapi/nf-fileapi-querydosdevicew: Ziel ist eine Mehrfach-Zeichenkette, // der erste Eintrag zählt; am 12.09.2026 an C: dieses PCs gemessen). // Damit zählt die Laufwerks-Gesundheit nur noch die Ereignisse DIESES // Laufwerks, nicht die einer hustenden Festplatte. const QueryDosDeviceW = kernel32.func( 'uint32_t __stdcall QueryDosDeviceW(str16 lpDeviceName, _Out_ char16_t *lpTargetPath, uint32_t ucchMax)', ) const DeviceIoControl = kernel32.func( 'bool __stdcall DeviceIoControl(void *hDevice, uint32_t dwIoControlCode, void *lpInBuffer, uint32_t nInBufferSize, _Out_ void *lpOutBuffer, uint32_t nOutBufferSize, _Out_ uint32_t *lpBytesReturned, void *lpOverlapped)', ) echteApi = { laufwerksbuchstaben(): string[] { const maske = GetLogicalDrives() as number const buchstaben: string[] = [] for (let i = 0; i < 26; i++) { if (maske & (1 << i)) buchstaben.push(String.fromCharCode(65 + i)) } return buchstaben }, laufwerkstyp(buchstabe: string): number { return GetDriveTypeW(`${buchstabe}:\\`) as number }, oeffnen(geraetepfad: string, zugriff: number): unknown { const handle = CreateFileW( geraetepfad, zugriff, FILE_SHARE_READ | FILE_SHARE_WRITE, null, OPEN_EXISTING, 0, null, ) const adresse = koffi.address(handle as Parameters[0]) // INVALID_HANDLE_VALUE ist (HANDLE)-1 — als vorzeichenlose 64-Bit-Zahl // 0xFFFF…FF, nicht -1 (dieselbe Falle wie in windows.py dokumentiert). if (adresse === 0n || adresse === 0xffff_ffff_ffff_ffffn) { throw new Win32Fehler('CreateFileW', GetLastError() as number) } return handle }, schliessen(handle: unknown): void { CloseHandle(handle) }, geraeteName(buchstabe: string): string { const ziel = Buffer.alloc(2 * 1024) const laenge = QueryDosDeviceW(`${buchstabe.replace(/:$/, '')}:`, ziel, 1024) as number if (laenge === 0) return '' // UTF-16LE, die erste Zeichenkette bis zum ersten NUL. const text = ziel.toString('utf16le', 0, laenge * 2) const ende = text.indexOf('\0') return (ende >= 0 ? text.slice(0, ende) : text).trim() }, steuern(handle: unknown, code: number, eingabe?: Buffer | null, ausgabeBytes = 0): Buffer { const aus = ausgabeBytes > 0 ? Buffer.alloc(ausgabeBytes) : null const zurueck = [0] const erfolg = DeviceIoControl( handle, code, eingabe ?? null, eingabe?.length ?? 0, aus, ausgabeBytes, zurueck, null, ) if (!erfolg) { throw new Win32Fehler(`DeviceIoControl(0x${code.toString(16)})`, GetLastError() as number) } return aus === null ? Buffer.alloc(0) : aus.subarray(0, zurueck[0]) }, } return echteApi }