pouët.net

two little win32 sizecoding tricks

category: code [glöplog]
In the following, two little tricks that might save you a tiny amount of bytes:

"Standard" 4k-style window creation:
Code: HWND hWnd = CreateWindowExA(0, "edit", 0, WS_POPUP|WS_VISIBLE|WS_MAXIMIZE, 0, 0, 0, 0, 0, 0, 0, 0);


Can be replaced with:
Code: HWND hWnd = CreateWindowExA(0, (LPCSTR)0xC018, 0, WS_POPUP|WS_VISIBLE|WS_MAXIMIZE, 0, 0, 0, 0, 0, 0, 0, 0);


Why?!
The second parameter can also be an "ATOM" - see here
Quote:

A null-terminated string or a class atom created by a previous call to the RegisterClass or RegisterClassEx function. The atom must be in the low-order word of lpClassName; the high-order word must be zero.

Now there are these system classes like edit and static. They have ATOMs which seem to be constant. Nice.

You can easily verify that the ATOM for edit seems to be 0xC018:
Quote:

HWND hWnd = CreateWindowExA(0, "edit", 0, WS_POPUP|WS_VISIBLE|WS_MAXIMIZE, 0, 0, 0, 0, 0, 0, 0, 0);
WORD atom = GetClassWord(hWnd, GCW_ATOM);

I didn't find any information on this except for this strange japanese page.


The second one is about audio setup/replay:
Quote:

waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, NULL, 0, CALLBACK_NULL);
waveOutPrepareHeader(hWaveOut, &waveHeader, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, &waveHeader, sizeof(WAVEHDR));

It seems that you can remove the waveOutPrepareHeader call completly if waveHeader.dwFlags is set to WHDR_PREPARED. Not sure how reliable this approach is but I didn't notice any problems yet. I'm also not exactly sure whether these tricks are new/unknown.

Just wanted to share these, make better 1k/4k/8k intros! ;)

las/mercury
added on the 2014-04-21 21:26:31 by las las
Thank you :)
added on the 2014-04-21 22:16:05 by xTr1m xTr1m
haha, nice :D
added on the 2014-04-22 00:01:32 by ferris ferris
Thanks! :D
added on the 2014-04-22 00:16:36 by slack slack
BeRo^FR just mentioned that removing waveOutPrepareHeader might not work with some drivers.
Maybe it would be a good idea to test how reliable the approach really is.

I didn't encounter any problems on real machines yet.
added on the 2014-04-22 01:03:34 by las las
Thanks for sharing!
added on the 2014-04-22 02:05:58 by maytz maytz
Cool it save 8 bytes with MS VS 2012 and 6 bytes MS VS2008
added on the 2014-04-22 11:07:33 by Ciclope Ciclope
Nice. If you have a more complete minimalist win32 framework (like goldenspider) I'd love a link to its sourcecode.
ja hammer ;-)
added on the 2014-04-22 17:45:19 by FeN FeN
Nice :) Thanks!
added on the 2014-04-22 19:07:45 by merry merry
Good to know! Nice tricks. Thank you.
added on the 2014-04-22 21:09:34 by ham ham
Quote:
I didn't encounter any problems on real machines yet.

what would be an unreal machine? :-)
added on the 2014-04-23 21:48:14 by styx^hcr styx^hcr
virtual ones? :)
added on the 2014-04-24 10:02:50 by FeN FeN
... in unreal mode? ;)
why to use:
Code:HWND hWnd = CreateWindowExA(0, "edit", 0, WS_POPUP|WS_VISIBLE|WS_MAXIMIZE, 0, 0, 0, 0, 0, 0, 0, 0);


instead
Code: xor eax,eax HWND hWnd = CreateWindowExA(0, "edit", eax, WS_POPUP|WS_VISIBLE|WS_MAXIMIZE, eax, eax, eax, eax, eax, eax, eax, eax);

?
added on the 2014-04-29 04:45:29 by g0blinish g0blinish
if you write assembler, you'd do exactly that, this is C. Modern compilers will zero a register and push it as well.
added on the 2014-04-29 09:09:08 by xTr1m xTr1m
I actually use:
Code: push byte 0 push byte 0 push byte 0 push byte 0 push byte 0 push byte 0 push byte 0 push byte 0 push dword WS_POPUP | WS_VISIBLE | WS_MAXIMIZE push byte 0 push dword 0xC018 push byte 0 call _CreateWindowExA@48 mov [_swapChainDesc + DXGI_SWAP_CHAIN_DESC.OutputWindow], eax

push byte 0 is a 2 byter - and seems to compress really well if you use it often.
It turns out to be smaller than pushing a register often but totally depends on the context and the overall style used in your code.

And yes, I have proper nasm headers for DX11. :D
added on the 2014-04-29 11:26:18 by las las
You never know what's going compress better, until you try. But for the "xor eax, eax" vs. "push 0 / pop eax" thing I'd say that the push+pop version has practically always been smaller. Read your crinkler output report, it's not hard.
added on the 2014-04-29 14:45:39 by yzi yzi
Omitting waveOutPrepareHeader might not even be smaller. Since the waveOutPrepareHeader and waveOutWrite calls are so similar, the second call compresses quite a lot. I looked at a couple of reports, and it was between 2 and 3 bytes in all of them. So you would have to write WHDR_PREPARED into waveHeader.dwFlags using less than that in order for it to be a win.

Do you know of any other window class atom values? It seems WC_DIALOG (0x8002) is somehow official, but I can't find any other (one could of course just dig them out manually). It could be that some of them have better properties in some ways than EDIT.

Are the WS_POPUP | WS_VISIBLE | WS_MAXIMIZE flags necessary? I usually just put 0 all the way, and it seems to work fine (for D3D9 fullscreen at least).
added on the 2014-04-29 18:23:03 by Blueberry Blueberry
There is a list of ATOMs on that japanese website (See first post).

In the tests I conducted removing the waveOutPrepareHeader call was smaller, might not be the case in all scenarios (+ you get rid of the 4 byte hash which usually does not compress well). The WAVEHDR struct compresses quite well, even with the flag set.
added on the 2014-04-29 18:40:54 by las las
Quote:

Are the WS_POPUP | WS_VISIBLE | WS_MAXIMIZE flags necessary? I usually just put 0 all the way, and it seems to work fine (for D3D9 fullscreen at least).

Found no way yet to get rid of the mouse cursor with dwStyle == 0. ShowCursor/SetCursor seem not to work at all.
added on the 2014-04-29 18:49:54 by las las
win32.hlp says:
Code: HWND CreateWindowEx( DWORD dwExStyle, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu, or child-window identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // pointer to window-creation data );

let me ask - where did you find byte 0?

Does anyone tried to use soundServer by Leonard?
added on the 2014-05-01 06:34:36 by g0blinish g0blinish
Depends on the calling convention, but here (Win32/C) cdecl/stdcall is used.
added on the 2014-05-01 12:54:26 by raer raer
Code:[...]push byte 0[...]

causes 0x00000000 to be pushed onto the stack. What's the problem here?

"soundServer by Leonard"?! Example audio replay code can e.g. be found here http://4klang.untergrund.net/.

Blueberry: I checked some old DX9 setup code, I did also use zeros everywhere.
Seems something is different with DX11 - any ideas?
In addition, I had a look at some recent DX11 intros, they all set dwStyle.
added on the 2014-05-01 14:16:45 by las las

login