A hacky mechanism to call forth 32 bits userland DLL's from 16 bits applications which execute under the NTVDM is supported in Windows in order to let DOS applications extend their environment, whatever it is (video, sound, serial port or any other peripheral). It is called BOP(-Instructions). And I guess no one really knows what it stands for, but who cares. This mechanism let you register a DLL and then call it and later on unregister the DLL. Luckily, it is easily used, with an interesting trick. In order to invoke those BOP's you have to use an invalid instruction (0xc4, 0xc4 - sort of LEA but with register-register operands which is invalid form). Then an Invalid Instruction exception, interrupt #6, is generated by the processor and the KiTrap06 is executed. The KiTrap quickly tries to determine the reason of the exception, whether it was a misuse of the LOCK prefix or maybe just a BOP instruction. It then checks for two specific BOP's instructions, for fast IO. The BOP instructions we have to use are for 3rd party services, I guess letting DOS applications communicate with userland applications or VDD's. There are many kinds of BOP's, but we will simply use a specific one, 0x58, and passing parameters to it as well. KiTrap06 transfers control to NTVDM which does the real job for handling the BOP's instructions. The DLL file should be in the DOS application directory, or in the default paths. When invoking the dispatcher NTVDM guarantees to not change the values of the registers, thus using the DDK with the VDD functions you could be able to read and write memory to and fro userland DLL. But in the example I use NTVDM.EXE directly, in order to spare the library and header files. Register Module: Register a third party DLL with the BOP manager. Input: DS:SI - Null terminated string with the userland DLL name. ES:DI - Null terminated string with the initialization routine (Optional, ES=DI=0). DS:BX - Null terminated string with the dispatch routine (for later use by dispatcher). Return: If Carry is set: AX = 1 - DLL file was not found. AX = 2 - Dispatch routine wasn't found (GetProcAddress failed). AX = 3 - Initialization routine wasn't found (GetProcAddress faild). AX = 4 - Insufficient memory. Otherwise AX contains the handle of the registered DLL. BOP Instruction: 0xc4, 0xc4, 0x58, 0x00 DispatchCall: Call the registered DLL function. Input: AX - Handle to a registered DLL. [It depends on you how to pass info to the DLL] Return: Depends on dispatch routine. BOP Instruction: 0xc4, 0xc4, 0x58, 0x02 Unregister Module: Unregister a module from the BOP manager. Input: AX - Handle to a registered DLL. Return: None BOP Instruction: 0xc4, 0xc4, 0x58, 0x01 The userland DLL side (using VS): File galaxy.dll: __declspec(dllexport) void MyRoutine() { MessageBox(NULL, "Hey there", "BOPs", MB_OK); } The DOS side (using NASM): bits 16 mov si, DLL_NAME ;mov di, INIT_PROC xor di, di push di pop es mov bx, DISPATCHER db 0xc4, 0xc4, 0x58, 0x0 jc error: ; Store the DLL's handle mov [DLL_HANDLE], ax ;... ;... In the sample, a string is being passed to the userland DLL! ;... error: ret DLL_HANDLE dw 0 DLL_NAME: db "galaxy.dll", 0 INIT_PROC: db "InitProc", 0 DISPATCHER: db "MyRoutine", 0 Here's a full sample code: galaxy.zip That took a few hours of researching, I think it's really kewl, not sure if it's handy though. Oh well. ;)