# winevdm: running 16-bit Windows programs on 64-bit Windows

> otya128/winevdm is a port of the Wine-derived winevdm 16-bit emulator to 64-bit Windows. It registers itself as the handler for Win16 executables, so you can double-click an old installer or game instead of keeping a 32-bit machine around.

**otya128/winevdm** — 16-bit Windows (Windows 1.x, 2.x, 3.0, 3.1, etc.) on 64-bit Windows

- Repository: https://github.com/otya128/winevdm
- Stars: 3,424 · Forks: 200
- Language: C
- License: GPL-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/otya128-winevdm

## The gap winevdm fills on 64-bit Windows

64-bit Windows cannot run 16-bit code. The README states the reason plainly: the CPU emulator exists because 64-bit Windows cannot modify the LDT, since NtSetInformationProcess with ProcessLdtInformation always returns an error. That is not a missing feature that a shim can paper over. Without a local descriptor table, the segmented memory model that every Win16 program was built on has nowhere to live, so a compatibility layer that only forwards API calls is not enough. You need to emulate the CPU as well.

winevdm, distributed as otvdm, is an altered version of winevdm, described in the README as a 16-bit Windows emulator, ported to 64-bit Windows. The target audience is narrow and specific: someone holding a Win16 executable for Windows 1.x, 2.x, 3.0 or 3.1 who has no 32-bit machine left to run it on. The README's own framing is a one-line pitch, 16-bit Windows on 64-bit Windows, and the repository is tagged only with win16. There is no server component, no daemon, and no configuration file to learn beyond otvdm.ini.

## CPU emulation plus a Win16 to Win32 thunk layer

The README lists the program's parts, and they explain the architecture better than any diagram would. There is a CPU emulator to supply the missing LDT. There is DOS emulation for Win16, because plenty of Windows 3.x programs shell out to DOS or call DOS interrupts directly. There is a 16-bit to native handle conversion layer, so window handles and other kernel objects can cross the boundary. And there is the Wine-based conversion code that maps each Win16 API onto its Win32 equivalent.

The mapping is mechanical. The README shows the shape of it with DestroyWindow16, which takes an HWND16 and calls the 32-bit DestroyWindow after converting the handle through WIN_Handle32. Writing hundreds of those by hand would be tedious and error-prone, so the relay routines are autogenerated by convspec from a spec file. The README gives the corresponding line: 53 pascal -ret16 DestroyWindow(word) DestroyWindow16. That spec format carries the ordinal, the calling convention, the return width and the argument types, which is enough to generate the thunk. It also means the API surface is limited by what has been described in spec files, not by what Wine implements upstream.

Two smaller mechanisms matter in daily use. First, install.inf. The README explains that when 64-bit Windows detects a 16-bit installer, it has a mechanism to start an alternative installer which is not 16-bit, and this program uses it. That is how a Win16 setup program gets routed to otvdm instead of failing. Second, WINDOWS directory redirection: the README notes that some Win16 programs try to save settings in %WINDIR%\<filename>.ini, that recent Windows does not allow writes there, and that the program redirects. That redirection is the difference between an old application remembering its preferences and silently forgetting them.

## Installing winevdm and running a first Win16 program

The README gives two paths: download or compile. The stable builds are on the GitHub releases page, and the README also links an AppVeyor build it labels as the latest version and unstable. If you build from source with cmake, the README's sequence is short. It assumes you are in a shell with git, cmake and make available.

```sh
# https://github.com/otya128/winevdm
git clone https://github.com/otya128/winevdm.git
cd winevdm
mkdir build
cd build
cmake ..
make
```

Visual Studio 2017 is the alternative toolchain the README documents: install it, edit PropertySheet.props, and compile. Either way, the build produces otvdm.

Installation is not an installer in the usual sense. The README says to run the install shortcut, or to right-click install.inf and select Install. After that, you can execute Win16 binaries directly, which is the whole point: the file association is what makes a double-click work. There is one prerequisite worth reading twice. If you get an error that VCRUNTIME140.dll is missing, the README directs you to the Microsoft Visual C++ Redistributable for Visual Studio 2017, 32-bit. Note the 32-bit qualifier; the 64-bit redistributable is not the one being asked for here.

For a first run, the README offers two entry points. You can drag and drop a Win16 executable onto otvdm.exe, or execute otvdmw.exe. There is also a command-line form, and the README's example is a Windows 3.1 calculator.

```bat
winevdm.exe [--app-name app.exe] command line
winevdm.exe CALC.EXE
```

If the calculator window appears and behaves like a Windows 3.1 application, the thunk layer and the emulator are both working. If nothing appears, the first thing to check is whether the 32-bit VC++ runtime is present, because that failure mode is documented and the others are not.

## The DOS mode is not the reason to install this

winevdm can also run DOS executables, and the README says so, describing the behaviour as DOS emulator-like. It also says the DOS version can be set with the VDMDOSVER environment variable. Then it closes the door: DOS emulation is incomplete, and the README recommends DOSBox or MS-DOS Player instead.

That is an unusually direct piece of documentation, and it should be taken at face value. If your actual goal is a DOS game or a DOS-era utility, winevdm is the wrong tool and its own README says so. The DOS layer exists because Win16 applications sometimes need it underneath, not because it is a general-purpose DOS environment. Treat VDMDOSVER as a compatibility knob for a Windows program that happens to make DOS calls, not as a configuration option for running DOS software.

There is a second limitation that the README does not resolve. It states that if the registry is initialized by Windows Update, you should perform the install procedure again. That is a maintenance cost, not a one-time setup: a Windows feature update can silently undo the file association, and the symptom will look like winevdm stopped working rather than like a registry reset. The README does not document any way to detect that condition in advance. It also does not document rollback beyond running uninstall.reg, and it does not describe what state uninstall.reg leaves behind. Anyone deploying this on a machine they do not physically control should plan for the reinstall step.

## winevdm versus DOSBox, and versus upstream Wine

The comparison the README itself makes is with DOSBox and MS-DOS Player, and the difference is scope rather than quality. DOSBox emulates a PC and a DOS environment, which is what a DOS program needs and what winevdm only approximates. winevdm emulates a 16-bit Windows machine on top of a native 64-bit Windows host, which is what a Win16 program needs and what DOSBox does not provide: DOSBox has no Win16 API layer. If your program is a Windows 3.1 application, DOSBox is not an alternative to winevdm. If it is a DOS application, winevdm is not an alternative to DOSBox. The README's own recommendation settles which side of that line you are on.

The other comparison is with Wine itself, and the naming is where people get confused. winevdm is an altered version of winevdm, which the README describes as a 16-bit Windows emulator. Wine, the project most readers know, runs Windows binaries on Unix-like systems; winevdm as packaged here is a Windows program that runs Win16 binaries on 64-bit Windows. The README contains no instructions for running it on Linux. The Win16 to Win32 conversion code is described as wine based, which is the lineage, not the deployment target.

## Licence, build cost and what a release actually means

The licence is GPL-2.0. The practical consequence worth naming is that if you redistribute a modified otvdm, the GPL-2.0 obligations travel with it, and the Wine-derived conversion code is part of that picture. This is a description of the licence file in the repository, not legal advice; if you are shipping winevdm inside a product, that is a question for someone qualified to answer it.

Upgrade cost is low in the ordinary case and awkward in one specific case. The last push to the repository was on 2026-09-22, and the most recent release listed is v0.9.0 from 2023-09-15, preceded by v0.8.0 in 2021 and v0.7.0 in 2019. That gap between repository activity and tagged releases means the stable download and the current source are not the same thing. The README points at the AppVeyor build for what it calls the latest version and marks it unstable. So a user has a real choice to make: take v0.9.0 and accept that fixes landed after it are missing, or take the AppVeyor artifact and accept that it is labelled unstable. There is no documented middle option.

One configuration surface exists, otvdm.ini, and the README does nothing more than point at it. That is the file to read before changing anything, because it is the only documented place where behaviour can be adjusted without rebuilding.

## Conclusion

winevdm is for people who need to open a specific Win16 program on a 64-bit Windows machine and are willing to install a file-association handler and a 32-bit VC++ runtime to do it. It is not for anyone whose real target is a DOS program, since the README itself points those users at DOSBox or MS-DOS Player, and it is not a way to run Win16 software on Linux. Before adopting it, check the release page for the version you intend to use, confirm whether the program writes its settings into %WINDIR% so you understand the redirection, and plan to re-run the install shortcut after a Windows Update resets the registry.

## FAQ

### What is winevdm?

It is an altered version of winevdm, which the README describes as a 16-bit Windows emulator, ported to 64-bit Windows so that Win16 programs from Windows 1.x through 3.1 can run there. It installs as the handler for 16-bit executables, so Win16 binaries can be executed directly.

### How to install winevdm?

Download a build or compile it, then run the install shortcut or right-click install.inf and select Install. If VCRUNTIME140.dll is reported missing, the README says to install the 32-bit Microsoft Visual C++ Redistributable for Visual Studio 2017.

### How to run winevdm?

After installation, Win16 binaries can be executed directly. The README also gives two manual routes: drag and drop the Win16 executable onto otvdm.exe, or execute otvdmw.exe.

### Is winevdm free?

The repository is licensed GPL-2.0, and the README points to GitHub releases for the stable version and to an AppVeyor build for the latest version, which it labels unstable. The README does not mention any paid edition.

### winevdm vs dosbox: which should I use?

winevdm can run DOS executables in a DOS emulator-like mode, but the README states that DOS emulation is incomplete and recommends DOSBox or MS-DOS Player instead. Use winevdm for Win16 programs; use DOSBox when the target is a DOS program.

## Sources

- [Issues](https://github.com/otya128/winevdm/issues)
- [License: GPL-2.0](https://github.com/otya128/winevdm/blob/master/LICENSE)
- [otya128/winevdm on GitHub](https://github.com/otya128/winevdm)
- [README](https://github.com/otya128/winevdm/blob/master/README.md)
- [Releases](https://github.com/otya128/winevdm/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/otya128-winevdm
