Very nice Vortex, I've never managed to get Win9x running without a section. I'll take a look at it, later on, tnx.
Posted on 2004-06-09 13:11:07 by pmpch
Vortex, very nice.
You can reduce the NE tweaking a little more. For eample, you can short more the DOS stub and cut out some strings.
Posted on 2004-06-09 13:20:30 by pelaillo
The second one reduced to 400 bytes. :)
Posted on 2004-06-09 14:12:51 by Vortex
hmm, why isn't the NE format used more like this? :) hmm, nice, i gotta look more into NE!
i know NE is ran from emulation, but it seems to support APIs, but it seems they're not 32bit, or am i wrong? what's the difference?
hmm, few more questions, what's INITTASK/WAITEVENT/INITAPP, i've never seen such apis :)

are you nice enough to provide some info/examples? :D
Posted on 2004-06-09 17:48:54 by Drocon
NE works with 32-bit Windows.... very interesting. I never thought of that. Smart.
Posted on 2004-06-09 17:57:49 by pmpch
i found a version of Turbo Pascal for Windows, and the outputted executables were NE, but i didn't know you could trim down a NE that much. interesting stuff
Posted on 2004-06-09 18:02:54 by Drocon
INITTASK sets up the local heap, and initializes DLLs.
AX=0 for failure, 1 for success
CX=lower bound of stack
DX=display flags (for SHOWWINDOW)
BX=offset of command line (0 terminated!)
SI=other instance
DI=current instance (set equal to (DS&0xfffc)|2)
ES=Current PSP
I have no idea about WAITEVENT, it takes one parameter which seems to always be 0, and it most applications call this right before INITAPP.
INITAPP creates a message queue and initializes a few things. It should be called before any other UI function.
The file Vortex posted looks quite sloppy and unoptimized, though.
First off, DS already contains the selector of the automatic data segment at startup, no need to set it again. Jnz $+02h / jmp $+29h is quite bad... And why are you saving everything returned by INITTASK when you're only using DI anyway? xor ax,ax / push ax should be changed to push 0. mov ax,[16h] should be changed to push di. The rest is so bad, I don't even know where to start... It looks like it was written in C! :eek:

Let's see if you won't save a number of bytes fixing this comparable to the number of bytes you saved by reducing header size.
Posted on 2004-06-10 12:23:18 by Sephiroth3
Here is my third example of 334 bytes. :)

Sephiroth3, before making strong comments like,
The rest is so bad, I don't even know where to start... It looks like it was written in C!
you should permit me to say that my code is just only a tiny example coded in C :)

Now here is the equivalent code in asm:


MB_OK = 0

WAITEVENT proto :word
INITAPP proto :word

MESSAGEBOX proto :word,:word,:word,:word,:word,:word

db 16 dup( 0 ) ; Required for Task Header!!
szMsg db 'Hello!',0
hInstance dw ?



;Windows initialization. Sets up registers and stack.

;INITTASK returns:
; 'Failure:
; AX = zero if it failed
; Success:
; AX = 1
; CX = stack limit
; DX = cmdShow parameter to CreateWindow
; ES:BX = -> DOS format command line (ES = PSP address)
; SI = hPrevinstance
; DI = hinstance
or ax,ax
jnz OK
jmp terminate
mov hInstance, di

;Initialize the Windows App

invoke WAITEVENT,0
invoke INITAPP,hInstance
or ax,ax
jz terminate
invoke MESSAGEBOX,0,ds,offset szMsg,ds,offset szMsg,MB_OK
mov ax, 4CFFh
int 21h ; terminate program
END start

The code is assembled with 32-bit Macro Assembler and linked with Digital Mars linker

\masm32\bin\ml -c Hello.asm
\dm\bin\link -alignment:2 -stub:stub.exe Hello.obj,Hello.exe,,libw.lib,win16.def

The initialization code taken from old Tasm and Masm examples.
Posted on 2004-06-10 13:54:55 by Vortex
Why isn't NE used more? Because it's 16bit protected mode, perhaps? ^_^
Posted on 2004-06-10 14:23:09 by f0dder

Why isn't NE used more? Because it's 16bit protected mode, perhaps? ^_^

Yeah, one can tell by the register sizes. However, I didn't realize those can still be run with Win9x and WinNt+.
Posted on 2004-06-10 16:59:17 by pmpch
Ah, ok :P Well, this is 264 bytes, but I'm sure it won't be too hard to beat.
Posted on 2004-06-10 17:48:28 by Sephiroth3
What's your technique to reduce the file to 264 bytes?
Posted on 2004-06-11 14:18:23 by Vortex
9x and NT still has more or less full support for the win16 subsystems (and 9x is based partially on it, very ugly). And of course you can still use 32bit registers in win16 apps, they'll just generate pesky prefix bytes.
Posted on 2004-06-11 14:22:39 by f0dder
Curiously enough, Solitaire, Minesweeper and probably a bunch of other programs came in 32-bit versions with Windows NT, although the old versions worked just fine :P The new Minesweeper is nearly 4 times as large as the old one. I wonder what they were on? Or was this a publicity trick?

To reduce the file size, I reduced the size of the horribly overbloated code and set the name and description of the program both to "A". I shrunk the space before the NE header and put the message at 0x18, and put the DOS program to display the message in the task header.
Posted on 2004-06-11 17:05:09 by Sephiroth3
How to shrink the space before the NE header?
Posted on 2004-06-12 03:09:40 by Vortex
I got 242, but I'm sure some more shrinking is possible.
Posted on 2004-06-12 04:06:14 by pelaillo

How you shrinked the executable? Can you post your method?
Posted on 2004-06-12 05:14:03 by Vortex
My method was:

1. Download NE specs from
2. IDA
3. Start tweaking with fasm
Posted on 2004-06-12 16:24:56 by pelaillo
He put the data segment in the header and removed the stub. Anyway there is plenty of unused space in the header now.

Okay, I got it down to 225 bytes and at the same time, restored the stub. This might be the absolute minimum, short of hard-coding the API addresses.
Posted on 2004-06-12 17:13:35 by Sephiroth3
Oops, forgot the file! Why will the board only allow you to upload a new attachment if the post already has one? :confused:

Posted on 2004-06-12 17:16:24 by Sephiroth3